主辦原本的活動頁做在 Canva 網站上。頁面有兩處寫著「👈點選圖片進入google 報名表單」,可是那兩張圖都沒有連結,點下去什麼事都不會發生。
這是一場在台北的睡眠工作坊,11 月 7 日(星期六)下午,限量 25 席,另有早鳥價。主辦要的不多:報名要點得進去、看得出還剩幾席、額滿時不要再有人匯款。
我們從 10 月 5 日開始做,下面照順序寫。
這個案子要解決什麼?
整理下來是四件事:
- 報名要點得進去:活動頁的報名按鈕連到主辦自己建的 Google 表單
- 看得到剩幾席:報名按鈕上方顯示「剩餘 N 席」,數字會跟著報名變
- 額滿就停收:剩 0 席時表單不再收回覆,網頁按鈕變成「已額滿」
- 報名者資料不外流:網頁只能讀到數字,讀不到姓名、電話
主辦已經習慣用 Google 表單收報名、在試算表核對匯款,所以我們不換報名工具,只在表單外面加東西。
活動頁:從 Canva 搬到自己的網域
Canva 頁的文字我們逐字照抄,不潤飾、也不加字。主辦後來在 Google 表單裡寫了一份較新的活動資訊(票價、流程、須知),和 Canva 頁有 8 處不一致,例如同一個字有兩種寫法、名額說明多了「額滿將提前關閉表單」。我們照表單改,並把每一處差異列成清單給主辦看。
主辦看完頁面,10 月 8 日回了 5 條修改意見,都是排版:英文標題在手機上要在哪裡斷行、講師介紹加兩行資歷、票價框一行字刪一個字讓它在手機排成一行、頁尾一項資訊一行。5 條當天改完。
另外三件主辦沒要求、我們做了的事:
- 報名按鈕的對比:驗收時量到報名按鈕白字配底色的對比是 4.35,低於 WCAG 2.2 成功準則 1.4.3 對一般文字要求的 4.5:1(大字是 3:1)。我們把底色調深,對比變成 5.17
- 手機寬度:票價框那一行在 360 到 430 像素寬的手機上都排成一行,320 像素寬仍是兩行
- 頁面不放匯款帳號:匯款資訊只在表單裡,頁面上找不到
Google 表單內建的回覆上限,為什麼不夠用?
Google 表單本身可以設定回覆上限:在「接受回應」下方按「設定截止日或回覆限制」,選「達到指定回覆數之後」,收滿就停收,也可以自訂關閉時顯示的訊息。
這個案子我們沒有用它,原因有三個:
- 它數的是筆數,不是席數:這場有雙人票,一筆回覆要算 2 席
- 主辦要能手動加減:朋友答應要來、還沒填表要先保留;有人取消要扣回來。內建上限只看表單收到幾筆
- 它只管表單:收滿會關表單,但不會在活動頁上告訴訪客「還剩幾席」
另外,Google 表單說明中心也寫了:如果多人同時送出回覆,系統會忽略回覆數量限制,接受所有同時提交的內容。也就是說,內建上限在最後一席一樣可能超收,這點和我們的做法相同(見下方「已知限制」)。
如果你的活動一人一筆、不需要在頁面上顯示剩幾席,內建上限就夠了,不用寫程式。
剩餘名額怎麼即時顯示?
我們寫了一支 Apps Script,綁在表單的回覆試算表上。
剩幾席怎麼算
剩餘席數 = 25 − 表單報名席數 − 「手動保留」分頁的合計。
- 一筆報名算 1 席,票種選「雙人報名」的算 2 席
- 「手動保留」是給主辦用的:朋友答應要來、還沒填表,填 +1;有人取消,填 −1
- 有人送出表單、或主辦改了試算表,數字幾秒內重算;另外每 10 分鐘自動重算一次
額滿與重新開放
剩 0 席時,程式先設定表單的關閉訊息「25 席已全數額滿」,再把表單設成不收回覆(Apps Script 的 setCustomClosedFormMessage 與 setAcceptingResponses(false)),網頁按鈕變成不能點的「已額滿」。
之後如果有人取消、剩餘回到 1 席以上,由程式關掉的表單會自動重新打開;主辦自己手動關的,程式不會去開。主辦手動關表單時,網頁按鈕會顯示「報名已截止」。主辦手動開關表單不會觸發即時重算,最多 10 分鐘後網頁才跟上。
網頁拿到的只有數字
Apps Script 部署成網頁應用程式,回傳的只有五個欄位:剩幾席、總共幾席、已佔幾席、表單開不開、更新時間。報名者的姓名、電話、LINE ID 都不在裡面。
部署時「執行身分」選「我」,程式以主辦的帳號讀試算表;「誰可以存取」選「所有人」,不是「任何擁有 Google 帳戶的使用者」。Apps Script 官方文件把存取層級分成「任何登入的使用者」和「任何使用者,即使未登入也適用」兩種,報名頁的訪客多半沒登入 Google,要用不需登入的那一種。
為什麼網頁不直接去問 Apps Script?
我們實測 Apps Script 網頁應用程式,冷啟動常要 10 秒以上才回應。如果每個訪客打開活動頁都去問一次,報名按鈕上方那一行會等很久才出現。
所以改成我們的伺服器每 5 分鐘去問一次,把結果存成活動網站上的一個小檔案,網頁讀這個檔案。訪客讀的是同一個網站的檔案,很快;Apps Script 一小時只被問 12 次。
這樣做要處理「資料舊了怎麼辦」。網頁的規則是:
- 抓不到、8 秒沒回應、數字不合理:不顯示這一行
- 超過 30 分鐘沒更新:不顯示這一行
- 不顯示時,報名按鈕照常可以點
寧可不顯示,也不顯示錯的數字。
「多久沒更新」我們一開始看的是 Apps Script 最後重算的時間,後來改看伺服器最後一次抓成功的時間。原因是沒人報名、主辦沒改表時,Apps Script 可能很久不重算,數字其實是對的,看它會誤判成過期。
已知限制:最後一席可能多賣一席
表單是「有人送出之後」才關。最後剩 1 席時,如果兩個人幾乎同時送出,或有人用雙人票報最後 1 席,會多出 1 席。
我們沒有用程式硬擋,而是寫進給主辦的說明:核對匯款時看一下總數,超出的話由主辦聯絡協調。25 席的活動,這個機率和處理成本,比為它改用付費報名系統划算。
免費分享會為什麼另開一份登記表?
活動當天晚上另有一場免費、自由參加的分享會。合作夥伴要在會員信裡先推這場分享會,我們去看主表單才發現:票種是必填、付款的三個欄位也是必填,只想來分享會的人根本填不完。
改主表單會動到剩餘席數的算法,所以 10 月 17 日另開一份分享會登記表,回覆收在另一份試算表,和主表單、剩餘名額完全分開。活動頁在分享會那一段加了「免費登記分享會」按鈕,開新分頁到登記表。
主表單沒有「從哪裡知道這場活動」的欄位,分享會登記表有。這是之後看「哪個管道帶來人」的主要依據。
合作夥伴的會員信:分兩群寄,分開看成效
活動的合作夥伴 10 月 19 日中午寄了一封會員信,對象是住址在北北基桃竹的會員,共 1,254 人,分成兩群:
- 近 6 個月有動靜的會員:59 人
- 其他會員:1,195 人
兩群收到同一封信,分開記錄開信與點擊,看「最近還有在用的會員」和「比較久沒動的會員」對活動信的反應差多少。信的主按鈕連分享會登記表,另一顆連活動頁看早鳥與剩餘席數。
報名表單沒有「得知管道」欄,所以和主辦說好:報名時在備註寫上合作夥伴的會員身分,可以免一項租借費。主辦數得出有幾筆,會員也拿到一點實際的好處。
量的時候踩到一件事:Google 表單的網址經過轉址後,網址上的追蹤參數(utm)會被拿掉,表單端記不到人是從哪封信來的。所以信的成效看信件系統自己的點擊統計,分享會看登記表的「從哪裡知道」欄,不靠網址參數。
成效
截至 10 月 19 日凌晨,活動頁顯示剩 16 席(10 月 10 日是剩 22 席)。
兩群會員信的開信與點擊、最後賣出幾席、分享會到場人數,活動結束後由主辦提供、主辦同意才寫,會補在這一節。
這套做法適合誰?
適合:
- 幾十人到一兩百人的小型活動、工作坊、講座
- 已經用 Google 表單收報名、在試算表核對匯款
- 有雙人票、團報,或要手動保留名額,內建回覆上限算不準
- 想讓報名頁看得出剩幾席,但不想換付費報名系統
不適合:
- 要線上刷卡、付款完成才算報名成功
- 名額要精準到一席都不能超賣(例如搶票)
- 報名量大到同一分鐘有很多人送出
想看你的活動適不適合這樣做,可以到聯絡頁留言。
常見問題
Google 表單可以設定報名人數上限嗎?
可以。在「接受回應」下方按「設定截止日或回覆限制」,選「達到指定回覆數之後」並輸入上限,收滿就停收。但它數的是回覆筆數,雙人票不會算成 2 席;官方也寫明多人同時送出時會忽略上限。要按席數算、手動保留名額,或在報名頁顯示剩幾席,就要另外用 Apps Script。
Google 表單額滿自動關閉後,有人取消會自動重新開放嗎?
內建的回覆上限不會,要自己把表單打開。我們的做法會:剩餘席數回到 1 以上時,如果表單是程式關的,就自動重新打開;主辦自己手動關的,程式不會去開,避免主辦想截止時又被打開。
網頁顯示剩餘名額,會不會洩漏報名者資料?
不會。Apps Script 回傳給網頁的只有剩幾席、總共幾席、已佔幾席、表單開不開、更新時間五個欄位,姓名、電話等報名資料都不在裡面。
為什麼不讓網頁直接呼叫 Apps Script?
我們實測 Apps Script 網頁應用程式冷啟動常要 10 秒以上。改由伺服器每 5 分鐘抓一次、存成網站上的檔案,訪客打開頁面就讀得到;超過 30 分鐘沒更新就不顯示,不會顯示錯的數字。
最後一席兩個人同時報名會怎樣?
可能多出 1 席,因為表單是在有人送出之後才關;Google 表單內建的回覆上限遇到同時送出也一樣會超收。小型活動可以由主辦核對匯款時處理;如果一席都不能超賣,要改用有即時庫存鎖定的付費報名系統。
參考來源
以下皆於 2026-10-17 查詢:
- Google 文件編輯器說明中心〈發布及管理表單上的回覆者〉(停止收集回應、設定回覆限制、編輯關閉訊息):https://support.google.com/docs/answer/139706?hl=zh-Hant
- Google Apps Script 參考文件 Class Form(
setAcceptingResponses、setCustomClosedFormMessage):https://developers.google.com/apps-script/reference/forms/form - Google Apps Script〈Web Apps〉指南(執行身分):https://developers.google.com/apps-script/guides/web
- Google Apps Script manifest 文件(網頁應用程式存取層級):https://developers.google.com/apps-script/manifest/web-app-api-executable
- W3C〈WCAG 2.2〉成功準則 1.4.3 對比(最低):https://www.w3.org/TR/WCAG22/#contrast-minimum
最後更新: