# Native Fingerprinting — Bundle Drop Docs

> Configure native fingerprinting for React Native and Expo OTA updates. Use automatic compatibility or combine fingerprints with explicit runtime versions.

Canonical: https://bundledrop.app/docs/native-fingerprinting

### Native Compatibility for OTA Updates

Native fingerprinting derives a runtime identity from your project's native inputs. Bundle Drop embeds that identity in the native binary and independently calculates it again when you upload an OTA bundle. Delivery requires the two identities to match.

This works with both Expo and bare React Native. A compatible JavaScript update can stay on the same runtime, while a detected native change creates a different identity and requires a new binary.

Native fingerprinting is currently in **Beta** and is **opt-in**. It is intended to become the default in a future release. Manual runtime versions remain the current default. Existing projects keep their configured behavior unless they explicitly opt in.

### Enable Fingerprinting

After completing [Installation](/docs/installation), replace the `runtimeVersion` section in your existing configuration:

**bundle.drop.config.js**

```js
runtimeVersion: {
  compatibilitySource: "fingerprint",
},
```

Keep your existing server, organization, project, and channel settings. The CLI detects the project workflow automatically; no additional fingerprint options are required for the normal setup.

Create a new Release native build after enabling fingerprinting, then upload from the matching project configuration. Changing the config in an OTA cannot change an older binary's embedded runtime identity.

Normal [upload commands](/docs/uploading) calculate the fingerprint automatically. You do not need to run a separate fingerprint command first or pass the hash to upload. A calculation failure stops the operation instead of silently falling back to a manual runtime.

### Hybrid: Fingerprints and Explicit Runtime Versions

You can combine automatic native detection with a version boundary that your team controls:

**bundle.drop.config.js**

```js
runtimeVersion: {
  compatibilitySource: "fingerprint",
  ios: "1.0.0",
  android: "1.0.0",
},
```

Both the native fingerprint and the platform's explicit value contribute to the final compatibility identity. A detected native change separates incompatible bundles even when `1.0.0` stays unchanged. Bumping that value deliberately starts a new compatibility line, even if the native inputs are identical.

Use the hybrid approach when you want automatic protection and an explicit release boundary. Keep the values unchanged for compatible OTA updates. Rebuild the affected platform whenever you change its explicit boundary.

In the dashboard, Runtime shows the explicit value, or Automatic when none was supplied. Fingerprint appears separately as a compact value. The complete derived identity remains authoritative for delivery.

### When a New Binary Is Required

| Change | Expected behavior |
| --- | --- |
| Edit application JavaScript, styles, or copy | Keep the identity and deliver a compatible OTA |
| Add a pure JavaScript dependency | Keep the identity when existing native inputs remain unchanged |
| Add or remove a native module, or change a bundled native font | Calculate a new identity and build a new native binary |
| Change an explicit runtime boundary | Calculate a new identity and build the affected platform |
| Update files inside an autolinked native dependency | The package may produce a new identity, including for tooling or JavaScript changes |

Fingerprinting detects compatibility changes; it does not deliver native code over the air. An older binary continues receiving updates for its own runtime line. A new binary receives bundles matching its new identity. Both lines can share a [channel](/docs/channels).

### Check and Compare Fingerprints

Inspect the current identity without building or uploading:

**Terminal**

```bash
npx bundle-drop fingerprint --platform ios
npx bundle-drop fingerprint --platform android
```

For a before-and-after comparison, optionally save a report before making a change:

**Terminal**

```bash
npx bundle-drop fingerprint --platform ios --output fingerprint-ios.json
# Make the change, then compare its inputs:
npx bundle-drop fingerprint --platform ios --compare fingerprint-ios.json --json
```

Reports are diagnostic snapshots, not runtime configuration or an upload cache. They are written only when you request an output file. Upload calculates the identity independently from the current project.

### Keep Builds and Uploads Aligned

Use the same native dependencies, dependency lockfile, configuration, and relevant build environment for the binary and its OTA uploads. Keep these inputs in source control and install dependencies consistently in [CI/CD](/docs/ci-cd).

Autolinked native dependencies can contribute their whole package contents. A tooling or JavaScript change inside one of those packages may therefore require a new runtime even when its native source did not change. Custom build inputs also need deliberate compatibility control; use an explicit boundary when your release process introduces a change that the collected inputs do not represent.

App version, iOS build number, and Android version code describe the native release. They do not override a fingerprint or make incompatible bundles eligible. See [Runtime Version](/docs/runtime-version) for the distinction between compatibility and release labels.

### Keep Your Update Policy

Fingerprinting controls which bundles are compatible. Your [update policy](/docs/update-policies) still controls when downloads and activation happen, including manual API control. Managed publishing, rollout eligibility, and native recovery keep their existing roles.

[Patch delivery](/resources/patch-delivery-full-bundle-reliability) works within the matching runtime line. Fingerprinting does not permit patches between incompatible runtimes.

### Keep or Return to Manual Runtime Versions

Manual runtime control remains available:

**bundle.drop.config.js**

```js
runtimeVersion: {
  compatibilitySource: "manual",
  ios: "1.0.0",
  android: "1.0.0",
},
```

Omitting `compatibilitySource` also preserves manual behavior. Switching between manual and fingerprint compatibility requires a new native build. It does not migrate installed binaries through an OTA.

### Related Docs

- [Runtime Version](/docs/runtime-version) compares manual, automatic, and hybrid compatibility.
- [Installation](/docs/installation) covers initial setup and native integration.
- [Expo](/docs/expo) also covers the separate Expo-owned runtime authority option.
- [Uploading](/docs/uploading) provides platform upload commands.
- [Troubleshooting](/docs/troubleshooting#fingerprint-mismatch) covers unexpected identity changes.
