[{"data":1,"prerenderedAt":140},["ShallowReactive",2],{"doc:\u002Fdocs\u002Fsdks\u002Freact-native":3},{"page":4,"toc":132,"updated":139},{"path":5,"title":6,"seoTitle":7,"description":8,"blocks":9},"\u002Fdocs\u002Fsdks\u002Freact-native","React Native","React Native SDK: Native iOS and Android Identification","Identify devices in React Native apps through the native iOS and Android SDKs, with one TypeScript API and the same verdicts on both platforms.",[10,13,18,24,27,40,42,45,51,53,56,73,84,86,89,120,122,125,130],{"type":11,"text":12},"p","`@fingerly\u002Freact-native` is a thin bridge to the native [iOS](\u002Fdocs\u002Fsdks\u002Fios) and [Android](\u002Fdocs\u002Fsdks\u002Fandroid) SDKs. Almost every signal worth having on a phone is out of reach of JavaScript, so the bridge calls native code rather than collecting less.",{"type":14,"level":15,"text":16,"id":17},"heading",2,"Requirements","requirements",{"type":19,"items":20},"list",[21,22,23],"React Native 0.74 or newer, including the New Architecture.","iOS 13 and Android 5.0 (API 21) or newer.","A development build. Expo Go cannot load native modules.",{"type":14,"level":15,"text":25,"id":26},"Install","install",{"type":28,"samples":29},"code",[30,34,37],{"label":31,"lang":32,"code":33},"npm","bash","npm install @fingerly\u002Freact-native\ncd ios && pod install",{"label":35,"lang":32,"code":36},"pnpm","pnpm add @fingerly\u002Freact-native\ncd ios && pod install",{"label":38,"lang":32,"code":39},"yarn","yarn add @fingerly\u002Freact-native\ncd ios && pod install",{"type":11,"text":41},"Autolinking adds the native modules. Rebuild the app after installing.",{"type":14,"level":15,"text":43,"id":44},"Identify a device","identify-a-device",{"type":28,"samples":46},[47],{"label":48,"lang":49,"code":50},"fingerly.ts","ts","import { load } from '@fingerly\u002Freact-native'\n\nconst fingerly = await load({ apiKey: 'fly_pk_us_production_…' })\n\nexport async function signIn(email: string, password: string) {\n  const { requestId } = await fingerly.identify({ tag: 'sign-in' })\n  return api.signIn({ email, password, requestId })\n}",{"type":11,"text":52},"Send `requestId` to your backend with the action, and decide there after reading the stored event with a secret key. See [server-side verification](\u002Fdocs\u002Fserver-side-verification).",{"type":14,"level":15,"text":54,"id":55},"API","api",{"type":57,"title":58,"fields":59},"fields","`load(options)`",[60,65,68],{"name":61,"type":62,"text":63,"required":64},"apiKey","string","Your public key.",true,{"name":66,"type":62,"text":67},"endpoint","A custom API origin or first-party proxy.",{"name":69,"type":70,"text":71,"default":72},"consent","'granted' | 'pending' | 'denied'","Until it is `granted`, `identify` and `collect` read and send nothing and throw `ConsentError`. The state is shared by the whole app, so pass it on every `load`. See [consent](\u002Fdocs\u002Fprivacy-and-consent#consent).","'granted'",{"type":57,"title":74,"fields":75},"`identify(options)`",[76,79],{"name":77,"type":62,"text":78},"tag","Your own reference for this identification.",{"name":80,"type":81,"text":82,"default":83},"submit","boolean","Set `false` to collect without sending.","true",{"type":11,"text":85},"`identify` resolves with the same fields as the native SDKs: `requestId`, `visitorId`, `visitorIsNew`, `visitorConfidence`, `identifiable`, `duplicate`, `state`, `suspectScore` (`number | null`), `suspectLevel`, `triggers`, `verdicts` and `report`. `collect()` returns a report without submitting. `setConsent(state)` changes the consent state, and `consent` reads it.",{"type":14,"level":15,"text":87,"id":88},"Verdicts","verdicts",{"type":90,"columns":91,"rows":95},"table",[92,93,94],"Verdict","Platform","What it means",[96,100,103,106,109,112,116],[97,98,99],"`instrumentation`","Both","An instrumentation toolkit is attached to the app.",[101,98,102],"`mitm`","Something is intercepting the app's encrypted traffic.",[104,98,105],"`automation`","A debugger or a test runner is driving the app.",[107,98,108],"`tampering`","The app's code has been hooked or modified.",[110,98,111],"`farm`","The device looks mass-provisioned or freshly reset.",[113,114,115],"`jailbreak`, `simulator`","iOS","Jailbroken device; iOS Simulator.",[117,118,119],"`root`, `emulator`, `appCloner`","Android","Rooted device; emulator; cloning framework.",{"type":11,"text":121},"Verdicts a platform cannot answer are returned as `{ value: false, confidence: 'low', reasons: [] }`, so the shape is the same on both.",{"type":14,"level":15,"text":123,"id":124},"Errors","errors",{"type":28,"samples":126},[127],{"label":128,"lang":49,"code":129},"errors.ts","import { FingerlyError } from '@fingerly\u002Freact-native'\n\ntry {\n  await fingerly.identify()\n} catch (error) {\n  if (error instanceof FingerlyError && error.status === 401) {\n    \u002F\u002F the key is wrong or revoked\n  }\n}",{"type":11,"text":131},"Retries happen in the native layer. If the native module is missing, every call throws a `FingerlyError` that explains how to rebuild. Without consent, calls throw `ConsentError`, a `FingerlyError` whose `code` is `consent_required`.",[133,134,135,136,137,138],{"id":17,"text":16,"level":15},{"id":26,"text":25,"level":15},{"id":44,"text":43,"level":15},{"id":55,"text":54,"level":15},{"id":88,"text":87,"level":15},{"id":124,"text":123,"level":15},"2026-09-17T16:57:29.000Z",1789667797812]