Did the update land? Release health for React Native OTA updates
A successful deploy only tells you the bundle was uploaded. Insights shows what happened next on real devices: how many picked the update up, how many rolled it back, and why the rest failed to update.
deploy finishes, the release shows up in the console, and then you wait. The questions that matter come next, and the deploy output cannot answer any of them. Are devices actually running the new bundle? Did any of them crash on it and roll back? The support ticket from someone still on last week's version: is that one device, or thousands?
Crash reporters answer part of this. They tell you when JavaScript throws, but not whether a device downloaded the update, whether it ever started, or why a download failed on a flaky connection. For years, CodePush users read that from the App Center dashboard, which counted installs and rollbacks for each release. When App Center was retired in March 2025, most teams lost that view and went back to guessing.
Insights, new in BetterCodePush 1.0, is that view rebuilt around how OTA releases fail in practice.
What Insights shows
Each app gets an Insights page in the console with four views.
Release health. Pick a release and see how many devices downloaded it, how many launched it, and how many crashed on it and went back to a working bundle. The crash rate is measured against the devices that actually tried the release, not against your whole user base, so a 10% rollout is judged on its own numbers. Once at least 20 devices have tried a release and 5% of them crashed, the console suggests rolling it back, with the disable button next to the numbers. It is a suggestion only. Nothing rolls back without you.
Update failures. Update check failure rate and download and install failure rate over time, then the failures grouped by stage and reason: a check that timed out, a download that failed its hash or signature check, an install that could not write to storage. The most recent error messages and stacks sit underneath, so "some users can't update" turns into a specific cause you can fix.
Usage. Daily, weekly and monthly active installations, the split between platforms, and the version distribution: for each app version in the stores, which bundle its devices are actually running. This is the view that tells you whether it is safe to stop supporting an old app version, or how many devices are stuck behind a release you disabled.
Device lookup. Paste an install ID and see that device's recent reports: which updates it downloaded, applied or failed, on which app version and channel. Paste your own user ID instead and see every installation that user has. When a customer writes in, you can see what their phone is running instead of asking them to find a version number in a settings screen.
Setting it up
Insights is a plugin for the BetterCodePush SDK. It is plain JavaScript, so there is no native step and no new store build if you are already on 1.0.
npm install @bettercodepush/insightsimport { BetterCodePush } from "@bettercodepush/react-native";
import { insights } from "@bettercodepush/insights";
export const betterCodePush = BetterCodePush.init({
plugins: [insights()],
});
export default betterCodePush.wrap({ updateStrategy: "appVersion" })(App);Then open the app in the console, go to Insights and turn it on. Insights is off by default for every app, so nothing is collected until someone on your team decides it should be. Ship the change as an OTA update and reports start arriving as devices pick it up.
If you want to look up devices by your own user IDs, attach one after sign-in and clear it on sign-out:
betterCodePush.insights.setUser({ userId: currentUser.id });
// on sign-out
betterCodePush.insights.setUser(null);Debug builds report nothing, so your simulator sessions never end up in production numbers. To check your setup from a debug build, pass insights({ debug: true }).
What the plugin sends, and what it never sends
Insights is built to answer release questions, not to profile your users. A device sends a small report when something about its update state changes: an update downloaded, an update applied at launch, a recovery after a failed start, an update that failed, plus one launch report a day. Each report carries the install ID, app version, platform, channel and the bundles involved.
Reports never include the device model, OS version, IP address, location or advertising IDs. Install IDs and user IDs are stored as keyed hashes, never in the clear, so the console can find a device from an ID you already have but cannot list your users. You can delete everything recorded for an install or a user from the console, which covers most data deletion requests in one step.
One thing to keep in mind: error messages are stored as your code wrote them. If your code puts an email address in an error message, it will be there. Keep personal data out of error strings, as you would for any crash reporter.
It never gets in the way of an update
Analytics must not be the reason an update fails. Reports are sent in the background, retried a few times and then dropped. A slow or failing report cannot delay, block or fail an update check, a download or an install. If you go over your plan's report allowance, reports are dropped and the console tells you. Updates are not affected.
Reading the numbers honestly
Every number in Insights is a count of reports that reached us, or of installations that sent at least one. A device that is offline, a build without the plugin, or a debug build is invisible. Treat Insights as a precise picture of the devices that report, which in a healthy app is nearly all of them, rather than a census of every install.
The active installation counts are also not your billing count. Billing is based on update checks, and Insights counts the devices that report, so the two will be close but rarely identical. Insights reports themselves are never billed as usage.
Using it during a rollout
Insights is most useful in the first hour after a deploy. A routine that works:
- Deploy to a small share of devices, for example 10%.
- Watch release health until a few hundred devices have launched the release. Compare its crash rate with the release before it.
- Check update failures for a new reason that started with this release.
- Widen to 50% and then 100%, or disable the release and let devices fall back to the previous one.
npx bettercodepush deploy --platform ios --channel production --rollout 10
# release health looks good: widen it
npx bettercodepush bundle update "$RELEASE_ID" --rollout-cohort-count 500 --yes
# or it does not: pull it back
npx bettercodepush bundle disable "$RELEASE_ID" --yesFor the full routine, see our guide to staged rollouts and rollbacks. For what happens on the device when a release crashes, see how crash recovery works. Insights is how you see that recovery happening across your whole user base.
Plans
Insights is included in every plan, Hobby included. Each plan comes with a monthly report allowance: 100,000 on Hobby, 1,000,000 on Starter, 10,000,000 on Pro and unlimited on Enterprise. See pricing for the details.
Already on BetterCodePush 1.0? Add the plugin, turn Insights on in the console and ship it as an OTA update. Still on an earlier version? Start with the 1.0 upgrade guide.