Skip to main content
A cross-browser extension submits to several stores, and every store asks for the same paperwork: listing copy, permission justifications, privacy disclosures, reviewer notes, and release notes. The STORE.md convention puts all of it in one tracked file at the project root, so a resubmission never reinvents it. The file has a second job. Store tooling that supports the convention reads it at submission time: the extension.dev MCP tool extension_submit sync-listing fills the Chrome Web Store, Firefox Add-ons, Edge Add-ons, and Mac App Store listings from it, and its store preflights check it. What a store takes only on its own dashboard (Chrome promo tiles and data-use answers, the Edge logo, tiles, and properties, Apple’s App Privacy and age rating) stays by hand, and the file lists those items under each store so you see the whole list once instead of one failed check at a time.
extension.dev, the sponsor of Extension.js, handles publishing, store submission, and sharing from the same project. Its docs cover the steps after extension build.

When to create it

Author STORE.md before the first submission, at the moment publishing intent appears. Submission tooling reads the file silently: when it is missing, submissions go out without reviewer notes, release notes, or certification notes, and nothing warns you. The file earns its keep by being maintained while the code changes, not written in a scramble at the end. For the full submission journey around it, see Publish to the browser stores.

Structure

Shared material comes first (## Listing, then ## Privacy and data use), then one ## section per store, then ## Version history. Store sections match by heading text, so ## Firefox Add-ons, ## firefox-amo, and ## AMO all work. The same applies to Chrome, Edge, and Safari (## Safari (Mac App Store)). Three reading rules shape every line:
  • A value that still starts with TODO is skipped, never sent. The file shows what is missing and never invents listing copy.
  • A bullet keeps its continuation lines only while they stay indented. A paragraph that starts at column 0 ends the bullet.
  • HTML comments carry each field’s format and limits. The readers strip them.

Listing

Every line was learned from a failed check or a store refusal, so each one has a format.

Privacy and data use

  • - Privacy policy URL: lives here and only here. The readers take the first http or https address on that line, so leave no sample address in a TODO. Apple requires a policy on every app, and Chrome and Edge require one once any data is handled.
  • - Data collected: names every kind of data that the extension collects, stores, or sends, or none. Chrome (data-usage checkboxes and three certifications), Edge (nine data categories and three certifications), and Apple (App Privacy, “Data Not Collected”) each ask the same question again on their dashboards, and this line is the answer sheet.
  • - Firefox data collection: mirrors browser_specific_settings.gecko.data_collection_permissions in the manifest. AMO reads the manifest, so the two must agree. See Firefox store readiness for the mandatory key.

Store sections

Chrome Web Store

  • ### Single purpose: one sentence, 1,000 characters at most.
  • ### Permissions justification: one bullet per permission, host permission, and content script match that the manifest requests. The text before the colon is the permission, the text after it is the reason, and a reason that still starts with TODO is not sent. A plain line states the remote code answer (Remote code: none). Edge’s Privacy page asks the same questions field by field and takes the same text.
  • ### Test instructions: the steps a reviewer follows, with test credentials when sign-in is required.

Firefox Add-ons

  • ### Reviewer notes: the test steps, then the exact toolchain a reviewer rebuilds with: the Node and npm versions, the install and build commands, and the output folder. Mozilla wants a reproducible build for a bundled package. With the Firefox source archive setting on, the platform attaches the repository at the built commit, so no separate source zip is uploaded.
  • ### Release notes: real notes for this version. A pointer to another section reaches AMO verbatim.

Edge Add-ons

  • ### Certification notes: what the certification team needs to test the extension. The Firefox reviewer notes fit here in most cases: paste them rather than pointing at them.
  • The package may hold no compressed file. Partner Center refuses any .gz, .zip, or other archive inside it, so vendor such assets uncompressed.
  • ### Dashboard checklist: what the Publish API cannot set, typed once on Partner Center: the 300x300 store logo, the 440x280 and 1400x560 promo tiles, the Properties-page answers on personal information and mature content, the Privacy-page categories and certifications, and an optional YouTube URL.

Safari (Mac App Store)

  • - Bundle identifier: is permanent once the first build reaches App Store Connect.
  • - Review contact name:, - Review contact email:, and - Review contact phone: are the App Review contact.
  • ### Reviewer notes: how to turn the extension on in Safari Settings, plus test credentials.
  • ### Release notes: “What’s New”, required from the second version on.
  • ### Age rating: one bullet per question with none unless stated. Apple’s questionnaire also asks about parental controls, age assurance, unrestricted web access, user generated content, social media, messaging, advertising, and loot boxes, and the push sends the full set.
  • App Privacy, and today the age rating and the availability in all 175 territories as well, are confirmed by hand in App Store Connect.
  • Run the converted app locally with npx extension build --browser safari --bundle-id <id> --development-team <TEAM>. An ad-hoc build without a team stops answering after Safari relaunches.

Version history

One line per version and store attempt with its outcome, newest first: 0.1.0: Chrome draft uploaded 2026-10-21, AMO upload refused 401 bad key pair, Edge draft pending. A store rejection goes here with its fix, so the next submission does not repeat it.

What each store reads

sync-listing sends each store the fields below and answers with what changed and what the listing still lacks. A field that is over its limit, or not the shape the store takes (an address, an http or https URL), is named with the STORE.md line to fix. The Safari push also takes the subtitle, the bundle identifier, the review contact, the release notes, and the age rating bullets from the Safari section. The Chrome Web Store section mirrors the sections that agent tooling expects from a CHROMEWEBSTORE.md file, so an agent that looks for those sections finds them here.

Starter files in the templates

Every Extension.js template ships a starter STORE.md generated from its own manifest: one TODO reason bullet per permission, host permission, and content script match, the Firefox data collection line read from the manifest, and every other fact marked TODO. extension create writes the project name on the Name line and the scaffold date on Last updated:. Create a project from a template and the convention is in place from the first commit:

Keep it current

Update STORE.md in the same change that makes it stale:
  • Manifest changed (permissions, host_permissions, content_scripts): add or revisit the justification bullet for each entry. Each permission needs a specific, plain-English reason. “Needed for the extension to work” fails review on every store.
  • User-facing behavior changed: refresh the listing copy and the screenshots.
  • New release: add a version history line and rewrite the Firefox and App Store release notes.
  • Data handling changed: update the privacy section, the policy it links to, and the manifest’s Firefox data_collection_permissions declaration together. The three must agree.
  • Store rejection: record the reason and the fix in version history, so the next submission does not repeat it.

Hygiene

  • Track the file in git. It is part of the project, not a scratch note.
  • Keep it out of the extension zip. The production build packages only dist/<browser>/, so a root-level STORE.md never ships to users.
  • Never put real user credentials in it. Reviewer test accounts are throwaway by construction.