STORE.md 约定把这些内容全部放进项目根目录下一个纳入版本控制的文件,重新提交时不必再从头整理。
这个文件还有第二个用途。支持该约定的商店工具会在提交时读取它:extension.dev 的 MCP 工具 extension_submit sync-listing 根据它填写 Chrome Web Store、Firefox Add-ons、Edge Add-ons 和 Mac App Store 的商店信息,它的商店预检也会检查这个文件。只能在商店自己后台填写的内容(Chrome 的宣传图块与数据使用答卷,Edge 的徽标、图块和属性,Apple 的 App 隐私与年龄分级)仍需手动完成,文件会在各商店小节下列出这些项,让你一次看到完整清单,而不是每次失败一项检查才发现一项。
extension.dev 是 Extension.js 的赞助方,可以在同一个项目里完成发布、商店提交和分享。它的文档覆盖
extension build 之后的步骤。什么时候创建它
在第一次提交之前、也就是刚出现发布意图的那一刻,就写好STORE.md。提交工具读取这个文件时是静默的:文件缺失时,提交会在没有审核备注、版本说明和认证备注的情况下发出去,而且不会有任何警告。这个文件的价值在于随着代码变化持续维护,而不是最后关头匆忙补写。围绕它的完整提交流程请参见发布到浏览器商店。
结构
共享材料在前(先## Listing,再 ## Privacy and data use),然后每个商店一个 ## 小节,最后是 ## Version history。商店小节按标题文本匹配,因此 ## Firefox Add-ons、## firefox-amo 和 ## AMO 都有效。Chrome、Edge 和 Safari(## Safari (Mac App Store))同理。
每一行都遵循三条读取规则:
- 仍以
TODO开头的值会被跳过,不会发送。文件只展示缺少什么,从不编造商店文案。 - 列表项只有在续行保持缩进时才会带上这些续行。从第 0 列开始的段落会结束该列表项。
- HTML 注释写明每个字段的格式和上限,读取工具会把它们去掉。
Listing
每一行都来自一次失败的检查或一次商店拒绝,所以每一行都有固定格式。Privacy and data use
- Privacy policy URL:只写在这里。读取工具会取这一行中第一个 http 或 https 地址,所以不要在TODO里留示例地址。Apple 要求每个 App 都有隐私政策,Chrome 和 Edge 在处理任何数据时也要求提供。- Data collected:列出扩展收集、存储或发送的每一类数据,或写none。Chrome(数据使用复选框和三项认证)、Edge(九个数据类别和三项认证)以及 Apple(App 隐私,“未收集数据”)都会在各自后台再问一次同样的问题,这一行就是答卷。- Firefox data collection:对应 manifest 中的browser_specific_settings.gecko.data_collection_permissions。AMO 读取的是 manifest,所以两者必须一致。必填键请参见 Firefox 商店审核的数据收集权限。
商店小节
Chrome Web Store
### Single purpose:一句话,最多 1,000 个字符。### Permissions justification:manifest 请求的每个权限、主机权限和内容脚本匹配各写一个列表项。冒号前是权限,冒号后是理由,仍以TODO开头的理由不会发送。单独一行写明远程代码的回答(Remote code: none)。Edge 的隐私页面会逐项问同样的问题,并接受同样的文字。### Test instructions:审核者要执行的步骤,需要登录时附上测试账号。
Firefox Add-ons
### Reviewer notes:先写测试步骤,再写审核者重新构建所用的确切工具链:Node 和 npm 版本、安装与构建命令,以及输出目录。对于打包过的扩展,Mozilla 需要可复现的构建。开启 Firefox 源码归档设置后,平台会附上构建所在提交的仓库,因此无需另行上传源码 zip。### Release notes:这个版本真实的说明。指向其他小节的文字会原样到达 AMO。
Edge Add-ons
### Certification notes:认证团队测试扩展所需的内容。大多数情况下 Firefox 审核备注同样适用:直接粘贴,而不是写一句指向它。- 扩展包里不能有任何压缩文件。Partner Center 会拒绝包内的任何
.gz、.zip或其他归档,所以这类资源要以未压缩形式放入。 ### Dashboard checklist:发布 API 无法设置、需要在 Partner Center 填写一次的内容:300x300 商店徽标、440x280 和 1400x560 宣传图块、属性页上关于个人信息和成人内容的回答、隐私页上的类别与认证,以及可选的 YouTube URL。
Safari (Mac App Store)
- Bundle identifier:在第一个构建到达 App Store Connect 后就不能再改。- Review contact name:、- Review contact email:和- Review contact phone:是 App 审核的联系人。### Reviewer notes:如何在 Safari 设置里启用扩展,以及测试账号。### Release notes:即”新功能”,从第二个版本起必填。### Age rating:每个问题一个列表项,除非另有说明都写none。Apple 的问卷还会问家长控制、年龄验证、不受限制的网页访问、用户生成内容、社交媒体、消息、广告和战利品箱,推送时会发送完整的一组回答。- App 隐私,以及目前的年龄分级和全部 175 个地区的上架范围,都要在 App Store Connect 里手动确认。
- 在本地运行转换后的 App:
npx extension build --browser safari --bundle-id <id> --development-team <TEAM>。没有团队的临时签名构建在 Safari 重启后就不再响应。
Version history
每个版本、每次商店提交写一行,附上结果,最新的在最前:0.1.0: Chrome draft uploaded 2026-10-21, AMO upload refused 401 bad key pair, Edge draft pending。商店拒绝及其修复也写在这里,下次提交就不会重蹈覆辙。
每个商店读取什么
sync-listing 把下列字段发送给各商店,并回答哪些发生了变化、商店信息还缺什么。超出上限或格式不符合商店要求(地址、http 或 https URL)的字段,会连同需要修改的 STORE.md 行一起指出。
推送到 Safari 时还会从 Safari 小节读取副标题、Bundle 标识符、审核联系人、版本说明和年龄分级列表项。Chrome Web Store 小节与代理工具期望在
CHROMEWEBSTORE.md 文件里找到的小节一致,所以寻找这些小节的代理可以在这里找到它们。
模板中的初始文件
每个 Extension.js 模板都带有一个根据自身 manifest 生成的初始STORE.md:每个权限、主机权限和内容脚本匹配各有一个 TODO reason 列表项,Firefox 数据收集行从 manifest 读取,其余事实都标为 TODO。extension create 会把项目名写到 Name 行,把创建日期写到 Last updated:。从模板创建项目,第一个提交里就已具备这套约定:
保持最新
在让STORE.md 过时的同一次改动里更新它:
- manifest 变了(
permissions、host_permissions、content_scripts):为每一项添加或重新审视说明列表项。每个权限都需要一个具体、直白的理由。“扩展运行所需”在所有商店都通不过审核。 - 面向用户的行为变了:更新商店文案和截图。
- 新版本:添加一行版本历史,并重写 Firefox 和 App Store 的版本说明。
- 数据处理方式变了:同时更新隐私小节、它链接的政策,以及 manifest 中 Firefox 的
data_collection_permissions声明。三者必须一致。 - 商店拒绝:在版本历史里记下原因和修复,下次提交就不会重蹈覆辙。
卫生习惯
- 用 git 跟踪这个文件。它是项目的一部分,不是草稿。
- 不要把它打进扩展 zip。生产构建只打包
dist/<browser>/,所以根目录下的STORE.md永远不会发给用户。 - 永远不要在里面放真实用户的凭据。审核用的测试账号本来就是一次性的。

