Skip to content
Everframe Docs
Documentation

Expo

The React Native SDK in an Expo app, with crash reports from Release builds and the symbols that make their stacks readable.

Updated

Expo Go cannot load the SDK’s native code. Use a development build: npx expo run:ios, npx expo run:android, or EAS Build. Each one runs expo prebuild when the android/ and ios/ folders do not exist yet. Prebuild generates the native projects that the SDK and the config plugins work in.

1. Install the SDK

npx expo install @everframe/react-native

Rebuild the native app afterwards. The SDK needs React Native 0.84 or newer with the New Architecture.

2. Add your SDK key

Mount the provider at the root of your app. With Expo Router, that is the root layout:

// app/_layout.tsx
import { Stack } from 'expo-router';
import { EverframeProvider } from '@everframe/react-native';

export default function RootLayout() {
  return (
    <EverframeProvider config={{ sdkKey: 'evf_live_…' }}>
      <Stack />
    </EverframeProvider>
  );
}

Without Expo Router, wrap the component your App.tsx exports.

sdkKey is the app’s SDK key (evf_live_…), filled in on the app’s Setup tab in the dashboard. It is publishable (it can only submit reports), so it can sit in the bundle or in an EXPO_PUBLIC_ variable.

Crash reporting is on once the provider mounts: uncaught JavaScript errors become reports by themselves, and so do JVM crashes on Android, native crashes, ANRs and low-memory kills on Android 11 and later, and native crashes on iOS. Crash reporting covers what each platform captures. Screens are not tracked until you wire navigation, as described in Install.

3. Add the config plugin

Install the build tooling:

npm i -D @everframe/metro @everframe/expo @everframe/cli

Wrap the Metro config, creating metro.config.js if the project has none:

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withEverframe } = require('@everframe/metro');

module.exports = withEverframe(getDefaultConfig(__dirname), { projectRoot: __dirname });

Add the config plugin to app.json, next to any plugins you already have:

{
  "expo": {
    "plugins": [
      [
        "@everframe/expo",
        {
          "appId": "00000000-0000-4000-8000-000000000000"
        }
      ]
    ]
  }
}

Replace the example with the app’s App ID, the UUID on the same Setup tab. It is not the SDK key: prebuild fails when appId is not a UUID.

Add .everframe/ to .gitignore. Metro writes each build’s identity there.

At prebuild the plugin adds the upload step to android/app/build.gradle and the Xcode project. It edits the Groovy build.gradle that Expo generates; a Kotlin-script build.gradle.kts is not supported. If you keep your own android/ and ios/ folders instead of generating them, see Expo for the one-time setup command.

4. Build Release with R8 on

Expo’s Android template builds Release without R8, so nothing is shrunk or obfuscated. To turn it on, install expo-build-properties:

npx expo install expo-build-properties

and add it to the plugins in app.json:

{
  "expo": {
    "plugins": [
      [
        "expo-build-properties",
        {
          "android": {
            "enableMinifyInReleaseBuilds": true
          }
        }
      ]
    ]
  }
}

The SDK ships its own keep rules, so it keeps working in a minified build. With R8 on, Java and Kotlin frames in Android crash reports are obfuscated until Everframe retraces them with that build’s mapping.txt; see Android R8. With R8 off they arrive readable, and there is no mapping to upload.

5. Regenerate the native projects

Config plugins change the native projects only when prebuild generates them, and npx expo run:ios and npx expo run:android prebuild only when android/ and ios/ are missing. Folders generated before you added @everframe/expo or expo-build-properties keep building without them: no upload step and no R8. After any change to plugins in app.json, generate them again:

npx expo prebuild --clean

--clean deletes both folders first, so move any edits you made there by hand into a config plugin before running it. EAS Build runs prebuild by itself when the folders are not committed.

Test crash reporting with a Release build (npx expo run:android --variant release, npx expo run:ios --configuration Release, or an EAS build). Debug builds run the JavaScript from Metro, so their stacks do not match what you ship.

6. Upload symbols

Set EVERFRAME_API_TOKEN, an API token with the artifacts:write scope (Settings → API tokens), in the environment of your Release builds: your shell or CI for local builds, and on EAS Build a secret environment variable of the environment the release profile uses. Never put it in the app or in an EXPO_PUBLIC_ variable.

Native Release builds then upload what makes their crash frames readable:

  • on both platforms, the Hermes bytecode and composed source map for JavaScript frames;
  • on iOS, the app’s dSYMs for native frames;
  • on Android, the R8 mapping (when R8 is on) and the app’s native libraries, through the dev.everframe Gradle plugin that the config plugin applies.

Expo has the details. Without the token the upload is skipped, the build still succeeds, and that build’s frames stay raw.

An over-the-air update (eas update) ships a new bundle without a native build. Upload its maps with npx @everframe/cli upload-expo-export, as described in Expo.

Which value goes where

Where it goesValue
EverframeProvider config.sdkKeyThe SDK key, evf_live_…
@everframe/expo appId, or EVERFRAME_APP_IDThe App ID, a UUID
EVERFRAME_API_TOKEN in the build environmentAn API token with the artifacts:write scope

Requirements

ExpoA development build or EAS Build. Expo Go is not supported.
React Native0.84+, New Architecture. Hermes supported.
Android build fileThe Groovy android/app/build.gradle that prebuild generates
Node22+ for @everframe/metro, @everframe/expo and @everframe/cli
TVreact-native-tvos with @react-native-tvos/config-tv. TVs have no on-device reporter; see Install.

Verify it

In a Release build, throw from a button:

<Button title="Crash test" onPress={() => { throw new Error('Everframe crash test'); }} />

React Native closes a Release app on an uncaught error, so the report is sent when the app starts again. It then appears under Errors in the dashboard. If its frames are raw, check that the build had EVERFRAME_API_TOKEN and that the build log shows the upload.

Next