React Native SDK
Add bug reporting to your iOS and Android app. Put the key in .env, wrap the app once, then shake or tap Report.
react-native-snagrelay brings the same report flow to React Native: open it with a
shake or the Report button, describe the problem, and the report arrives in your inbox
with device info, recent console errors, network requests, and the last 15 screens.
Your agent reads it over MCP like any other report.
On the project's Install tab, choose React Native.
Copy the .env line (it already has your API key), then wrap the app as below. Do not
paste the key into source.
Requirements
React Native 0.76 or later. Rebuild the native app after installing the peer packages. Works in a bare app, an Expo custom dev client, and Expo Go.
Install
npm install react-native-snagrelay
npm install react-native-view-shot react-native-svg react-native-device-info react-native-shake @react-native-picker/picker react-native-safe-area-context @react-native-async-storage/async-storage
cd ios && pod installnpm 7+ installs those peers automatically. Yarn does not — run the second line.
Put the key in .env
Keep the project key out of git. Expo inlines any EXPO_PUBLIC_* variable at bundle
time. Restart Metro after you change .env.
# .env (or .env.local)
EXPO_PUBLIC_SNAG_RELAY_API_KEY=YOUR_API_KEYThe Install tab shows this line with your real key. Only add a base URL if you are not
on https://app.snagrelay.com:
EXPO_PUBLIC_SNAG_RELAY_BASE_URL=https://app.snagrelay.comWrap your app
Pass the env value into the provider. Expo only inlines EXPO_PUBLIC_* in your
source, not inside node_modules, so this line has to live in the app.
import { Platform } from 'react-native';
import { SnagRelayProvider } from 'react-native-snagrelay';
export default function App() {
const app = <YourApp />;
if (Platform.OS !== 'web') {
return (
<SnagRelayProvider apiKey={process.env.EXPO_PUBLIC_SNAG_RELAY_API_KEY}>
{app}
</SnagRelayProvider>
);
}
return app;
}On a native-only app you can drop the Platform check.
Why not put the key in the JSX?
A hardcoded apiKey="…" works, but it ends up in git and in every build. The env
pattern is the same one Expo uses for every other secret-ish public key.
Bare React Native, no Expo
Use your own env helper (react-native-config, Babel inline, …) or paste the key:
<SnagRelayProvider apiKey="YOUR_API_KEY">
<YourApp />
</SnagRelayProvider>Expo config plugin
Writes the key into extra.snagrelay (read through expo-constants). Still prefer
.env so the key is not in app.json.
{ "expo": { "plugins": [["react-native-snagrelay", { "apiKey": "YOUR_API_KEY" }]] } }Open a report
Rebuild, then:
- TestFlight / release: shake the device, or tap the Report button.
- Local development: shake opens the React Native / Expo developer menu, not
the widget. Pick Report a Snag, or tap the button. Set
shakeToOpen={true}if you want shake to open the widget in__DEV__as well (both will fire).
iOS Simulator: Device → Shake. The Android emulator has no shake gesture.
Expo Go
Screenshots, the form, and network capture work in Expo Go. Shake uses expo-sensors
(npx expo install expo-sensors). Device info falls back to Platform and
expo-constants.
Screen trail (the last 15 screens)
There is no session replay on React Native. The stand-in is a screen trail: the last 15 routes, with token-like params redacted. It is opt-in.
Expo Router, once in the root layout:
import { usePathname, useGlobalSearchParams } from 'expo-router';
import { useSnagRelayScreenTrail } from 'react-native-snagrelay';
useSnagRelayScreenTrail(usePathname(), useGlobalSearchParams());React Navigation:
import { trackNavigationState } from 'react-native-snagrelay';
<NavigationContainer onStateChange={trackNavigationState}>Configure it from the dashboard
How reporters open it and what they see is set under Widget in the dashboard, not in code:
- Launch: the floating button and your own button. See Launch.
- Capture and Form: the first screen, markup tools, report types, and form fields. See Capture and Form.
React Native has no element picker (there is no DOM). Reports use the screenshot, annotations, and the screen trail.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
apiKey | string | from .env / plugin | Prefer process.env.EXPO_PUBLIC_SNAG_RELAY_API_KEY |
baseUrl | string | https://app.snagrelay.com | Or EXPO_PUBLIC_SNAG_RELAY_BASE_URL |
user | { email?, name?, id? } | none | Attribute reports to the signed-in user |
autoShowButton | boolean | true | Set false to use only your own button or a shake |
buttonPosition | 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | from the project | |
theme | { primaryColor?, textColor?, iconColor?, backgroundColor? } | none | Overrides the dashboard colours |
shakeToOpen | boolean | true in production, false in __DEV__ | Shake is the dev-menu gesture locally |
shakeSensitivity | 'low' | 'medium' | 'high' | 'medium' | Expo Go accelerometer fallback only |
hapticFeedback | boolean | true |
Open it from your own button
import { SnagRelay } from 'react-native-snagrelay';
<Button title="Report a problem" onPress={() => SnagRelay.open()} />SnagRelay.close() and SnagRelay.setUser({ email }) are also available.
What a report contains
- Device and build: device info, app version and build, React Native version, Hermes,
New Architecture, and with
expo-updatestheupdateId,channel, andruntimeVersion - Network, with bodies: the last 50 requests, with string / JSON / text bodies up to 64 KB. Secrets are redacted on the device. Skipped when the plan does not include network capture
- Console and JS errors
- Screen trail: the last 15 screens, when you call the hook above
- Screenshot with markup: pen, arrow, highlight, comment, and redact (paid plans)
Not included: session replay, video, or an element picker.
Screen trail and body capture need SDK 0.2 or later
Request bodies, the screen trail, and build metadata ship in react-native-snagrelay
0.2. Check your installed version if they're missing.