강동민
구글 스프레드시트 · 앱스스크립트

구글 시트로 만드는
신청 접수 웹앱

방문자가 폼을 채워 신청하면, 내 구글 스프레드시트에 한 줄씩 자동으로 쌓입니다. 주소(URL)가 있는 진짜 웹앱을, 설치 없이 브라우저에서 만듭니다. 코드는 한 줄도 안 씁니다. 붙여넣기만 합니다.

약 30분 구글 계정 하나 설치 없음 코드 지식 불필요 실제 화면 13장

시작하기 전에 준비할 것

앱스스크립트가 뭔가요? 구글 스프레드시트에 딸려 오는 무료 자동화 도구입니다. 시트를 조종하는 작은 프로그램을 브라우저 안에서 만들고, 그것을 누구나 여는 웹페이지(웹앱)로 공개할 수 있습니다. 프로그램 언어는 자바스크립트지만, 우리는 코드를 붙여넣기만 하면 됩니다.
이 신청 폼은 하나의 예입니다. 핵심은 원하는 형태를 앱스스크립트로 만들 수 있다는 것입니다. 설문, 예약, 재고 조회, 방명록, 주문 접수, 무엇이든 같은 방법으로 만듭니다. 폼에 넣을 항목과 시트에 저장할 내용만 바꾸면 됩니다. 이 가이드는 그 틀 하나를 처음부터 끝까지 손에 익히는 것이 목적입니다. 이 흐름을 한 번 익히면 나머지는 항목만 바꾸는 일입니다.
1

스프레드시트 만들고 제목 줄 넣기

먼저 신청이 쌓일 표를 만듭니다. 브라우저 주소창에 sheets.new를 치고 Enter를 누릅니다. 빈 구글 스프레드시트가 새로 열립니다.

맨 윗줄(1행)에 제목 여섯 칸을 넣습니다. A1 칸을 누르고 아래 한 줄을 복사해 붙여넣으면, 여섯 칸에 한 번에 나뉘어 들어갑니다.

접수시각 이름 연락처 인원 희망일 메모

이 표가 신청을 담을 곳입니다. 방문자가 폼을 낼 때마다 2행부터 한 줄씩 아래로 쌓입니다. 접수시각은 자동으로 채워집니다.

행접수시각이름연락처인원희망일메모
22026-08-22 14:03김민수010-2345-678922026-09-05주차 되나요?
32026-08-22 14:07이서연010-9876-543212026-09-05
새 구글 스프레드시트 1행에 여섯 개의 제목이 들어간 화면
[ 화면 ]
제목 줄을 넣은 시트새 스프레드시트 1행에 접수시각·이름·연락처·인원·희망일·메모 여섯 칸이 들어간 상태. 1행에 주황 테두리.
그림 1. 1행에 여섯 개의 제목이 들어갔습니다. 신청은 2행부터 쌓입니다.
시트 이름은 아무거나 괜찮습니다. 아래쪽 탭 이름이 "시트1"이어도 됩니다. 코드가 이름이 아니라 맨 앞 시트를 쓰기 때문에 바꾸지 않아도 됩니다.
여기까지 확인

스프레드시트 1행에 여섯 칸 제목(접수시각 … 메모)이 들어 있습니다.

2

앱스스크립트 편집기 열기

이 시트를 조종할 코드를 넣을 곳을 엽니다. 위쪽 메뉴에서 확장 프로그램을 누르고 Apps Script를 고릅니다.

확장 프로그램 메뉴를 열어 Apps Script를 고르는 화면
[ 화면 ]
확장 프로그램 > Apps Script상단 확장 프로그램 메뉴를 편 상태. "Apps Script" 항목에 주황 테두리.
그림 2. 확장 프로그램 > Apps Script를 누릅니다.

새 탭이 하나 뜹니다. 이것이 코드를 넣는 편집기입니다. 왼쪽에 Code.gs라는 파일이 있고, 가운데 코드 칸에 기본 코드(function myFunction() { })가 들어 있습니다.

앱스스크립트 편집기 첫 화면에 Code.gs 기본 코드가 보이는 화면
[ 화면 ]
편집기 첫 화면앱스스크립트 편집기. 왼쪽 파일 목록의 "Code.gs"와 가운데 기본 코드가 보이는 상태.
그림 3. 이 편집기가 코드를 넣는 곳입니다. 왼쪽에 Code.gs가 보입니다.
여기까지 확인

