> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Over-the-air updates

> Ship JavaScript updates and remote configuration to installed apps without a store release.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Publish an update to a channel, watch adoption, and roll back instantly if something goes wrong.

## Prerequisites

* mobile\_ota is enabled on the plan
* For code push: an Expo or React Native app

## Workflow

<Steps>
  <Step>
    Point your app at the update endpoint: Expo apps use the standard expo-updates protocol against /ota/expo/\<app-slug>/manifest; any app can poll /ota/config/\<app-slug> for JSON remote configuration.
  </Step>

  <Step>
    Publish updates from your pipeline with an ota\_publish step, from CI with the ota:publish token scope, or by uploading a bundle.
  </Step>

  <Step>
    Pin updates to channels per platform and runtime version; use staged rollouts to expose a new update gradually.
  </Step>

  <Step>
    Roll back a bad update in one click — or let auto-rollback do it when clients report failures.
  </Step>
</Steps>

## Two kinds of updates

* code\_push: a full JavaScript bundle for Expo and React Native apps, served over the expo-updates protocol with RSA signing.
* config: a JSON document any app can poll — feature flags, kill switches, copy changes — no particular framework required.

## Safety controls

* Channels and runtime versions keep updates away from binaries that cannot run them.
* Staged rollouts serve a new update to a cohort percentage before everyone.
* Auto-rollback unpins an update when clients report enough failures.
* Update history per channel makes every pin, promote, and rollback auditable.

## Adoption analytics

Clients report manifest checks, downloads, applies, and failures, so each update shows real adoption. Observe ties crash-free rates to the update group, so you can see whether an over-the-air fix actually fixed things.

## Expected result

<Check>
  A fix reaches installed apps in minutes, with per-update adoption numbers and an instant path back.
</Check>

## Common failures

<Warning>
  * Clients never see an update: the channel, platform, or runtime version does not match what the app requests.
  * Publishing fails for a Flutter app: code push is JavaScript-only; Flutter apps can still use JSON remote configuration.
  * Signed update verification fails: the app pins an old signing key — rotate keys carefully and ship the new public key first.
</Warning>
