Chrome Web Store 上架:账号、Manifest V3、权限说明与审核拒绝复盘

浏览器扩展上架不是把 zip 传上去就结束。本篇按账号、Manifest V3、权限说明、商店素材、审核拒绝、申诉、更新回滚七个环节,拆解 Chrome Web Store 的实际流程,并给出权限说明模板、申诉模板和一份可直接勾选的上架清单。

本篇是《独立开发者的平台寄生》系列的第 3 篇,只讲 Chrome Web Store 的上架流程、审核规则与申诉。Manifest V3 的运行时、CSP、service worker 生命周期、消息传递等技术细节,已经在 WASM 浏览器扩展 里讲过,本篇不重复。

一、一个被拒三次的扩展

这是为解释机制构造的假设案例,人物、引语、收入和耗时均为教学设定,不是对真实事件的调查记录。

一位开发者做了一个「在招聘网站上一键保存职位到 Notion」的扩展。功能不复杂:读取当前页面的职位标题、公司、薪资,调用 Notion API 写入数据库。第一次提交,审核拒绝,理由是「权限请求超出功能所需」。他在 host_permissions 里写了 <all_urls>,因为「反正以后可能要支持更多网站」。第二次提交,他把范围缩小到三个招聘网站,但仍然被拒,理由是「未提供隐私政策,且未说明数据如何传输到第三方」。第三次,他补了隐私政策、补齐真实数据流说明并整改 token 访问范围后才通过。chrome.storage.local 不是加密保险箱,单纯改存储位置并不能证明安全或保证过审;应尽量用 OAuth、最小 scope 与可撤销凭据,并限制不需要接触 token 的上下文。

三次拒绝加起来花了六周。功能代码其实第二周就写完了。上架成本主要不在写代码,而在权限、隐私和材料。

二、上架前先确认三件事

在注册开发者账号之前,先确认这三件事,能省掉很多返工:

  1. 你的扩展是否真的需要上架。 如果只是给自己或小团队用,可以用开发者模式加载未打包扩展,或者用企业策略分发;上架意味着公开审核、公开隐私政策和长期维护。
  2. 你的核心功能是否能在 Manifest V3 下成立。 Manifest V3 对远程代码、后台脚本生命周期、网络请求拦截都有约束。如果核心功能依赖被移除的能力,先改架构,不要先写商店文案。
  3. 你是否愿意承担长期维护。 扩展上架后,Chrome 的 API、审核规则、商店政策都会变;你需要留出跟进时间。

三、账号与开发者身份

Chrome Web Store 官方注册文档确认需要一次性注册费;本文不把未在当前官方正文确认的美元金额写成定价。付款前在自己的注册流程确认金额、币种和付款资料并保存回执。

注册时要注意:

  • 发布者身份与团队协作分别确认。 开发者注册、身份/交易者验证和群组发布者是不同设置,不照搬 Google Play 的个人/组织账号模型;按实际控制台提交法律主体与联系资料。
  • 联系邮箱要长期可用。 审核沟通、政策通知、账号恢复都走这个邮箱。
  • 双重验证。 开启 2FA,避免账号被盗导致扩展被下架。
  • 付款资料。 即使扩展本身免费,注册费用和可能的开发者服务费用也需要付款资料。

账号注册完成后,先不要急着提交。把下面的 Manifest 和材料准备好,再走提交流程。

四、Manifest V3 的最小合规集

下面是字段示意,不是完整可安装工程,更不是通过审核的保证。引用的 popup.html、service-worker.js 和图标必须实际存在;功能不同也不一定需要后台或这些权限:

{
  "manifest_version": 3,
  "name": "你的扩展名",
  "version": "1.0.0",
  "description": "一句话说明扩展做什么",
  "action": {
    "default_popup": "popup.html"
  },
  "background": {
    "service_worker": "service-worker.js"
  },
  "permissions": ["storage", "activeTab"],
  "host_permissions": ["https://example.com/*"],
  "icons": {
    "16": "icons/16.png",
    "48": "icons/48.png",
    "128": "icons/128.png"
  }
}

几个容易出问题的点:

  • manifest_version 必须是 3。 新扩展不再接受 MV2。
  • host_permissions 要尽量窄。 能写具体域名就不要写 <all_urls>;能用 activeTab 就不要申请全站访问。
  • permissions 只放真正用到的。 storage、activeTab、scripting、contextMenus 这些常见权限,审核会看你的功能是否真的需要。
  • 不要引用远程代码。 Manifest V3 禁止从远程加载并执行 JS;所有可执行代码必须打包在扩展里。远程配置可以传 JSON,但不能传可执行脚本。
  • service worker 不是常驻进程。 不要依赖全局变量保存状态;需要持久化的状态放 chrome.storage。