새 탭에 편집기가 떴고, 왼쪽에 Code.gs 파일이 보입니다.

3

서버 코드 붙여넣기

가운데 코드 칸의 기본 코드를 모두 지웁니다. 코드 칸을 한 번 누르고 Ctrl + A(맥은 ⌘ + A)로 전부 선택한 뒤 Delete로 지웁니다.

그 자리에 아래 코드를 붙여넣습니다. 오른쪽 복사 버튼을 누른 다음, 빈 칸에서 Ctrl + V로 붙입니다. 코드는 읽지 않아도 됩니다.

Code.gs 전체 코드 읽지 않아도 됩니다. 오른쪽 복사만 누르세요.
// 신청 접수 웹앱 - 서버 코드 // doGet: 방문자에게 신청 폼(Index.html)을 보여 준다. // submit: 폼에서 보낸 내용을 스프레드시트 첫 시트에 한 줄로 넣고, 접수번호를 돌려준다. // 이 스크립트는 스프레드시트에 딸려 있으므로(확장 프로그램 > Apps Script), 그 시트를 바로 조종한다. function doGet() { return HtmlService.createHtmlOutputFromFile('Index') .setTitle('신청 접수') .addMetaTag('viewport', 'width=device-width, initial-scale=1'); } function submit(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0]; var stamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd HH:mm'); sheet.appendRow([ stamp, data.name, data.phone, data.count, data.date, data.memo ]); return sheet.getLastRow() - 1; // 1행은 제목 줄이므로 빼면 접수번호가 된다 }

이 코드가 하는 일은 두 가지입니다. 방문자에게 폼을 보여 주고(doGet), 방문자가 낸 신청을 시트 맨 아래에 한 줄로 넣습니다(submit). 고칠 곳은 없습니다.

Code.gs 코드 칸에 서버 코드가 붙여넣어진 화면
[ 화면 ]
Code.gs 붙여넣기 완료코드 칸에 코드가 가득 찬 상태. 맨 위에 function doGet() 이 보입니다.
그림 4. 코드 칸에 코드가 채워졌습니다. 맨 윗줄에 function doGet()가 보이면 제대로 들어간 것입니다.
여기까지 확인

Code.gs 코드 칸에 코드가 가득 차 있고, 맨 위에 function doGet()가 보입니다.

4

폼 화면 파일 추가하기

방문자가 볼 폼 화면을 담을 파일을 하나 더 만듭니다. 왼쪽 파일 옆의 +를 누르고 HTML을 고릅니다.

파일 옆 더하기를 눌러 HTML을 고르는 화면
[ 화면 ]
HTML 파일 추가왼쪽 파일 목록의 + 를 눌러 나온 메뉴. "HTML" 항목에 주황 테두리.
그림 5. 파일 옆 + > HTML을 누릅니다.

파일 이름을 묻습니다. Index라고 정확히 적습니다(대문자 I, 확장자 .html은 저절로 붙습니다).

이름은 반드시 Index입니다. 코드가 Index라는 파일을 찾아 폼을 띄웁니다. 이름이 다르면 7단계에서 흰 화면이나 오류가 뜹니다.

새로 생긴 Index.html의 기본 내용을 Ctrl + A, Delete로 모두 지우고, 아래 코드를 붙여넣습니다.

