Verify a test release
Verify a test release
- React Native
- Capacitor
Publishing with cmpatch release-react only confirms the server accepted the bundle. This page closes the loop for your app: install a native build, publish a JS change, confirm the device picks it up.
A successful cmpatch-capacitor release create only confirms that the server accepted the bundle. This page shows how to confirm that your app receives it: install a native build, publish a web change, and check that the device applies it.
- React Native
- Capacitor
The repo includes a ready-made on-device demo wired to the local evaluation stack. If you would like to try an OTA before integrating your own app, run cmpatch selfhost local-eval, then the optional cmpatch demo walkthrough. The demo handles sign-in, setup, and publishing the fix after your confirmation. Come back here when verifying a Staging build of your product.
The repository includes an Ionic + Angular example app that uses the SDK. Its README walks through checking, downloading, installing, restarting, and crash rollback against the local evaluation stack. Use this page to verify a Staging build of your own app.
Use Staging (or your local evaluation deployment) until you are confident, not Production.
Before you start
The app on device must already satisfy:
| Requirement | Why |
|---|---|
| Patch SDK in the native binary | OTA cannot add the SDK after install, Core concepts |
CodemagicPatchDeploymentKey matches the deployment you publish to | Wrong key → manifest 404 or wrong channel |
CodemagicPatchApiUrl and CodemagicPatchDownloadBaseUrl reachable from the device | Simulator can use localhost; phone and test-track builds need your Install HTTPS domains |
Running binary version matches the release's targetBinaryVersion | Mismatch → server offers no update |
sync() (or manual check/download/install) runs on launch or resume | No check → no download, Checking for updates |
If you have not published yet, start with First release.
Choose how the test app is installed
Where the app runs determines which server URLs work. Two common setups:
| Setup | Typical use | Server URLs |
|---|---|---|
| Local + simulator | Local evaluation stack on your Mac (cmpatch selfhost local-eval), app in iOS Simulator or a same-machine Android emulator | http://localhost:3000 + http://localhost:9100/codemagic-patch, Local quickstart |
| Server + phone | Phone or test-track build (TestFlight, Play internal testing) talking to a real Patch install | Public HTTPS API + storage domains from Install |
You do not need separate guides for each path; the test loop is the same. Only the URLs and how you install the binary differ.
For Staging on a public install, most teams ship an internal or TestFlight build with the Staging deployment key embedded, then OTA against https://updates.example.com. Production users stay on the Production key until you promote.
The test loop
Make one visible change, then run through this sequence.
1. Confirm the release is published on the server
- React Native
- Capacitor
cmpatch release inspect --app MyApp-iOS --deployment Staging --label v1 --wait
cmpatch-capacitor release inspect --app MyApp-iOS --deployment Staging --label v1 --wait
Status should reach published (not stuck in uploaded or processing). In the dashboard, open the deployment release table and confirm the label appears as Published.
2. Publish the change
- React Native
- Capacitor
cmpatch release-react \
--platform ios \
--deployment Staging \
--release-notes "Verify OTA" \
--yes
npm run build # rebuild webDir with your change
cmpatch-capacitor release create --bundle-path www \
--app MyApp-iOS --deployment Staging \
--target-binary-version 1.2.3 \
--release-notes "Verify OTA"
--target-binary-version must match the version of the build installed on the test device. Devices with a different version do not receive the release.
Wait for processing again (inspect --wait or dashboard).
3. Trigger an update check on device
- React Native
- Capacitor
Cold-start the app or bring it to foreground, however you wired sync() (Checking for updates).
Default sync() uses ON_NEXT_RESTART for non-mandatory releases, so you may need to kill and reopen the app twice: once to download, once to run the new bundle.
Cold-start the app, or bring it to the foreground if it uses start({ checkFrequency: CheckFrequency.ON_APP_RESUME }). See Checking for updates.
With the default install mode (ON_NEXT_RESTART), you may need to close and reopen the app twice: once to download the update and once to run it.
Use a native build without live reload. ionic serve and npx cap run --live-reload load the app from the dev server, so installed updates have no effect.
For faster iteration during testing, use immediate apply:
- React Native
- Capacitor
import { InstallMode, sync } from "@codemagic/react-native-patch";
void sync({ installMode: InstallMode.IMMEDIATE });
import { InstallMode, start } from "@codemagic/capacitor-patch";
start({ installMode: InstallMode.IMMEDIATE });
4. Confirm it worked
| Signal | What to look for |
|---|---|
| UI | Your change is visible after reload |
| SDK | sync() resolves to "update-installed" (or "up-to-date" if already on latest) |
| Dashboard | Download / applied metrics tick up on the release, Analytics |
| CLI | release inspect … shows client activity for the label, and release metrics … shows adoption counts |
Repeat on Android if you ship both platforms, separate apps and deployment keys per platform.
Quick checks if nothing updates
| Symptom | Likely cause |
|---|---|
| Release Published but device unchanged | Install mode needs a second launch; or sync() not called |
| No update offered | Binary version mismatch, compare app version to --target-binary-version on the release |
| Network errors in logs | Device cannot reach API or storage URL (common when a phone still points at localhost) |
| Wrong bundle | Deployment key in the binary does not match the deployment you published to |
Full list: Troubleshooting. CLI sanity check before publishing:
- React Native
- Capacitor
cmpatch doctor --platform ios --app MyApp-iOS --deployment Staging --verbose
cmpatch doctor does not support Capacitor projects. Check manually that the deployment key in the packaged capacitor.config.json (or the Info.plist / strings.xml override) matches cmpatch-capacitor deployment list, and that the release's target binary version matches the installed app version.
After Staging looks good
When QA is satisfied on Staging, follow Preparing for production before your first Production release. In short:
- Promote the release to Production with no rebuild required, or publish a new release directly to Production when ready
- Use Production control for rollouts and rollbacks on live users
Production devices must use a native binary built with the Production deployment key. Staging OTAs never reach them.
Related
- React Native
- Capacitor
- First release: initial publish
- Releasing updates: Staging → Production workflow
- Local quickstart: local evaluation stack and on-device demo
- Native setup: SDK and config keys
- First release: initial publish
- Releasing updates: Staging → Production workflow
- Local quickstart: local evaluation stack and on-device demo
- Native setup: SDK and config keys