五、权限最小化:审核最容易卡住的地方

权限与功能不匹配是需要重点检查的拒审风险;本文没有官方拒审原因占比,不能将其排为第一。审核员看的不是「你有没有写权限说明」,而是「这个权限和你的功能是否匹配」。

5.1 三种权限策略

策略适用场景审核风险
最小权限只申请当前功能必需的权限低
可选权限高级功能按需申请,用 chrome.permissions.request中
全站权限需要读取任意网页内容高,必须有充分理由

如果核心功能只需要在特定网站工作,就把域名写死;如果需要在用户主动点击时读取当前页,用 activeTab;如果需要用户授权更多站点,用可选权限,并在 UI 里解释为什么。

5.2 权限说明模板

商店页和隐私政策里,建议用下面这种结构说明每一个敏感权限:

权限:host_permissions(https://example.com/*)
用途:读取当前职位页面的标题、公司、薪资字段,用于生成保存到用户 Notion 数据库的记录。
数据流向:页面内容仅在用户点击「保存」时读取,通过 HTTPS 发送到扩展自己的后端做字段清洗,再写入用户授权的 Notion 数据库;不用于广告、画像或出售。
保留期限:后端仅保留 7 天用于排错,随后删除;用户可在扩展设置中一键清除本地缓存。

这段说明要同时出现在三个地方:商店页的「隐私」部分、扩展内的隐私政策链接、以及提交审核时的「权限理由」输入框(如果控制台提供)。

5.3 不要做的事

  • 不要为了「以后可能用」申请全站权限。
  • 不要在用户不知情时读取页面内容。
  • 不要把用户数据发送到未在隐私政策中声明的第三方。
  • 不要用远程脚本绕过审核。
  • 不要在描述里写与功能无关的关键词。

六、商店页素材与文案

商店页不是装饰,它同时影响审核和转化。需要准备:

素材要求常见问题
扩展名称清晰、不与已有品牌混淆堆关键词、冒充官方
简短描述一句话说明解决什么问题写成功能列表
详细描述功能、使用场景、权限说明、隐私链接夸大承诺、缺少隐私说明
图标128×128 PNG模糊、尺寸或内容不符、与实际产品不一致
截图1280×800 或 640×400只放 logo、不含真实界面
小型宣传图440×280官方素材指南列为必备;PNG/JPEG,按指南检查内容
隐私政策可公开访问的 URL缺失、打不开、内容与功能不符

文案上,最容易被拒的是「夸大承诺」和「关键词堆砌」。比如「全网最强」「自动赚钱」「官方推荐」这类表述,既不能证明,也容易触发审核。把「最强」换成「在 X 场景下做 Y」,能减少无法证明的声明;本文没有通过率数据。

七、审核拒绝的六种常见原因

下面六类原因覆盖了独立开发者最常见的情况。每一条都给出「审核员看到什么」和「你怎么改」。

7.1 权限过宽

审核员看到:一个只做翻译的扩展申请了 <all_urls> 和 tabs。
怎么改:把域名缩到翻译服务需要的范围;用 activeTab 替代全站读取;把高级权限改成可选权限。

7.2 功能过于单薄

审核员看到:扩展只有一个按钮,点开是一个静态页面,没有实际功能。
怎么改:确保扩展在安装后能完成一个明确的核心动作;如果功能依赖外部服务,在描述里写清楚,并提供可验证的使用路径。

7.3 远程代码

审核员看到:service-worker.js 从远程 URL 拉取并 eval 一段脚本。
怎么改:把所有可执行代码打包进扩展;远程只传 JSON 配置;如果必须动态加载,改成由后端返回数据、前端用固定逻辑解释。

7.4 误导性描述

审核员看到:描述里写「官方插件」「与某平台合作」,但没有任何授权证明。
怎么改:删掉未经授权的品牌词和官方暗示;用「适用于」「兼容」而不是「官方」。

7.5 缺少隐私政策

审核员看到:扩展处理用户数据,但商店页没有隐私政策链接,或链接打不开。
怎么改:准备一个公开可访问的隐私政策页面,写明收集什么、为什么收集、传给谁、保留多久、用户怎么删除。

7.6 功能不可用

审核员看到:安装后点击按钮没有反应,或需要登录但没有测试账号。
怎么改:在审核备注里提供测试账号和操作步骤;确保核心功能在干净浏览器环境里可用;不要依赖审核员无法访问的内部环境。

八、被拒之后怎么申诉

被拒后不要立刻重新提交同样的包。先做三步:

  1. 读拒绝理由,分类。 是「产品问题」(功能、权限、数据)还是「材料问题」(隐私政策、截图、描述)?产品问题要改代码,材料问题只要补材料。
  2. 改一处,说明一处。 在申诉或重新提交的备注里,逐条对应拒绝理由,写清楚改了什么、在哪里改的。
  3. 保留证据。 截图、录屏、测试账号、隐私政策 URL,都放在一个文档里,后续沟通直接用。

申诉模板

主题:Appeal for extension review rejection — [扩展名] [Item ID]

审核团队好:

我们的扩展 [扩展名] 于 [日期] 因 [拒绝理由原文] 被拒。我们已按以下方式修正:

1. [拒绝理由 1]
   - 问题:[具体描述]
   - 修改:[具体改动,例如将 host_permissions 从 <all_urls> 缩小到 https://example.com/*]
   - 验证:[如何验证,例如重新安装后仅在 example.com 注入]

2. [拒绝理由 2]
   - 问题:[具体描述]
   - 修改:[具体改动]
   - 验证:[如何验证]

附件包括:更新后的隐私政策链接、权限说明、测试账号(如需)、操作录屏。
如果还有未满足的要求,请指出具体条款,我们会继续修正。

谢谢。

申诉的语气要具体、克制,不要争辩「这个规则不合理」。审核员每天看大量申诉,能快速定位问题的材料更容易通过。

九、更新、回滚与版本节奏

上架不是终点。扩展的更新会带来新的审核风险:

  • 权限变更会触发重新审核。 新增 host_permissions 或敏感权限时,审核会更严格;能做成可选权限的,尽量做成可选。
  • 版本号要递增。 每次提交都要更新 version,不要重复提交同一个版本号。
  • 保留上一个可用版本。 如果新版本被拒或出问题,你需要能快速回滚;官方支持回滚到前一个已发布版本,并以新的递增版本号重新发布旧包;这不是任意降级,也不会自动回退数据 schema 或服务端变更。
  • 分批发布。 如果控制台支持按比例发布,先放一小部分用户,观察崩溃率和差评,再全量。
  • 更新说明要写人话。 「修复了一些问题」不会让用户更新;写清楚「修复了在 X 页面崩溃的问题」更有效。

版本节奏上,独立开发者容易走两个极端:要么半年不更新,要么每天发版。更稳的是每 2–4 周一个功能版本,紧急修复随时发,并在商店页维护一个简短的更新日志。

十、上架检查清单

  • 开发者账号已注册,2FA 已开启,联系邮箱长期可用。
  • manifest_version 为 3,所有可执行代码已打包,无远程脚本。
  • permissions 与 host_permissions 已按最小权限原则收敛。
  • 敏感权限有可选权限方案,且 UI 中有解释。
  • 隐私政策已公开可访问,内容与实际数据流一致。
  • 商店名称、简短描述、详细描述无夸大、无未授权品牌词。
  • 图标、截图、宣传图尺寸与内容符合要求。
  • 核心功能在干净浏览器环境中可复现,测试账号已准备。
  • 审核备注写清了测试步骤、权限理由、数据流向。
  • 已记录当前线上版本号,准备好回滚方案。

使用边界与实操验收

权限策略必须与实现和实际数据流一致。activeTab 通常需要用户触发,脚本注入还需相应 API/权限,不能仅凭 manifest 示例认定功能可运行。

审核前演练:在独立浏览器配置中加载完整文件夹,点击一次保存,记录发出的域名、请求字段和 token 可访问上下文;拒绝授权时应有明确提示。再用旧版数据启动新包、用新版本号发布旧逻辑的测试包验证兼容性,不把“包可回滚”当作“数据可恢复”。

关键参考与核验范围

以下链接支持对应的机制或规则;本文的案例、成本和经营评分是说明方法的假设,不能当作平台统计或收益承诺。核验日期:2026-10-22。

系列导航

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「Indie」更多文章

  1. 定价复盘:价格、转化、留存与退款的一张表
  2. 低流量定价实验:样本不够时怎么测
  3. 结账页:币种、税费、失败重试与拒付