Quick start: React Native / Expo
The SDK is plain TypeScript with no native code, so it works in Expo Go, development builds and bare React Native. It does not import react-native itself; you hand it the few platform pieces it needs.
1. Install
npx expo install @himmetkaan/remote-devtools @react-native-async-storage/async-storageAsyncStorage is used to remember the device id and the pairing, so the app reconnects by itself after a restart.
2. Initialise
Create the instance once, for example in a module imported by your root layout:
// devtools.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import {AppState, Platform} from 'react-native';
import {
functionsModule,
networkModule,
reactNativeLifecycle,
RemoteDevTools,
} from '@himmetkaan/remote-devtools';
export const functions = functionsModule();
export const devtools = RemoteDevTools.init({
enabled: __DEV__ || isInternalBuild, // off in production unless you switch it on
isDevelopment: __DEV__, // simulators / emulators find the local relay
app: {id: 'com.example.app', name: 'Example', version: '1.4.0', build: '210'},
device: {platform: Platform.OS, os: String(Platform.Version)},
meta: {environment: 'staging'}, // shown on the device card in the UI
storage: AsyncStorage,
lifecycle: reactNativeLifecycle(AppState),
history: {enabled: true, maxEntries: 500}, // send what happened before pairing
captureConsole: ['warn', 'error'],
modules: [functions, networkModule()],
});networkModule() captures XMLHttpRequest (which React Native's fetch and axios use) automatically.
Enabling it outside development
enabled is the only gate. A common pattern is to start the SDK when a hidden developer menu is switched on and call devtools.destroy() when it is switched off. While disabled the SDK opens no sockets and patches nothing.
3. Connect
Simulator / emulator — with isDevelopment: true the app looks for a relay on localhost (iOS simulator) and 10.0.2.2 (Android emulator), ports 8787 and 8080, and sends a connect request you approve in the UI.
Physical device on the same network — add your computer's address to the discovery hosts. In Expo the Metro host is a good guess:
import Constants from 'expo-constants';
const metroHost = Constants.expoConfig?.hostUri?.split(':')[0];
RemoteDevTools.init({
// …
discovery: {localhost: {hosts: ['localhost', '10.0.2.2', ...(metroHost ? [metroHost] : [])]}},
});Any device, any network — scan the QR code or type the 6-digit code shown in the UI:
await devtools.connection.pairWithQr(scannedText);
await devtools.connection.pairWithCode('123456', 'https://devtools.example.com');The SDK only gives you state and actions; the connect screen is yours to design. Subscribe to the state to show it:
const [state, setState] = useState(devtools.connection.state);
useEffect(() => devtools.connection.subscribe(setState), []);
// state.status: 'idle' | 'discovering' | 'connecting' | 'pending-approval' | 'connected' | 'reconnecting' | 'disabled'4. Add more modules
import {asyncStorageAdapter, flagsModule, stateModule, storageModule, zustandAdapter} from '@himmetkaan/remote-devtools';
const flags = flagsModule();
export const newCheckout = flags.define({key: 'checkout.v2', title: 'New checkout', field: {type: 'boolean'}});
RemoteDevTools.init({
// …
modules: [
functions,
networkModule(),
storageModule({adapters: [asyncStorageAdapter(AsyncStorage)]}),
stateModule({stores: [zustandAdapter(useCartStore, {id: 'cart', title: 'Cart'})]}),
flags,
],
});Each module has its own page under Modules.
Troubleshooting
- The app does not find the relay. Check that the relay accepts connect requests (
CONNECT_REQUESTS=local; the desktop app does by default) and that the phone and computer are on the same network. Guest and corporate Wi-Fi networks often block traffic between devices. - iOS asks for local network access. Allow it (Settings → Privacy & Security → Local Network); without it the app cannot reach your computer.
- Plain
ws://to a non-local address fails on iOS. App Transport Security blocks it. Use awss://relay (Self-hosting) or a tunnel such ascloudflared.
