Runtime APIs
What the Runtime APIs Are
The runtime APIs are the direct functions behind Bundle Drop's update behavior.
Use them when you want explicit control over checking, downloading, applying, channel discovery, bundle browsing, or user-property management.
Start by calling BundleDrop.init once. After that, these APIs use the active runtime channel and app environment managed by the Bundle Drop runtime.
If you prefer React state and actions for manual UI flows, use useBundleDrop.
Runtime Controller
BundleDrop.init({ environment, enabled?, channelName?, policy?, onStatusUpdate?, checkOnly? })
Initializes Bundle Drop for the current app process.
environmentis required and should match the app environment you use for rollout targetingenableddefaults totruechannelNamesets the initial active channelpolicycontrols startup behavioronStatusUpdatereceives progress messagescheckOnlylets you initialize without automatically downloading or applying updates
Call this once near app startup before using the other runtime APIs.
BundleDrop.setChannel(channelName)
Changes the active runtime channel for later checks, downloads, applies, and hook-driven actions.
BundleDrop.getChannelName()
Returns the current active runtime channel outside React.
BundleDrop.reportHealthy()
Marks the currently running OTA update healthy for this device:
Promise<void>
Most apps do not need to call this because Bundle Drop uses automatic health reporting by default.
Use it when rollback.healthCheckMode is set to "manual" and your app wants to decide when startup is safe. In manual health mode, call it after your critical startup work completes. If you forget to call it, Bundle Drop may roll back the update after repeated unconfirmed launches.
Core Update Functions
checkForUpdate(onStatusUpdate?)
Checks whether the active channel has an update for the current app install:
The response includes the decision fields below:
Promise<
| {
action: "NOOP";
upToDate?: boolean;
channelName?: string;
reason?: string;
skippedFailedBundle?: boolean;
skippedHash?: string;
incompatible?: boolean;
requestedRuntimeVersion?: string;
latestRuntimeVersionOnChannel?: string;
}
| {
action: "INSTALL";
upToDate?: false;
channelName?: string;
hash?: string;
bundleVersion?: number;
version?: string;
runtimeVersion?: string;
}
| {
action: "ROLLBACK";
channelName?: string;
reason?: string;
}
| null
>
Use it when you want to check availability without downloading immediately.
useBundleDrop().checkLatest() wraps this for hook-based flows.
When skippedFailedBundle is true, Bundle Drop kept the current bundle because the selected update previously failed on this device. Treat that as no update for this install. Publish a new bundle if you need the device to try again.
Install decisions may also include SDK-managed delivery metadata used by downloadUpdate(). Treat those fields as diagnostic-only unless another API explicitly asks for them.
downloadUpdate(onStatusUpdate?)
Downloads and stages an update:
Promise<
| { status: "staged"; bundlePath: string; hash: string }
| {
status: "upToDate";
reason?: string;
skippedFailedBundle?: boolean;
skippedHash?: string;
}
| { status: "disabled" }
| { status: "incompatible" }
| { status: "rollback"; reason?: string }
>
Use it when you want to fetch an update but choose separately when to apply it. It uses the currently active runtime channel.
useBundleDrop().downloadUpdate() wraps this for hook-based flows.
When status is "staged", the update is downloaded and ready to apply. When skippedFailedBundle is true, no download was attempted because that update previously failed on this device.
Bundle Drop may optimize the download automatically. Your app does not need to know which delivery path was used; downloadUpdate() only stages an update after Bundle Drop has validated it for local use.
applyUpdate(onStatusUpdate?)
Applies a staged update:
Promise<
| { status: "applied" }
| { status: "noBundle" }
| { status: "disabled" }
| { status: "alreadyApplied" }
| {
status: "blocked";
reason: "BUNDLE_PREVIOUSLY_FAILED";
skippedHash?: string;
}
>
Use it when you want to explicitly switch to a bundle that has already been downloaded.
useBundleDrop().applyUpdate() wraps this for hook-based flows.
When applyUpdate() returns status: "blocked", the staged update previously failed on this device and was not applied. Do not retry that same update on the same device; publish a new bundle or keep the current one.
getUpdateState()
Returns local update state:
Promise<{
hasBundle: boolean;
info: BundleInfo | null;
pendingApply: boolean;
}>
Use this when your UI needs to know whether a bundle exists locally and whether it is waiting to be applied.
getInstalledBundleInfo()
Returns metadata for the installed OTA bundle:
Promise<BundleInfo | null>
Use it when you only need installed bundle metadata and do not need the full update state wrapper.
Channel Discovery
getAvailableChannels()
Returns public channel names for the configured project:
Promise<string[]>
useBundleDrop().fetchAvailableChannels() exposes the same capability in hook form and stores the result in availableChannels.
Configuration
bundleDropConfig
A read-only object that exposes the resolved project configuration for the current device. It is useful for dev tools, debug screens, or support dialogs without manually importing and parsing bundle.drop.config.js.
import { bundleDropConfig } from "@gfean/react-native-bundle-drop";
Shape:
{
serverUrl: string;
platform: "ios" | "android";
runtimeVersion: string | undefined;
defaultChannel: string;
org: { slug: string };
project: { name: string; slug: string };
debugLocal: boolean;
rollback: {
maxCrashCount: number;
healthCheckMode: "auto" | "manual";
healthyAfterSec: number;
};
}
Values are resolved at module load for the current device. The platform and runtimeVersion fields are already resolved, so you do not need to check Platform.OS yourself.
The project API key is intentionally excluded from this object.
The BundleDropConfig type is also exported for TypeScript consumers:
import type { BundleDropConfig } from "@gfean/react-native-bundle-drop";
Bundle Browsing and Manual Install
These functions let users browse available bundles on a channel and install a specific version. This is useful for custom version pickers, QA tools, or rollback-style screens inside your app.
Bundle Drop handles the download and staging. Your app handles the UI.
getAvailableBundles(options?)
Fetches a paginated list of downloadable bundles for a channel:
Promise<{
items: BundleListItem[];
nextCursor: string | null;
hasMore: boolean;
}>
Each BundleListItem contains:
{
hash: string;
bundleVersion: number;
version: string;
platform: string;
runtimeVersion: string;
releaseNotes: string | null;
createdAt: string;
downloadUrl: string | null;
}
hash is the stable Bundle Drop identifier for that update. Use it for display, support, analytics, or error-reporting correlation. Most apps should not try to interpret it.
Options:
channelName: defaults to the active runtime channelplatform: defaults to the current device platformlimit: number of items per page, from 1 to 50; default is 20cursor: pagination cursor from a previous response'snextCursor
Only downloadable bundles are returned. Results are sorted newest first.
useBundleDrop().fetchBundles() wraps this for hook-based flows.
installBundle(hash, downloadUrl, bundleVersion?, version?, runtimeVersion?, onStatusUpdate?)
Downloads and stages a specific bundle by its hash and download URL. It returns the same shape as downloadUpdate:
Promise<
| { status: "staged"; bundlePath: string; hash: string }
| {
status: "upToDate";
reason?: string;
skippedFailedBundle?: boolean;
skippedHash?: string;
}
| { status: "disabled" }
| { status: "incompatible" }
| { status: "rollback"; reason?: string }
>
Use the downloadUrl returned by getAvailableBundles(). After calling installBundle, call applyUpdate() to reload with the selected bundle.
useBundleDrop().installBundle(bundleListItem) wraps this for hook-based flows and accepts a BundleListItem directly.
Typical usage
import {
BundleDrop,
getAvailableBundles,
installBundle,
applyUpdate,
} from "@gfean/react-native-bundle-drop";
BundleDrop.init({
environment: "staging",
channelName: "Beta",
policy: "manual",
});
// Fetch first page of bundles
const page = await getAvailableBundles({
limit: 10,
});
// Fetch next page
await getAvailableBundles({
cursor: page.nextCursor,
});
// User picks a bundle
const selected = page.items[3];
if (!selected?.downloadUrl) {
throw new Error("Selected bundle is not downloadable");
}
await installBundle(
selected.hash,
selected.downloadUrl,
selected.bundleVersion,
selected.version,
selected.runtimeVersion,
);
// Apply the selected version
await applyUpdate();User Property Functions
These functions manage key-value user properties on the device. They are used for Targeted Rollout and audience estimation.
Property keys and string values are case-sensitive. "tier" and "Tier" are treated as different keys.
Values can be strings, finite numbers, or booleans. Use the same type you selected for the property in the dashboard.
Keys are trimmed before they are saved. They must be non-empty, 128 characters or fewer, and cannot start with $, contain ., or use reserved prototype names.
setUserProperty(key, value)
Sets a key-value property for the current app install:
Promise<Record<string, string | number | boolean>>
The returned object is the full set of user properties after the change. If the key already has the same value, the call is a no-op.
removeUserProperty(key)
Removes a property by key:
Promise<Record<string, string | number | boolean>>
The returned object is the full set after removal.
getUserProperties() / getCurrentUserProperties()
Each returns:
Promise<Record<string, string | number | boolean>>
Use these when you need to inspect the currently stored properties.
resetUserProperties()
Clears all user properties for the current app install:
Promise<void>
Hook vs Direct Functions
A practical way to choose:
- use useBundleDrop when building manual React UI
- use direct runtime functions when you want lower-level control
- use BundleDrop.init when you want automated startup handling or shared runtime state
Some direct runtime functions are also surfaced through the hook:
checkForUpdate->useBundleDrop().checkLatest()downloadUpdate->useBundleDrop().downloadUpdate()applyUpdate->useBundleDrop().applyUpdate()getAvailableChannels->useBundleDrop().fetchAvailableChannels()getAvailableBundles->useBundleDrop().fetchBundles()installBundle->useBundleDrop().installBundle()
Related Docs
- For runtime startup setup, see BundleDrop.init.
- For manual UI-driven flows, see useBundleDrop.
- For policy behavior, see Update Policies.
- For audience targeting, see Targeted Rollout.
