RELAYOTA SDK Guide
Push JS bundle updates to your React Native users instantly — no App Store review, no infrastructure to manage.
Before you start
Create an app & get your App ID
Every React Native app needs an App record in the dashboard. The App ID is used by the SDK to check for updates.
Go to Apps → New App, choose your platform, enter your bundle ID, and set the runtimeVersion (must match your native build — e.g. 1.0.0).
runtimeVersion must be an exact match — 1.0.0 and 1.0 are treated as different values. Use full semver strings (three parts) everywhere.Copy the App ID from the app detail page — you'll need it in step 4.
Install the SDK
Install the npm package and its required peer dependencies.
npm install relay-ota-react-native react-native-fs @react-native-async-storage/async-storage# iOS — link native modules
cd ios && pod installAdd the native bundle loader
The native module intercepts the JS bundle load so the updated bundle is used after an OTA restart.
Copy OtaBundleUpdater.h and OtaBundleUpdater.m from the SDK's src/native/ folder into your Xcode project.
AppDelegate.mm
#import "OtaBundleUpdater.h"
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
return [OtaBundleUpdater bundleURLForBridge:bridge];
}AppDelegate.swift), wrap the method in an @objc extension and import the header via the bridging header.Wrap your app with OtaProvider
OtaProvider holds update state, auto-checks on foreground, and exposes hooks to all children.
// App.tsx
import { OtaProvider, createRNFSFileSystemAdapter } from 'relay-ota-react-native';
const fileSystem = createRNFSFileSystemAdapter();
export default function App() {
return (
<OtaProvider
fileSystem={fileSystem}
config={{
serverUrl: 'https://api.relayota.com', // ← API URL, not dashboard URL
appId: 'YOUR_APP_ID',
channel: 'production',
platform: 'IOS',
currentVersion: '0.0.0', // ← use 0.0.0 for fresh installs (see note below)
runtimeVersion: '1.0.0', // ← must match the dashboard exactly
}}
>
{/* rest of your app */}
</OtaProvider>
);
}Config reference
serverUrlUse https://api.relayota.com — this is the managed API, not the web dashboard URLappIdApp ID from the dashboardchannel"production" or "staging" (created automatically)platform"IOS" or "ANDROID"currentVersionSemver of the JS bundle currently running. Use "0.0.0" for fresh installs — the first release auto-assigns "1.0.0"runtimeVersionMust match the dashboard App record exactly (full semver, e.g. "1.0.0" not "1.0")checkOnForegroundAuto-check when app returns to foreground (default: true)1.0.0 by the server. If your app's currentVersion is also 1.0.0, the server will not report an update (it only serves versions higher than currentVersion). Set currentVersion to 0.0.0 in the initial APK/IPA to ensure the first OTA release is delivered. The SDK automatically tracks which release was last applied and sends that version on subsequent checks — so you only need the low starting value in the initial build.Handle updates in your UI
Use the built-in hooks to show update prompts, progress bars, or auto-apply silently.
Option A — useAutoUpdate (recommended)
import { useAutoUpdate } from 'relay-ota-react-native';
export function UpdateHandler() {
const { isReady, isLoading, applyUpdate } = useAutoUpdate();
if (isLoading) return <ActivityIndicator />;
if (isReady) {
return (
<View style={styles.banner}>
<Text>Update ready — restart to apply</Text>
<Button onPress={applyUpdate} title="Restart" />
</View>
);
}
return null;
}Option B — useOtaUpdate (full manual control)
import { useOtaUpdate } from 'relay-ota-react-native';
export function UpdateScreen() {
const {
status, progress, release,
hasUpdate, isLoading, isReady,
checkForUpdates, downloadUpdate, applyUpdate, rollback,
} = useOtaUpdate();
return (
<View>
<Text>Status: {status}</Text>
{hasUpdate && <Button onPress={downloadUpdate} title={`Download v${release?.version}`} />}
{isLoading && <ProgressBar progress={progress} />}
{isReady && <Button onPress={applyUpdate} title="Restart & apply" />}
</View>
);
}UpdateStatus values
idleNo check started yetcheckingPolling the serverup_to_dateAlready on latestupdate_availableNew bundle available — call downloadUpdate()downloadingBundle download in progressreadyBundle saved — call applyUpdate() to restarterrorCheck state.error for detailsPush your first release
Build your JS bundle and upload it to the dashboard.
Go to Releases → New Release in the dashboard. Select your app, choose the channel (production), set the runtime version to match your OtaProvider config, then upload the bundle file.
Build the bundle first:
# Android
npx react-native bundle \
--platform android --dev false \
--entry-file index.js \
--bundle-output ./index.android.bundle
# iOS
npx react-native bundle \
--platform ios --dev false \
--entry-file index.js \
--bundle-output ./main.jsbundleUpload the generated index.android.bundle or main.jsbundle file via the dashboard release form. The server auto-assigns version numbers and handles delivery to devices.
runtimeVersion in OtaProvider and the dashboard App record (e.g. 1.0.0). The SDK only applies releases whose runtime version matches exactly.You're live
Monitor update adoption in Analytics. Use Disable on a release or call rollback() from the SDK to revert if needed.
Troubleshooting
Common issues and how to fix them. Click to expand.
The native files weren't registered. For iOS: confirm the .m file is added to the Xcode target and pod install ran. For Android: verify OtaBundleUpdaterPackage is added in getPackages() and the package name matches your source directory.
Ready to ship OTA updates?
Start your 14-day free trial and push your first OTA update in minutes.
Get started free