Index.html 전체 코드 읽지 않아도 됩니다. 오른쪽 복사만 누르세요.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <base target="_top"> <style> :root{ --accent:#0f9d58; --ink:#1b2030; --muted:#5b6472; --line:#e2e5ec; --bg:#f5f7f9; } *{box-sizing:border-box} body{ margin:0; background:var(--bg); color:var(--ink); line-height:1.6; padding:24px 16px; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Malgun Gothic",system-ui,sans-serif; } .card{ max-width:440px; margin:0 auto; background:#fff; border:1px solid var(--line); border-radius:16px; padding:28px 24px; box-shadow:0 8px 30px rgba(20,26,45,.08); } h1{ font-size:22px; margin:0 0 6px; } p.sub{ margin:0 0 22px; color:var(--muted); font-size:14.5px; } label{ display:block; font-weight:700; font-size:14px; margin:14px 0 6px; } input,textarea{ width:100%; padding:11px 13px; border:1px solid var(--line); border-radius:10px; font-size:15px; font-family:inherit; background:#fff; color:var(--ink); } input:focus,textarea:focus{ outline:none; border-color:var(--accent); } textarea{ min-height:72px; resize:vertical; } button{ width:100%; margin-top:22px; padding:14px; border:0; border-radius:10px; background:var(--accent); color:#fff; font-size:16px; font-weight:700; cursor:pointer; } button:disabled{ opacity:.6; cursor:default; } .done{ text-align:center; padding:20px 0; } .done .no{ display:inline-block; margin-top:10px; font-size:15px; background:#e7f4ee; color:var(--accent); border-radius:999px; padding:8px 18px; font-weight:700; } .err{ color:#c0392b; font-size:14px; margin-top:12px; text-align:center; display:none; } </style> </head> <body> <div class="card"> <div id="form-area"> <h1>신청 접수</h1> <p class="sub">아래 내용을 채워 신청해 주세요.</p> <label>이름</label> <input id="name" type="text" placeholder="홍길동"> <label>연락처</label> <input id="phone" type="tel" placeholder="010-0000-0000"> <label>인원</label> <input id="count" type="number" min="1" value="1"> <label>희망일</label> <input id="date" type="date"> <label>메모 (선택)</label> <textarea id="memo" placeholder="궁금한 점이나 요청을 적어 주세요."></textarea> <button id="btn" type="button" onclick="send()">신청하기</button> <div class="err" id="err">이름과 연락처를 확인해 주세요.</div> </div> <div class="done" id="done-area" style="display:none"> <h1>접수되었습니다</h1> <p class="sub">신청이 정상적으로 접수되었습니다.</p> <div class="no">접수번호 <span id="rno"></span></div> </div> </div> <script> function send(){ var name = document.getElementById('name').value.trim(); var phone = document.getElementById('phone').value.trim(); var err = document.getElementById('err'); if(!name || !phone){ err.textContent = '이름과 연락처를 확인해 주세요.'; err.style.display = 'block'; return; } err.style.display = 'none'; var btn = document.getElementById('btn'); btn.disabled = true; btn.textContent = '접수 중...'; var data = { name: name, phone: phone, count: document.getElementById('count').value, date: document.getElementById('date').value, memo: document.getElementById('memo').value.trim() }; google.script.run .withSuccessHandler(function(no){ document.getElementById('form-area').style.display = 'none'; document.getElementById('rno').textContent = no; document.getElementById('done-area').style.display = 'block'; }) .withFailureHandler(function(e){ btn.disabled = false; btn.textContent = '신청하기'; err.textContent = '잠시 후 다시 시도해 주세요.'; err.style.display = 'block'; }) .submit(data); } </script> </body> </html>
Index.html 코드 칸에 폼 코드가 붙여넣어진 화면
[ 화면 ]
Index.html 붙여넣기 완료왼쪽 목록에 Code.gs와 Index.html 두 파일. 가운데 코드 칸에 폼 코드가 가득 찬 상태.
그림 6. 왼쪽 목록에 Code.gs와 Index.html 두 개가 보이면 됩니다.

위쪽 저장 아이콘(디스크 모양)을 누르거나 Ctrl + S로 저장합니다.

여기까지 확인

왼쪽 파일 목록에 Code.gs와 Index.html 두 개가 있고, 저장했습니다.

5

웹앱으로 배포하기

이제 이 코드를 누구나 여는 웹 주소로 내보냅니다. 편집기 오른쪽 위 배포 버튼을 누르고 새 배포를 고릅니다.

오른쪽 위 배포 버튼을 눌러 새 배포를 고르는 화면
[ 화면 ]
배포 > 새 배포편집기 오른쪽 위 파란 "배포" 버튼을 눌러 나온 메뉴. "새 배포"에 주황 테두리.
그림 7. 오른쪽 위 배포 > 새 배포를 누릅니다.

창이 뜹니다. 왼쪽 위 톱니바퀴(유형 선택)를 눌러 웹 앱을 고릅니다. 그리고 아래 두 칸을 이렇게 맞춥니다.

  • 실행 계정: 나 (내 계정)
  • 액세스 권한이 있는 사용자: 모든 사용자
배포 구성 창에서 액세스 권한을 모든 사용자로 고른 화면
[ 화면 ]
웹 앱 구성배포 구성 창. 유형 "웹 앱", 액세스 권한 드롭다운이 "모든 사용자"로 된 상태. 그 드롭다운에 주황 테두리.
그림 8. 액세스 권한을 모든 사용자로 바꾸고 배포를 누릅니다.
왜 "모든 사용자"인가요? 이렇게 해야 구글 로그인이 없는 사람도 폼을 열어 신청할 수 있습니다. 신청이 쌓인 시트는 나만 봅니다. 방문자는 폼만 봅니다.
여기까지 확인

유형이 웹 앱, 액세스 권한이 모든 사용자인 상태에서 배포를 눌렀습니다.

6

권한 승인하기

처음 배포할 때 한 번, 구글이 "이 스크립트가 네 시트에 접근해도 되냐"고 묻습니다. 액세스 승인을 누릅니다. 구글 계정이 여러 개면 뜬 창에서 내 계정을 고릅니다.

다음에 "Google hasn't verified this app"(구글에서 확인하지 않은 앱)이라는 경고 화면이 뜹니다. 놀라지 않아도 됩니다. 왼쪽 아래 고급(Advanced)을 누르고, 아래에 나타난 (안전하지 않은 페이지)로 이동(Go to ... unsafe)을 누릅니다.

확인되지 않은 앱 경고에서 Advanced를 눌러 이동하는 화면
[ 화면 ]
확인되지 않은 앱 경고"Google hasn't verified this app" 화면. 왼쪽 아래 "Advanced" 링크에 주황 테두리. 계정 이메일은 흐리게.
그림 9. Advanced > (안전하지 않은 페이지)로 이동 > Continue 순서로 누릅니다.
이 경고는 정상입니다. 내가 방금 만든 개인 앱이라 구글의 심사를 안 거쳤을 뿐입니다. 남이 만든 앱이 아니라 내 것이니 넘어가도 됩니다. 화면이 영어로 떠도 순서는 같습니다.

다음 화면에서 이 앱이 내 스프레드시트에 접근한다는 안내가 나옵니다. 아래 계속(Continue)을 누르면 승인이 끝납니다.

승인하면 배포 완료 화면이 뜨고, 가운데에 웹 앱 URL이 보입니다. 그 아래 복사를 눌러 주소를 복사해 둡니다.

배포 완료 화면에 웹 앱 URL과 복사 버튼이 보이는 화면
[ 화면 ]
배포 완료 · 웹 앱 URL배포 완료 화면. 웹 앱 URL 아래 복사 버튼에 주황 테두리. URL의 스크립트 주소 일부는 흐리게.
그림 10. 웹 앱 URL이 나왔습니다. 복사를 눌러 둡니다.
여기까지 확인

https://script.google.com/...로 시작하는 웹 앱 URL이 나왔고, 복사했습니다.

7

웹앱 열어서 신청해 보기

복사한 URL을 새 탭 주소창에 붙여넣고 Enter를 누릅니다. 방금 만든 신청 폼이 뜹니다. 이름, 연락처, 인원, 희망일, 메모를 채우고 신청하기를 누릅니다.

웹앱 신청 폼에 내용을 채운 화면
[ 화면 ]
신청 폼웹앱 신청 폼에 이름·연락처 등을 채운 상태. 아래 초록 "신청하기" 버튼에 주황 테두리.
그림 11. 폼을 채우고 신청하기를 누릅니다.

잠시 뒤 화면이 바뀌며 "접수되었습니다"와 접수번호가 뜹니다. 첫 신청은 1번입니다.

접수되었습니다 메시지와 접수번호가 뜬 화면
[ 화면 ]
접수 완료"접수되었습니다"와 "접수번호 1" 배지가 뜬 화면. 접수번호에 주황 테두리.
그림 12. 이 화면이 뜨면 웹앱이 살아 있는 것입니다.
이 URL을 그대로 보내면 됩니다. 카톡이나 메일로 이 주소를 보내면, 받는 사람은 구글 로그인 없이 폼을 열어 신청합니다.
여기까지 확인

화면에 "접수되었습니다"와 접수번호가 보입니다.

8

스프레드시트에 쌓였는지 확인하기

1단계에서 만든 스프레드시트 탭으로 돌아옵니다. 방금 낸 신청이 2행에 새 줄로 들어와 있습니다. 접수시각은 자동으로 채워졌습니다.

스프레드시트 2행에 방금 낸 신청이 쌓인 화면
[ 화면 ]
시트에 쌓인 신청스프레드시트 2행에 접수시각·이름·연락처 등이 채워진 새 행. 그 행에 주황 테두리.
그림 13. 신청이 시트에 자동으로 쌓였습니다. 앞으로 오는 신청도 아래로 계속 붙습니다.

끝났습니다

주소가 있는 신청 접수 웹앱이 생겼습니다. 이 URL 하나를 보내 두면, 신청이 들어올 때마다 스프레드시트에 저절로 쌓입니다. 폼을 손보고 싶으면 코드를 고친 뒤 다시 배포하면 됩니다.


자주 막히는 곳

웹앱 주소를 열었더니 흰 화면이나 오류가 떠요

대개 HTML 파일 이름이 Index가 아닙니다. 코드는 Index라는 파일을 찾아 폼을 띄웁니다. 왼쪽 파일 목록에서 이름이 정확히 Index(대문자 I)인지 봅니다. 다르면 그 파일 이름 위에 마우스를 올려 점 세 개 > 이름 바꾸기로 Index로 바꾸고, 다시 저장한 뒤 배포합니다.

코드를 고쳤는데 웹앱에 반영이 안 돼요

배포는 그때의 코드를 사진처럼 찍어 둡니다. 고친 뒤에는 배포 > 배포 관리로 들어가 오른쪽 위 연필(수정)을 누르고, 버전을 새 버전으로 바꿔 다시 배포합니다. 이렇게 하면 URL이 그대로 유지됩니다. "새 배포"로 또 만들면 주소가 새로 생기니, 이미 남에게 준 주소를 살리려면 꼭 "배포 관리 > 수정"을 씁니다.

"확인되지 않은 앱"(Google hasn't verified this app)이라는 무서운 화면이 떠요

정상입니다. 내가 직접 만든 개인용 앱이라 구글 심사를 안 거쳐 뜨는 경고입니다. 화면이 영어로 떠도 고급(Advanced) > (안전하지 않은 페이지)로 이동(Go to ... unsafe) > 계속(Continue) 순서로 넘어가면 됩니다. 이 화면은 앱을 만든 나에게만, 그것도 처음 한 번만 뜹니다. 내가 URL을 보내 준 사람에게는 이 화면이 뜨지 않습니다(실행이 내 계정으로 되기 때문입니다).

신청한 사람도 내 신청 목록을 볼 수 있나요?

아니요. 방문자는 폼 화면만 봅니다. 신청이 쌓이는 스프레드시트는 그 파일을 가진 나만 봅니다. 방문자에게는 시트 주소가 노출되지 않습니다.

접수시각이 이상한 시간으로 찍혀요

스프레드시트의 시간대가 서울이 아닐 수 있습니다. 스프레드시트에서 파일 > 설정을 열고 시간대를 (GMT+09:00) 서울로 바꾼 뒤, 앱스스크립트를 다시 저장하고 배포합니다.


윈도우·맥 어디서든

이 가이드는 전부 브라우저 안에서 일어납니다. 윈도우든 맥이든 화면과 순서가 같습니다. 저장 단축키만 다릅니다. 윈도우는 Ctrl + S, 맥은 ⌘ + S입니다.


이제 원하는 형태로 바꾸기

여기까지 왔다면 웹앱을 만드는 흐름을 손에 익힌 것입니다. 이제 이 틀로 원하는 것을 만듭니다. 폼 항목을 바꾸려면 세 곳을 같이 맞춥니다. Index.html의 입력칸, 시트 1행 제목, Code.gs의 저장 순서입니다. 예를 들어 예약이면 날짜와 시간 칸을, 설문이면 선택지 칸을, 주문이면 품목과 수량 칸을 넣습니다.

신청이 들어올 때 나에게 메일 알림이 오게 하려면 submit 함수 끝에 MailApp.sendEmail 한 줄을 더합니다. 만드는 방법이 막히면, 지금까지처럼 AI에게 "이 코드에 이런 항목을 더해 줘"라고 물어 받은 코드를 같은 자리에 붙이면 됩니다. 방법은 바뀌지 않습니다. 바꾸는 것은 항목뿐입니다.

태그앱스스크립트스프레드시트웹앱구글시트폼자동화GAS배포노코드신청접수
최종 수정: 2026-08-22
무료 AI 활용 진단 내 AI 활용 수준, 상위 몇 %일까요? 진단하면 내 점수와 지금 무엇부터 할지 알려드립니다.