# App Store submission

Source: https://developers.swell.is/apps/app-store-submission

Publishing an app to the Swell App Store requires a released version and a review by the Swell team. `swell app release` validates your listing details and fails if anything a listing needs is missing. A reviewer then reads the app and its listing before it goes live.

> **Note:** Only apps published to the App Store are reviewed. A private app requires an existing version and can be installed with `swell app install` into the live or test environment of any store you are logged into, except the test environment of the store the app belongs to. See [App distribution](https://developers.swell.is/apps/distribution).

### Before you start

- An app must belong to a partner account before it can be released. Partner accounts are self-serve: apply at [partners.swell.store](https://partners.swell.store) and verify your email. In the partner dashboard, open Apps and choose Connect app to link an app you have already built.
- An app's `type` cannot be changed to or from `storefront` or `theme` after the app is created.
- `id` is the only required property in `swell.json`. It becomes the app's private ID, an underscore followed by your id, which must be snake_case. The public ID is the private ID without the leading underscore. Only one published app can hold a given public ID, and releasing fails if another published app already holds yours. A small set of IDs is reserved by Swell.

> **Warning:** Nothing prevents changing `id` in `swell.json`, but the CLI then treats it as a different app, and a published app keeps the public ID it was assigned at publish. Treat the app ID as fixed.

> **Warning:** Themes are not listed in the App Store. A theme can be released and versioned like any other app, but it does not appear in App Store listings.

### What Swell checks automatically

These checks run at release, not at push and not at submit. A version must be released before it can be staged, and submitting stages it, so a release that fails these checks cannot reach a reviewer.

#### Every app

- `name`: Required on the app record. It is optional in `swell.json`, where the CLI falls back to the `id`, but a release fails if the record has no name.
- `description`: Required, 70 characters or fewer. This is the tagline shown beneath the app name in the store, not the long description.
- `version`: A valid semver higher than the previous one. A version number cannot be reused, and a released version cannot be released again.

> **Warning:** Removing `description` from `swell.json` and pushing clears it on the app record, and the next release fails. Change the value rather than deleting the key.

#### Every app except themes

Release validation requires only a name and a description for themes. Every other app type also requires an icon and at least one gallery image.

- An icon. Add an image at `assets/icon.<ext>`, or set `logo_src` in `swell.json` to the path of another pushed image. The default path is matched exactly, so `assets/icons/icon.png` and `assets/icon.v2.png` do not qualify. Square, minimum 512×512, PNG or SVG.
- At least one gallery image. Push the file to `assets/screenshots/`, then declare it in the `images` array in `swell.json` with a unique `id` and an `image_src` matching the pushed file's path. A file that is not declared is uploaded but does not appear in the listing. 16:9, minimum 1600×900, PNG, JPEG, WebP or GIF.

**Declaring a gallery image in swell.json**

```json
{
  "id": "my_app",
  "name": "My App",
  "description": "Sync orders with your fulfilment provider",
  "images": [
    {
      "id": "dashboard",
      "image_src": "assets/screenshots/dashboard.png",
      "title": "Order dashboard",
      "description": "Track fulfilment status without leaving Swell."
    }
  ]
}
```

An image entry's `title` accepts up to 40 characters and its `description` up to 140. Both are optional. See [Assets](https://developers.swell.is/apps/assets) for icon and image details.

#### Storefront apps

A desktop preview image is required when `type` is `storefront`, the top-level `kind` is unset or `shop`, and `storefront.theme.provider` is not `app`. A storefront that takes its theme from another app is exempt. Add the image at `assets/preview.*`, or set `preview_src` to its path. Minimum 1600×900. A mobile preview image is not required.

> **Note:** An asset can be up to 7MB. Images are not resized on upload, and the dimensions above are recommendations rather than enforced limits, but an image outside them is cropped to fit. See [Assets](https://developers.swell.is/apps/assets) for the full asset reference.

#### Fields reserved for storefronts and themes

An app whose type is not `storefront` or `theme`, meaning admin, integration and channel apps, is rejected at release for setting `preview_image`, `preview_mobile_image`, `use_cases`, `purchase_options` or `features`. Use `images` instead.

`use_cases`, `purchase_options` and `features` come from `swell.json`. `preview_image` and `preview_mobile_image` are set by image files pushed at `assets/preview.*` and `assets/preview-mobile.*`, or at the paths `preview_src` and `preview_mobile_src` point to. Declaring `preview_src` does not set the field; pushing a file at that path does.

To clear `use_cases`, `purchase_options` or `features`, set the key to an empty array. Deleting the key leaves the stored value in place.

> **Warning:** Deleting a preview image file does not clear the record field. Once an image has been pushed at a preview path, `preview_image` remains set: removing `assets/preview.*` removes the config, but no `swell.json` key unsets the field. Contact Swell support to clear it.

### Preparing your listing

Listing details come from `swell.json`, your app assets and your `DESCRIPTION.md`.

- The long description comes from `DESCRIPTION.md` in the app root, truncated at 20,000 characters. It cannot be set in `swell.json`.
- Categories are assigned by Swell. A `categories` key in `swell.json` is ignored on push.

The following properties reach the public listing: `name`, `description`, `images`, the `price` fields, `support_url`, `documentation_url`, `support_email`, `preview_video_url` and the logo icon. See [the swell.json reference](https://developers.swell.is/apps/swell-json) for every field.

> **Warning:** Listing details are served from the snapshot taken when a version is published. Pushing does not update a live listing.

#### Pricing

An app can be free or paid. Set the price fields in `swell.json` before releasing, since they are captured with the rest of the listing at submission. See the [Swell Help Center](https://www.swell.is/help/partners/earnings-and-payouts) for earnings and payouts.

#### Support contact

The app's `support_email` is the merchant-facing contact shown on the listing. Review decisions, including a reviewer's request for changes, are sent to the partner profile's support email instead, not to the person who submitted the release.

> **Warning:** If the app's `support_email` is empty, the listing falls back to the partner profile's support email and publishes it to merchants.

#### Previewing before you submit

Preview release, on the app page in the partner dashboard, opens the App Store filtered to your app, including unpublished releases. The gallery shows up to four images, taken from the first four entries of the `images` array. An entry with no uploaded file is dropped, and later entries do not move up to replace it. A `preview_video_url` set to a YouTube or Vimeo URL appears as the first gallery item.

### What reviewers look for

A reviewer reads the app and its listing to check that it is safe to install and describes what it does. Grounds for rejection include, but are not limited to:

- Credentials committed to the app, unsafe handling of the access token issued at install, or missing input validation on route functions.
- Store or customer data sent to third parties beyond what the described feature requires.
- Permissions broader than the app uses. Scopes are not validated automatically, and an empty or missing `permissions` array grants unrestricted API access, which merchants are shown as full access to their store.
- An app that does not install into a clean store, or does not do what the listing describes.
- Placeholder copy, screenshots that do not show the app, or support and documentation links that do not resolve.

> **Tip:** See [Best practices](https://developers.swell.is/apps/best-practices) for the engineering patterns a reviewer is likely to ask about.

### Pre-submission checklist

The partner dashboard does not open the submit dialog until the first four items are present. Those four are a client-side check; release validation on the server checks more.

- A name and a short description.
- At least one image declared in the `images` array.
- A logo icon at `assets/icon.*`.
- A released version that has not been submitted.
- Permissions narrowed to what the app uses. `swell create app` scaffolds an empty array for admin, storefront and integration apps; theme apps get no `permissions` key.
- The released version installed into a clean test store and tested.
- Release notes.
- The listing checked with Preview release.

### Submitting a release

#### 1. Push your latest configuration and assets

Release validation runs against the app record on the server. Run `swell app push` from the directory containing `swell.json`, or pass `--app-path`.

#### 2. Release a version

**Release a version**

```txt
swell app release 1.0.0 --release-notes releases/v1.0.0.md
```

Pass the version explicitly. Without a version argument, `swell app release` uses the version on the app record rather than the one in your local `swell.json`. Releasing a new version while another is staged unstages the staged version.

> **Warning:** `--amend` updates the description, release notes and supported flag of an existing version. It does not check whether the version was released, so amending an unreleased version releases it. The `--release-notes` path resolves against the current working directory.

#### 3. Submit for review

Open the app in the partner dashboard and choose Submit for review. Submitting snapshots the current app details, including listing copy, images and pricing. The snapshot is what the reviewer sees and what becomes the live listing.

#### 4. Reply to reviewer comments

While a release is under review the app page shows Reviewing release, and the Review tab carries the conversation. The reviewer opens the thread; you reply there.

### After you submit

Swell aims to review an app or send feedback within 48 business hours. This is a target, not a guarantee. If you have not heard back, reply in the Review tab.

Approvals, requests for changes and rejections are emailed to the partner account's support email, not to the person who submitted the release.

- `Approved`: The version is published in the same step, so there is no approved-but-unpublished state. The snapshot becomes the live listing and the app appears in the App Store.
- `Needs changes`: The version needs changes before it can be approved. The reviewer's feedback is emailed and stays in the Review tab, where you can reply. A version that needs changes cannot be resubmitted. Make the changes, then release and submit a new version.
- `Rejected`: The app won't be published to the App Store, and Swell does not accept new versions of it. The email lists the reasons for the rejection.

#### Updating a published app

Each update is a new version through the same flow, and the newly published version becomes the live one.

A version can also be unpublished from the partner dashboard. The app falls back to the previous published version, or leaves the App Store if there is none. Unpublishing changes the published version only; the listing keeps the name, description and images it was showing.

> **Warning:** A live listing is fixed to the published version. Correcting a tagline, a screenshot or a price requires releasing a new version and taking it through review.

### Common errors

| Message | What to do |
| --- | --- |
| App must have the following to release: name and description in swell.json. | Add both and push before releasing. |
| App must have the following to release: assets/icon.*. | Push an image to assets/icon.<ext>, or set logo_src to a pushed image. Not raised for themes. |
| App must have the following to release: at least one image described in the images section in swell.json. | Add an entry to the images array with an id and an image_src matching a pushed file. Not raised for themes. |
| App must have the following to release: assets/preview.*. | Push a desktop preview image. Raised only for a storefront app of kind shop whose theme provider is not app. |
| App type "admin" cannot use preview_image. Those belong to storefronts and themes; use assets/screenshots and highlights instead. | The app type cannot carry that field. If the message names preview_image or preview_mobile_image, a pushed image file set it and Swell support has to clear it. |
| App version must be released before staging | Run swell app release before submitting. |
| App version is already in review | The version has already been submitted. Wait for the decision, or release a new version. |
| Version 1.0.0 has already been released. Use --amend to update version details. | Increment the version. --amend updates only the description, release notes and supported flag. |
| Not allowed to update versioned app configuration | A released version's files are immutable. Release a new version. |

The missing-details message combines its clauses: configuration and asset problems are separated by `;` , and items within each are joined with "and". "App version is already in review" interpolates the current status, so the same error also appears as "already needs changes", "already approved" and "already rejected".

### Next steps

For private installs, see [App distribution](https://developers.swell.is/apps/distribution). For the development and versioning workflow behind a release, see [App development](https://developers.swell.is/apps/app-development). For every property you can set, see [the swell.json reference](https://developers.swell.is/apps/swell-json).
