Store releases
A store submission is the release of that build for that browser. Submitting a build creates the release row for that store and version, and every store act after it (publish, the store's review, a withdrawal, a newer version) advances the same row. Reach for this page when you need to know what is live in each store, which record says so, and what extension_submit writes.
Channels stay the way testers get a build: promoting a build pins a channel to it, and that is a separate record. Nothing has to be promoted before a store submission, and a store submission never moves a channel.
Quick start
GET /api/projects/{id}/releasesThe answer carries storeReleases, one row per store and version, beside the channel rows it always carried. summary.activeReleases counts the rows at live; summary.liveChannels counts the channels every browser's promote run proved live.
From an agent, extension_release_status {include: ["history"]} answers value.storeReleases with the same rows, and {include: ["stores"]} carries each store's newest row as release.
How it works
The row
One row per store and version. Several submissions of one version (a Chrome draft uploaded twice, two TestFlight builds of one App Store version) advance one row; the newest record wins.
| Field | Meaning |
|---|---|
id | <store>:<version> |
store | chrome, firefox, edge or safari |
browser | The browser the store serves, the same word |
version | The version the store names: storeVersion.packaged when the platform stamped one, else the submission's version |
buildSha | The seven character sha of the build the row stands on |
state | uploaded, in-review, live, rejected, withdrawn or superseded |
storeWord | The store's own word for that version as last read (PUBLISHED, InReview, WAITING_FOR_REVIEW), empty when the platform holds none |
readAt | When that word was read |
source | Where it was read: publish-answer (the store's answer to a publish, cancel or review send), poll (the platform's store poller), run (the store's answer to the upload, read by the store run), or inferred (no store word; the state was inferred from the recorded submission) |
visibility | public or unlisted, only when the store said so (Chrome's publish answer or poll); absent otherwise. A live row with no visibility is live for an audience the platform has not read |
storeVersion | {packaged, displayed, source, buildNumber?} when the platform stamped the package |
submissionId, submittedAt, updatedAt | The submission that advanced the row, and when |
storeUrl, failureReason | The listing, and the store's refusal when it refused the last act |
channel | The channel the build was promoted to, when one pins it |
A row whose source is inferred says what the platform recorded, not what the store said. It is shown as such and never grounds a next step: an agent reads the store again before acting on it.
Visibility is read, never inferred. A Chrome item Chrome calls PUBLISHED with visibility unlisted, or a Firefox version AMO signed for self distribution, is live for its audience only, and a row never reads it as public. Where no store said who can find the version, visibility is absent and the row says nothing about it.
What a submit does to the row
A submit uploads the build. The row appears at uploaded once the platform's record says the store took the package. A run that failed before any store step, and a submission the platform dispatched and has no answer for yet, create no row: the submissions page shows them, the Releases page does not.
What each store's acts do to the row
| Store | Act | Row |
|---|---|---|
| Chrome | Upload a draft | uploaded |
| Chrome | Publish (send to review) | in-review with Chrome's word |
| Chrome | Chrome approves and publishes | live (PUBLISHED) |
| Chrome | Chrome rejects | rejected |
| Chrome | Cancel review | withdrawn; the draft stays on the dashboard |
| Edge | Upload a draft | uploaded |
| Edge | Publish (certification) | in-review (InReview); Edge locks the product until certification ends |
| Edge | Certification passes and the product serves the version | live |
| Edge | Partner Center refuses the publish | stays uploaded with failureReason in Microsoft's words |
| Firefox | Unlisted upload, signed | live for self distribution once AMO signed it |
| Firefox | Listed upload | in-review (awaiting review) |
| Firefox | AMO approves | live; AMO rejects: rejected |
| Firefox | A newer version arrives before review | the older row superseded, AMO's own word |
| Safari | TestFlight upload | uploaded with the build number |
| Safari | Send to App Review | in-review (WAITING_FOR_REVIEW, IN_REVIEW) |
| Safari | Apple approves | live; Apple rejects: rejected |
| Safari | Remove from review | withdrawn (DEVELOPER_REJECTED); the build stays on TestFlight |
Across stores, the last rule is the same: when a newer version of one store reaches live, the older live row of that store reads superseded. That transition is inferred, since no store says it in one word, and the row says so in source.
How the state is read from the record
The platform's submission record carries status, the store's answers (storeUpload, storeReview, publish, cancel) and the version it stamped. The row is read from them in this order:
| Record | State |
|---|---|
draft, uploaded | uploaded |
submitted | in-review |
approved, published | live |
rejected | rejected |
superseded | superseded |
a cancel the store accepted, on a record that is no longer in review | withdrawn |
failed while the store holds the package (storeUpload or storeSubmissionId) | uploaded with failureReason |
failed before the store, pending, dry_run, unknown | no row |
storeWord, readAt and source come from the newest of storeReview and storeUpload; with neither, source is inferred.
What counts as active
summary.activeReleases is the number of rows at live. One store has at most one live row, the newest version it serves. summary.liveChannels is what activeReleases counted before: channels whose every browser's promote run concluded success. The two are different facts and are shown apart.
What the Releases page shows
The console Releases page lists the store rows in a Stores section: store, version, build, state, the store's word with when and where it was read, and a link to the submission. The overview cards read Live in stores from activeReleases and Live channels from liveChannels. While every reading is zero and the history is empty, the cards step aside.
What the MCP answers
extension_release_status {include: ["history"]} answers value.storeReleases and value.summary (activeReleases, liveChannels, channels), and its hint leads with what is live where. {include: ["stores"]} carries each store's newest row as release on that store, so "is it live on Chrome" reads the same answer on both.
extension_submit sends no channel. Its answer's value.channel is the channel the platform found the build promoted to, when one pins it; a submit of a build no channel pins answers no channel.
The submission's channel
A store submission used to carry channel: "stable", a label that named no channel and changed nothing uploaded. A submission's channel is now the channel whose pin for that browser is the build submitted, read from the project's channel pins, else absent. POST /api/cli/stores/submit and POST /api/projects/{id}/stores/{store}/submissions accept channel in the body and ignore it, and the store run receives channel only when such a pin exists. The approval of a submit binds browsers and buildSha.
Reference
Store release row
| Field | Type |
|---|---|
id | <store>:<version> |
store, browser | chrome, firefox, edge, safari |
version, buildSha | string |
state | uploaded, in-review, live, rejected, withdrawn, superseded |
storeWord, readAt | string, empty when the platform holds no store word |
source | publish-answer, poll, run, inferred |
visibility | public or unlisted, optional, only from the store's own word |
storeVersion | {packaged, displayed, source, buildNumber?}, optional |
submissionId, submittedAt, updatedAt | string |
storeUrl, failureReason, channel | string, optional |
Summary
| Field | Counts |
|---|---|
activeReleases | Store rows at live |
liveChannels | Channels every browser's promote run proved live |
channels | Channels that exist, shipped or not |
When it fails
- A store is live and the Releases page reads no live store. The platform's record for that submission has not read the store's word yet. Ask for a store read with
extension_release_status {include: ["stores"], refresh: ["<store>"]}or the Refresh control on the submission, then read again. - The row reads
inferred. The platform recorded the submission and holds no store word for it. Read the store before acting on the row. - A submission the record says failed shows no row. The store never received the package. The submissions page carries the failed step and its last log lines.
channelis absent on a new submission. No channel pins the build that was submitted. Promote the build to a channel first when the records should match, or leave it: the store release stands on its own.- A live row carries no
visibility. The store has not said who can find the version. Read it in the store's dashboard before calling it public.