1. 对审核流程的高层视角
在 Store 发布 ChatGPT App 并不是“贴个链接就完事”,而是一个活生生的循环。简化来看,这个过程是:你准备好 App,提交审核,审核员根据清单跑通流程,你收到反馈,改进后再提交。如此往复,直到各方都满意为止。
最方便的视角是把它当作一个小型工作流程(workflow):
flowchart TD A[Dev 模式 / 内部测试] --> B[提交到 Store] B --> C[审核中] C -->|已批准| D[已发布] C -->|需修改| E[修复与迭代] E --> B D --> F[更新] F --> C D --> G[已暂停 / 已下架]
在早期阶段(Dev 模式、内部测试)你会抓到技术与 UX 问题。当你点击“Submit to Store”后,会进入更正式的审核:他们会查看内容政策的符合性、权限、稳定性,以及列表页和法律文档里写了什么。
有益的心态是:审核不是一次性“考试”,不是“通过就永远不用再来”或“不通过就完蛋”。它是你与平台之间的持续反馈通道。Store 希望你的 App 安全、清晰、稳定;你希望能触达用户且不会一周后被下架。惊喜的是:双方的诉求其实是一致的。
2. 你提交审核的内容
在平台那边打开你的 App 之前,你需要填写一组相当常见的实体:
- App 元数据:名称、副标题、类别、图标。
- 列表页描述:简短与完整描述、示例使用场景。
- 指向 Privacy Policy、Terms、Support/Contact 的链接。
- 权限设置:App 申请了哪些访问(例如 OAuth、外部 API、支付模式等)。
- 有时还需要提供测试场景的说明以及审核员可用的账号。
- App 本身:MCP 服务器、UI bundle、system prompt 以及 tools 的描述,这些平台已可通过 Dev Mode/production URL 识别。
技术上,这个时间点你通常已经部署了生产版本(常见于 Vercel 或类似平台),Store 会访问该环境。也就是说,“Submit”按钮并非部署代码,而是更改其状态:“这段代码已在我们的生产环境中,请审核并放行给用户。”
为串联所有部分,通常在仓库中保留一个小配置会很方便,用来明确这次“候选审核版本”包含了什么。比如,一个简单的 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 界面:若总是无缘由地全屏展开且没有清晰解释,这是减分项。若后端频繁报错、工具时好时坏,也会降低信任。
最后,核对列表页的真实度: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 模式(测试卡、测试账号)。如果你的 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!,
});
这样的小改动能大幅降低难度:你可以在尽可能接近生产的模式下运行 App,但审核员不会触碰到真实资金。
还需要单独设计像 Gmail、Slack、Notion 等集成的测试场景。涉及 OAuth 的地方,审核往往期望提供一个通用 demo 账号,或一份极简的说明,指引如何创建测试 workspace。尽量避免“给 support 发邮件,我们手动给你开通”这类路径——审核通常自动化且时间有限,不会等你的回信。
5. 常见审核意见与应对方式
可能有点不愉快的事实:你第一次就完美通过审核的概率,大概和程序员一次写出无 bug 代码的概率差不多——接近于零。这很正常。
意见通常集中在几类可预期的问题上。
第一类——权限与隐私。例如,你请求访问用户邮箱,但在列表页未解释用途;或者 Privacy Policy 声称“不存储聊天数据”,而 MCP 服务器的日志却把包含 PII 的请求全记录了。审核员可能要求你更新文档、修改 App 行为,或两者都要。
第二类——UX 与聊天中的行为。App 可能会“霸占”对话:在可以 inline 的地方强行全屏、动作后不留下文本总结、不提供清晰的方式“回到聊天”。这类情况通常会被要求简化 UX,并尊重 ChatGPT 的主对话界面。
第三类——稳定性与错误。如果在典型场景下 App 经常出现 “Error talking to app” 或内部 500,审核会暂停,直到你证明这不是常态。这里不仅期望你修 bug,还要具备基本可观测性:日志、健康检查、合理的超时等。
第四类——列表页的真实度与营销承诺。若你的描述“画得太满”,审核员往往很快就能看出来,尤其在敏感领域承诺“保证结果”。修正通常有两步:要么降低承诺,要么增强实现(更多时候是前者)。
如何正确回应审核意见? 核心原则是把审核当作合作伙伴,而不是“苛刻的审核官”。在回复中,建议:
- 清楚承认问题:“是的,在当前版本里 App 做了 X,而描述中写的是 Y”。
- 说明已经做了哪些变更:“我们已校正列表页并更新 Privacy Policy,明确了……”
- 尽可能附上一段精简的测试场景,方便审核员复现并看到修复效果。
如果你确实没理解为什么会被指出问题,最好先问清楚,而不是盲猜。比如:“我们是否理解正确:主要问题是 App 会在未经用户请求的情况下自动全屏?”
6. 提交审核前的内部检查清单
为了减少迭代次数,建议建立自己的 “pre-flight 检查清单”,可参考模块 7、15–17。这不是“打勾清单”,而是你在每次提交前真的会走一遍的实操项。
技术上,你甚至可以把这份清单放进仓库,作为一个小型 JSON/TS 模块,并在 README 或流水线中自动执行。
一个最简单的 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: "仅请求最小必要的权限;每项都在列表页中说明。",
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-checkout",
"在列表页中澄清了权限说明",
],
"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 秒,且最近 N 天的 error rate < 1%。”
缺少UX 模块(8、11),App 可能直接“破坏”对话:在不需要时使用 fullscreen、模式切换莫名其妙、缺少文本总结。审核员往往比你更快察觉这些问题,因为他们测试过大量 App,很容易感知“过度设计”的地方。
最后,缺少今天对审核流程的理解,你可能会停留在“我们提交了、被打回了、我们不开心”的阶段。更正确的做法是把它视作另一条迭代循环,和你的内部回归非常相似,只是多了一个利益相关方——平台。
总之,只要你有像样的检查清单、测试账号与 sandbox 模式、基础可观测性,以及与审核员的正常沟通,审核就不再是“碰运气”。它只是围绕你的 ChatGPT App 的又一个迭代循环——像发布前的回归测试或团队内的代码审核一样自然。
10. 通过审核时的常见错误
错误 №1:未使用内部检查清单就直接提交。
很多团队在 App 刚能在 Dev 模式跑通时就点击“Submit”。结果在审核中暴露出基础问题:Privacy/Terms 链接失效、场景不可用、缺少测试账号。用一份你真的会执行的内部检查清单即可解决(有效链接、最小权限、关键场景可用)——上文“提交审核前的内部检查清单”就是一个示例。
错误 №2:忽视测试账号与 sandbox 模式。
提交一个需要审核员真实银行卡的 App 是个糟糕主意。同样糟糕的是:理论上有结账功能,但审核员根本无法测试。需要预先设计你系统里的测试 organization/user,以及与 REVIEW_MODE 或类似标志绑定的支付服务商 sandbox 模式。
错误 №3:试图“讨价还价”而不是修复问题。
有时开发者会与审核员争辩:“竞争对手也是这样”或“这是平台限制,不关我们事”。这种风格很少有用。更有效的是重塑场景、简化 UX、缩减权限,并修正文案,让列表页如实反映 App 行为。
错误 №4:不记录审核意见与解决方案。
若你收到审核意见后只是“改了代码中的 bug”,却没记录“具体禁止了什么”,半年后团队里可能又会犯同样的错。最好维护一个简短的审核决策记录:“不得在未有明确用户动作时自动全屏”“不得在 Policy 未明确说明的情况下存储完整聊天文本超过 N 天”等。
错误 №5:大而全的发布,而非循序渐进。
试图在一个版本里同时加入支付、新权限、新 UX、以及重写后端,是拉长审核迭代的好配方。更从容的策略是小步快跑:先做仅推荐、再上 sandbox checkout、最后才是完整支付流程。这样既能降低风险,审核时也会少很多争议点。
错误 №6:把 Store 审核当成自己的 QA 与可观测性替代。
有些团队潜意识里指望“审核员替我们测试”。结果审核变成免费的 QA,发售却被拖慢数周。更健康的方式是把审核当作一个成熟产品的最终 sanity 检查;你的产品应当已经具备自有测试、日志、指标与清晰的场景。
GO TO FULL VERSION