1. 從高層次看審核流程
在 Store 發佈 ChatGPT App 並不是「上傳連結就忘了」這麼簡單,而是一個活生生的循環。簡化來看,它大致如下:你準備好 App,送交審核;審核者依自己的檢查清單跑情境;你收到意見、修改,然後再次送審。如此往復多次,直到雙方都滿意為止。
把這件事當作一個小型工作流程(workflow)會更容易理解:
flowchart TD A[Dev Mode / Internal beta] --> B[Submit to Store] B --> C[Under review] C -->|Approved| D[Published] C -->|Changes requested| E[Fixes & Iteration] E --> B D --> F[Updates] F --> C D --> G[Paused / Unpublished]
在早期階段(Dev Mode、內部 beta 測試)你會抓到技術與 UX 問題。當你按下「Submit to Store」後,會開始更正式的審核:關注內容政策是否符合、權限、穩定性,以及列表頁與法律文件中的說明。
建議先建立一種心態:審核不是考試,不是「要嘛通過、永不回頭;要嘛失敗」。它是你與平台之間的持續回饋管道。Store 希望你的 App 安全、可理解、穩定;你則希望能觸及使用者,且不會一週後就被下架。驚喜的是:雙方的利益其實是一致的。
2. 送審時會提交哪些內容
在平台端的人開啟你的 App 之前,你需要填寫一個相當基本的資料集合:
- App 中繼資料:名稱、副標、類別、圖示。
- 列表頁(listing)描述:精簡與完整描述、情境範例。
- 指向 Privacy Policy、Terms、Support/Contact 的連結。
- 權限設定:App 請求哪些存取(例如:OAuth、外部 API、付款模式等)。
- 有時還包括—提供給審核者的測試情境描述與帳號資訊。
- App 本身:MCP 伺服器、UI bundle、system prompt 與工具(tools)描述,平台已可由 Dev Mode/production URL 得知。
在技術上,到這個時間點你通常已經部署了 production 版本(常見於 Vercel 或類似平台),Store 也會連到這個位址。也就是說,「Submit」按鈕不是在部署程式碼,而是在變更它的狀態:「這段程式碼已在你的 production 上線,現在請審核並允許使用者使用」。
為了串起所有部分,通常在版本庫中準備一個小型設定檔,明確標示「候選送審版本」包含哪些內容會很有幫助。例如,一個簡單的 TypeScript 結構:
// config/release-candidate.ts
export const releaseCandidate = {
version: "1.0.0",
apiBaseUrl: process.env.API_BASE_URL,
enableCommerce: true,
privacyPolicyUrl: "https://example.com/legal/privacy",
termsUrl: "https://example.com/legal/terms",
supportUrl: "https://example.com/support",
};
這類檔案不會取代 Store 的表單,但能幫助你的團隊理解此刻你要「交付」給審核者與使用者的是什麼。
3. 審核者如何看你的 App
你已填好表單、準備好連結並按下 Submit。Store 那頭會發生什麼?想像你自己就是審核者。你沒看過程式碼,不清楚專案歷史,但有一份檢查清單且時間有限。通常會從幾個角度檢視 App。
首先,關注內容與品牌政策的符合性。不得提供被禁止的類別;若涉醫療、法律或金融,需有相應的免責聲明與 human‑in‑the‑loop。不得假冒 OpenAI 或以其品牌呈現得像官方產品。
其次,檢視權限。若你請求敏感存取(使用者個資、付款、透過 OAuth 的第三方帳號),審核者會問:這真的必要嗎?使用者能否從描述與 App 行為中清楚理解?理想情況是權限最小化,且與描述的情境一致。
第三,評估 UX 與穩定性。App 不應該霸佔整個 ChatGPT 視窗:若動不動就全螢幕(fullscreen)且沒有清楚說明,會被扣分。若後端經常丟錯誤、工具時好時壞,也會影響信任。
最後,檢查列表頁(listing)的誠實性:描述是否與審核者在對話中實際看到的相符。若你宣稱「閃電般找到完美禮物並立即結帳」,但實際上 App 在搜尋步驟連續當機三次,且不具備下單能力,審核通常會很快且不愉快地結束。
為了讓審核者更容易,建議事先準備「路徑指引」:建議嘗試的步驟與預期結果。這對你之後做回歸測試也很有幫助。
最簡單的程式內描述範例——可在內部文件中引用的測試情境結構如下:
// test/review-scenarios.ts
export const reviewScenarios = [
{
id: "gift-basic",
title: "不含購買的禮物挑選",
steps: [
"請求:幫我為朋友挑選一份禮物,他喜歡桌遊,預算 50$",
"確認 App 會提供選項且不要求登入",
],
},
{
id: "gift-checkout",
title: "含測試結帳的禮物挑選",
steps: [
"從清單中選擇任一禮物",
"使用測試信用卡進入結帳流程",
],
},
];
這個結構不會直接送到 Store,但能讓你的團隊更有紀律,日後也有助於更新給審核者與技術支援的說明。
4. 测試帳號與數據:沒有它們審核跑不起來
只要牽涉金錢、個人資料或外部帳號,審核者會期待你提供一個安全方式來完整走過情境,而不需要使用他們的真實信用卡、私人信箱或真實的 Slack/Google/其他服務。
大致可以分為兩種測試實體。
第一種——你系統中的測試使用者/組織。例如,對 GiftGenius 你可以建立專用的「審核用組織」,預先準備好示範型錄,並在支付供應商的 sandbox 模式下綁定測試付款方式。重點是審核者不該經歷繁瑣的導入流程:理想情況是拿到一組登入帳密或魔法連結,就能直接進入可用的沙盒環境。
第二種——外部供應商的測試資料。支付通常有 sandbox 模式(test cards、test accounts)。若你的 App 透過 ACP/Instant Checkout 委派付款,你必須確保在審核中使用測試環境,沒有人會動用真實金錢。這會影響到 commerce 架構,但核心想法很簡單:在後端加上一個「review/test mode」旗標。
在程式層面,可以是簡單的環境變數與設定:
// config/env.ts
export const env = {
nodeEnv: process.env.NODE_ENV,
reviewMode: process.env.REVIEW_MODE === "true",
paymentProviderEnv: process.env.REVIEW_MODE === "true" ? "sandbox" : "production",
};
在初始化支付系統客戶端的地方:
// lib/payments/client.ts
import { env } from "@/config/env";
export const paymentClient = createPaymentClient({
environment: env.paymentProviderEnv, // "sandbox" 或 "production"
apiKey: process.env.PAYMENT_API_KEY!,
});
這樣的小改動會大大簡化流程:你能在極度接近 production 的模式下運行 App,同時讓審核者不會動到真實金錢。
另外要設計好像 Gmail、Slack、Notion 等整合的測試情境。凡是使用 OAuth 的地方,審核通常期望提供共用的 demo 帳號,或非常簡單的指引來建立測試用 workspace。盡量避免「寫信給 support,我們會手動幫你開通」這類情境——很多審核都是自動化且時間受限,沒有人會等你的回信。
5. 審核常見意見與回應方式
可能有點不妙的消息:你第一次送審就完美通過的機率,大概等同於工程師一次就寫出零 bug 的程式。也就是幾乎為零。這很正常。
意見通常落在幾個可預期的類別。
第一類——權限與隱私。例如你請求存取使用者的 email,但在列表頁未說明用途;或是 Privacy Policy 寫著「不儲存聊天資料」,而 MCP 伺服器的日誌卻會把整個請求連同 PII 一起寫入。審核者可能會要求你調整文件、改變 App 行為,或兩者一起。
第二類——UX 與在聊天中的行為。App 可能會「霸佔」對話:在可以 inline 的地方過度打開 fullscreen、操作後不留文字摘要、沒有讓使用者「回到聊天」的明確方式。這種情況多半會要求你簡化 UX、尊重 ChatGPT 的主要對話介面。
第三類——穩定性與錯誤。若在典型情境下 App 經常出現「Error talking to app」或內部 500,審核可能會暫停,直到你證明那是少數個案而非常態。在這裡,除了修 bug,也期待你具備基本的可觀測性:日誌、健康檢查、合理的逾時等。
第四類——列表頁與行銷承諾的誠實性。若你的描述誇大於實際能力,審核者通常很快會察覺,尤其是在敏感領域宣稱「保證結果」。修正通常有兩步:要嘛降低宣稱、要嘛提升實作(多半是前者)。
如何正確回應意見?核心原則是把審核當作夥伴關係,而不是「惡意的審核官」。在回覆中有幾點很有用:
- 明確承認問題:「是的,在目前版本 App 做的是 X,但描述寫的是 Y」。
- 說明你已調整的內容:「我們已修正文案並更新 Privacy Policy,具體為……」。
- 盡可能附上簡短的測試情境,讓審核者能看到修正生效。
若你不確定為何收到某個意見,與其猜測不如先詢問釐清。例如:「我們這樣理解是否正確:主要問題在於 App 會在未經使用者同意的情況下自動展開 fullscreen?」
6. 送審前的內部檢查清單
為了減少迭代次數,依據模組 7、15–17 建立自己的「pre‑flight 檢查清單」很有幫助。這不是「打勾用」的清單,而是你在每次送審前真的會逐項檢視的實務清單。
在技術上,你甚至可以把這份清單放進版本庫,寫成小型 JSON/TS 模組,並在 README 或 pipeline 中跑過它。
一個最簡單的 TypeScript 版本可能如下:
// tools/review-checklist.ts
export interface ChecklistItem {
id: string;
description: string;
done: boolean;
}
export const reviewChecklist: ChecklistItem[] = [
{
id: "ux-inline-first",
description: "App 的主要情境在 inline 模式下運作;僅在確有必要時才使用 fullscreen。",
done: false,
},
{
id: "privacy-links",
description: "Privacy Policy、Terms、Support 連結有效且可在無需登入的情況下開啟。",
done: false,
},
{
id: "permissions-minimal",
description: "只請求最低限度所需的權限;每個權限都在列表頁(listing)中有說明。",
done: false,
},
];
接著你可以在內部工具或單純在主控台中輸出這份清單並標記進度。這當然不是必備自動化,但工程師通常更習慣與程式碼互動而不是 Google Docs,不妨善用習慣的工具。
7. 迭代與版本控管:首次發佈之後的生活
第二個驚喜是:即使你的 App 已通過審核並對使用者開放,流程也不會結束。任何重大更新都可能再次觸發審核,特別是調整權限、加入新的敏感情境或大幅改動 UX。
因此,應該把 ChatGPT App 當成具有正常發佈流程的活產品,而不是「最後一擊」。
通常合理的最低限度是:在程式碼中維護版本(semver)、變更日誌(changelog),並清楚哪些發佈需要重新審核、哪些不用。比如 UI 的錯字修正、不影響 App 行為與權限者可靜默通過;但從「僅建議」到「完整結帳與付款」的轉變,肯定需要新的審核關注。
在程式中可用簡單常數與變更對照物件表示:
// config/app-version.ts
export const appVersion = "1.1.0";
export const appChangelog = {
"1.1.0": [
"為測試使用者新增 sandbox 結帳",
"在 listing 中明確化權限說明",
],
"1.0.0": ["GiftGenius 第一個公開版本(無付款功能)"],
};
而且,若你把這些說明與 Store 的發佈說明同步,審核者與使用者都能更輕鬆理解發生了什麼變動。
8. 與平台的溝通:如何不與審核者鬧僵
或許最被低估的能力,就是與審核者好好對話。回饋通常以條列方式出現:哪裡不妥、碰到哪些政策條款、哪些 UX 片段令人疑惑。好的回覆不是「你們什麼都不懂」,而是冷靜、具體的說明。
記住幾個簡單原則。
首先,清楚。不要寫長篇大論介紹你的 MCP 伺服器內部架構有多美。審核者最關心的是使用者體驗與政策符合性。簡短說明你改了什麼、現在如何驗證即可。
其次,透明。如果問題不是「改個文字」那麼簡單,而是需要大幅重構,最好誠實說明:「這項意見影響我們 checkout 流程的關鍵部分,正確修正需要 1–2 週。我們會在就緒後立刻提交更新版本」。
第三,記憶。把審核意見不僅僅留在信箱或內部追蹤工具,也要整理成文件裡的小「決策」:究竟什麼不允許、為什麼不允許。這能幫新進工程師與產品避免重蹈覆轍。可以在文件中加一段內部筆記,甚至在 README 中新增「Store Review Decisions」小節。
9. 與架構及前面模組的關聯
把審核流程當成你前面所有工作的「整合性驗證」會很有幫助。
缺少安全與權限(模組 7、15),你多半會在存取、PII 處理、OAuth 與破壞性動作上被追問。
缺少穩定性與可觀測性(模組 16、17),你就難以清楚回答為何 App 有時會當、有時不會,以及你如何監控。此時指標與 SLO 從理論變成論據:「我們觀察到主要工具的 p95 < 2 秒,且 error rate < 1%,時間範圍為過去 N 天」。
缺少UX 模組(模組 8、11),App 可能會直接「搞壞」對話:在不需要的地方開 fullscreen、模式切換不清楚、沒有文字摘要。審核者測試過很多 App,對這些問題通常比你更敏感。
最後,缺少今天對審核流程的理解,你可能會卡在「我們送了、被退回、我們不爽」的階段。更好的心態是把它當成另一個迭代循環,很像你的內部回歸測試,只是多了一位利害關係人——平台。
總之,只要你有像樣的檢查清單、測試帳號與 sandbox 模式、基本的可觀測性,以及與審核者的正常溝通,審核就不再是抽獎。它只是圍繞你 ChatGPT App 的另一個迭代循環——就像發佈前的回歸或團隊內的程式碼審查一樣自然。
10. 通過審核時的常見錯誤
錯誤 №1:不做內部檢查清單就把 App「如實」送審。
許多團隊在 App 在 Dev Mode「能跑」後就按下「Submit」。結果在審核時爆出基本問題:Privacy/Terms 連結失效、情境不可用、沒有測試帳號。解法是建立一份你真的會在每次送審前跑過的內部檢查清單(連結有效、權限最小化、關鍵情境可用)——上一節「送審前的內部檢查清單」正有範例。
錯誤 №2:忽視測試帳號與 sandbox 模式。
要求審核者提供真實信用卡來跑你的 App 是很糟的主意。若有結帳功能卻完全無法測試,也同樣糟。你需要事先設計好系統內的測試 organization/user,以及支付供應商的 sandbox 模式,並綁定到 REVIEW_MODE 或類似旗標。
錯誤 №3:想「談例外」而不是修問題。
有時開發者會與審核者爭論:「競品也是這樣」或「這是平台限制,不關我們的事」。這種風格很少有幫助。更有效的是重構情境、簡化 UX、減少權限,並修正列表頁讓它如實反映 App 的行為。
錯誤 №4:不記錄審核意見與決策。
如果你只是在收到意見後「修了個 bug」而沒有記錄「究竟什麼不允許」,半年後團隊裡又會有人踩到同一個坑。最好維護一份審核決策登錄:「不得在未經使用者明確動作下自動展開 fullscreen」、「不得在未於政策中明確說明的情況下,保存完整聊天內容超過 N 天」等。
錯誤 №5:「大改版」缺乏分階段策略。
試圖在一次發佈中同時加入付款、新權限、新 UX、重做後端,是讓審核久拖不決的好方法。更穩妥的做法是小步前進:先做不含付款的建議,再加入 sandbox 結帳,最後才是完整付款流程。這樣風險更低、審核需要辯護的點也更少。
錯誤 №6:把 Store 的驗收當成自家 QA 與可觀測性的替代。
有時團隊下意識地期待審核者「幫他們測」。結果審核成了免費的 QA,啟動卻被拖延數週。更健康的做法是把審核視為對一個已經相當成熟產品的最後 sanity‑check——這個產品應該已具備自己的測試、日誌、指標與清楚的情境。
GO TO FULL VERSION