HotupdaterHot Updater
GuidesUpdate Strategies

Fingerprint Update Strategy

Automatically prevent incompatible OTA updates by tracking native code changes with Expo's fingerprint library.

Why Choose Fingerprint?

Fingerprint automatically detects native code changes and blocks incompatible OTA updates. This ensures only safe updates reach your users.

Fingerprint vs App Version:

  • Fingerprint: Automatic protection - detects native changes and blocks unsafe updates
  • App Version: Manual control - you specify version targets, no automatic checking

Choose Fingerprint for automatic safety. Choose App Version for manual control.

Setup

Fingerprint is the default strategy. Configure it explicitly if needed:

hot-updater.config.ts
import { defineConfig } from "hot-updater";

export default defineConfig({
  updateStrategy: "fingerprint", // Default strategy
});

Include Additional Files (Optional)

Track extra files that affect native compatibility:

hot-updater.config.ts
import { defineConfig } from "hot-updater";

export default defineConfig({
  updateStrategy: "fingerprint",
  fingerprint: {
    extraSources: [
      "config/native-config.json",
      "scripts/post-build.sh",
    ],
    debug: true,
  },
});

Workflow

Before App Store Submission

Step 1: Generate Fingerprint

Before building for App Store, generate the fingerprint:

npx hot-updater fingerprint create

This creates a fingerprint.json file and embeds the hash in your native files:

  • iOS: ios/YourApp/Info.plist
  • Android: android/app/src/main/res/values/strings.xml

Example fingerprint.json:

{
  "ios": {
    "hash": "11142b9062165fa48665f5efa095dd94e9e45eb0"
  },
  "android": {
    "hash": "c763ed5729a0bcccf23248ee0183ddf9016c2e6e"
  }
}

Step 2: Build and Submit

Build your app with the embedded fingerprint and submit to the App Store.

Step 3: Deploy OTA Updates

After your app is live, deploy JavaScript-only updates:

npx hot-updater deploy

The system automatically ensures only compatible updates reach users.

When Native Code Changes

Check if your fingerprint needs updating:

npx hot-updater fingerprint

If there's a mismatch, create a new fingerprint:

npx hot-updater fingerprint create

Important: After creating a new fingerprint, you must rebuild your app. The new fingerprint must be embedded in the app binary before deploying OTA updates.

Client Setup

Configure your React Native app:

App.tsx
import { HotUpdater, getUpdateSource } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({
  source: getUpdateSource("https://your-update-server.com/api/update-check", {
    updateStrategy: "fingerprint", 
  }),
})(App);

The client automatically constructs this endpoint:

GET {baseUrl}/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId

How It Works

JavaScript/UI Changes ✅ OTA Update Safe

// ✅ Safe for OTA updates
// - Component logic changes
// - Style and layout updates
// - New screens
// - Business logic changes
// - API call modifications

Result: Fingerprint unchanged → OTA update deployed

Native Code Changes ⚠️ Rebuild Required

# ⚠️ Requires native rebuild
# - New native modules (react-native-camera)
# - React Native version updates
# - Native iOS/Android code changes
# - Build configuration changes

Result: Fingerprint changed → OTA blocked → Rebuild needed

If you try to deploy with a changed fingerprint:

$ npx hot-updater deploy
 Fingerprint mismatch!
💡 Native code changed. You need to:
1. Run: npx hot-updater fingerprint create
2. Rebuild and resubmit your app
3. Then deploy OTA updates

Advanced

Multiple App Targets

fingerprint create automatically handles standard React Native projects. Only configure custom paths if you have:

  • iOS app extensions (widgets, share extensions)
  • Multiple Android build variants
  • Non-standard project structure
hot-updater.config.ts
import { defineConfig } from "hot-updater";

export default defineConfig({
  updateStrategy: "fingerprint",
  platform: {
    ios: {
      infoPlistPaths: [
        "ios/YourApp/Info.plist",
        "ios/YourAppWidget/Info.plist",
        "ios/YourAppExtension/Info.plist"
      ]
    },
    android: {
      stringResourcePaths: [
        "android/app/src/main/res/values/strings.xml",
        "android/app/src/debug/res/values/strings.xml"
      ]
    }
  }
});

💡 Most projects don't need this - the defaults work perfectly.

Testing the Endpoint

Test your update endpoint with curl:

curl "https://your-update-endpoint.com/check-update/fingerprint/ios/11142b9062165fa48665f5efa095dd94e9e45eb0/production/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000001"

Parameters:

  • :platform - ios or android
  • :fingerprintHash - Current fingerprint hash
  • :channel - Channel name (e.g., production, staging)
  • :minBundleId - Minimum supported bundle ID
  • :bundleId - Current bundle ID