Skip to documentation
DocumentationDelivery and reference

OTA staging and live preview

Preview saved draft translations in a test app before publishing. Enable project staging, opt in your SDK, and understand refresh and cache behavior.

On this page

Two switches control draft delivery

OTA staging lets a test app read saved, enabled drafts, including unfinished translations and never-published keys. Enable OTA staging for the project in the dashboard and opt the client into staging mode. Both switches must be on to receive drafts. Unsaved editor changes are not included.

Project OTA stagingClient staging modeContent on the next successful sync
OffOffPublished translations
OffOnPublished translations
OnOffPublished translations
OnOnSaved, enabled drafts

Enable preview in the dashboard

  1. Open your project, select the Keys tab, and turn on OTA staging. Changing this project-wide setting requires project settings permission.
  2. Edit and save an enabled translation key. You can preview it before marking the translation finished or publishing the key.
  3. Start a test app with a staging-capable SDK and the same project's OTA Publish ID. Enable staging at setup or switch the running client into staging mode.
  4. Run an update check and inspect the text in the app. Check a normal published client alongside it to verify that the draft is still limited to staging requests.

Preview translations before publishing

Watch published and staging clients side by side, edit an unpublished headline, disable staging, and publish the reviewed key. Recorded with Flutter SDK 1.3.0; the walkthrough also explains requests, snapshots, and separate caches.

Watch on YouTube

Opt in from your SDK

Staging is available in Flutter 1.3.0, React / React Native / Angular 1.6.0, and Android / iOS 1.2.0. Upgrade to a staging-capable version before using these APIs. Add the option to your existing setup; keep your native localization configuration and UI revision hooks.

Flutter · setup and runtime switching

await ReRune.setup(
  otaPublishId: '<READ_ONLY_OTA_PUBLISH_ID>',
  localizations: reRuneAppLocalizationsConfig,
  staging: true,
);

// After setup, from your QA controls:
await ReRune.setStaging(true);
await ReRune.setStaging(false);

React · setup and runtime switching

import { ReRune } from '@rerune/react';

const client = await ReRune.setup(
  { otaPublishId: '<READ_ONLY_OTA_PUBLISH_ID>', staging: true },
  nativeOptions,
);

// After setup, from your QA controls:
await client.setStaging(true);
await client.setStaging(false);

React Native uses the same staging option and client methods, imported from @rerune/react-native. Keep its existing native resources and AsyncStorage integration.

Angular · existing root provider

import { ReRune } from '@rerune/angular/ngx-translate';

// In the existing root providers array:
ReRune.provide(
  { otaPublishId: '<READ_ONLY_OTA_PUBLISH_ID>', staging: true },
  nativeOptions,
)

Use the ngx-translate or Transloco entry point that matches your app. Inject ReRuneService from that entry point. In your async QA controls, await service.setStaging(true) to preview drafts or service.setStaging(false) to return to published content. For SSR, server and browser must use the same mode; mismatched hydration snapshots are discarded.

Android switches at runtime with ReRune.setStaging(true) and returns with ReRune.setStaging(false). The linked Android example apps include a session-scoped staging toggle.

iOS · setup and runtime switching

// Enable staging when the app starts.
reRuneSetup(
    otaPublishId: "<READ_ONLY_OTA_PUBLISH_ID>",
    staging: true
)

// Or switch modes after setup from an async QA control.
try await reRuneSetStagingMode(true)
let isStaging = reRuneIsStagingModeEnabled
try await reRuneSetStagingMode(false)

Call reRuneSetStagingMode only after reRuneSetup; otherwise it throws ReRuneStagingModeError.setupRequired. Read reRuneIsStagingModeEnabled to show the active mode in your QA controls. Production and staging use separate caches, and the next app launch starts with the staging value passed to setup.

Refresh, snapshots, and caching

Live preview updates on a successful SDK check, not on every keystroke or through a push connection. Staging requests add staging=true to manifest and locale requests. Each sync checks every manifest locale because draft edits do not advance publication versions. An unchanged manifest does not mean the draft is unchanged.

Locale responses provide full snapshots, with ETags for revalidation. Applying a new snapshot replaces the previous locale document: never-published keys can appear, and deleted or disabled keys disappear from OTA content. Normal main-language and bundled fallback still applies.

The SDKs keep staging and published caches separate. Runtime switching selects the matching cache and checks for updates. The mode selection is session-scoped; the next app startup uses its setup option. Flutter custom cache stores must provide a separate stagingNamespace. React SSR preload must use the same staging option as browser setup.

Staging downloads use the project's normal OTA quota. After each saved edit, refresh the test app and allow its normal reactive consumers or revision observers to redraw the text.

Return to published text or release the draft

Turn off OTA staging in the dashboard to make staging requests return published snapshots on their next successful sync. This does not publish or discard the editor drafts. Disconnected test apps can keep their cached preview until they reconnect and sync.

To release the reviewed wording, publish the intended keys. Normal clients receive that publication on their next successful update check. To stop previewing on one client, switch its staging mode to false; other staging clients keep their own selection.

If the preview does not change

  1. Check both switches, the project's OTA Publish ID, and the installed SDK version. A staging client receives published text when project staging is off.
  2. Save the editor change, confirm the key is enabled, and check the selected language and variant. An unfinished translation can be previewed, but unsaved content cannot.
  3. Trigger a new update check, inspect its errors and OTA quota, and verify the app's revision-driven UI refresh. Existing strings stored outside the render path need to be recalculated.