React Native SDK
The Ferry React Native SDK is a typed wrapper around the native iOS and Android SDKs. It includes an Expo config plugin for Associated Domains and verified App Links.
Install
Add ferry-react-native from npm:
npm install ferry-react-nativepnpm add ferry-react-nativeyarn add ferry-react-nativebun add ferry-react-nativeReact Native apps still need iOS 15 or later and Android API 24 or later.
1. Configure at app start
import { Ferry } from 'ferry-react-native';
Ferry.configure('pk_test_xxx');2. Register the unified callback
import { useEffect } from 'react';import { Ferry } from 'ferry-react-native';import type { FerryLink } from 'ferry-react-native';
export function useFerryLink() { useEffect(() => { const subscription = Ferry.onLink((link: FerryLink) => { route(link.data); });
return () => subscription.remove(); }, []);}Register once in the root component. This starts deferred matching and receives both direct and deferred links.
3. Forward React Native links
import { useEffect } from 'react';import { Linking } from 'react-native';import { Ferry } from 'ferry-react-native';
export function useIncomingLinks() { useEffect(() => { Linking.getInitialURL().then((url) => { if (url) Ferry.handle(url); });
const subscription = Linking.addEventListener('url', ({ url }) => { Ferry.handle(url); });
return () => subscription.remove(); }, []);}4. Configure Expo
Add the config plugin with every Ferry hostname used by the project:
{ "expo": { "plugins": [ [ "ferry-react-native", { "linkDomains": ["acme.feryl.io", "go.acme.com"] } ] ] }}The plugin adds iOS Associated Domains entries and one Android autoVerify intent filter during prebuild.
Bare React Native
In Xcode, add applinks: entries for the project hostnames. In AndroidManifest.xml, add an autoVerify App Links intent filter for the same hostnames.
Standard React Native linking forwards the initial URL and later URL events. No Ferry-specific AppDelegate or Activity bridge code is required.
5. Track events
import { Ferry, FerryEvents } from 'ferry-react-native';
Ferry.track(FerryEvents.login);Ferry.track(FerryEvents.signup, 'opaque_customer_42');Ferry.track(FerryEvents.purchase('txn_1', 9.99, 'USD', 'pro_monthly'), 'opaque_customer_42');Link shape
type FerryLink = { data: Record<string, string>; url: string | null; clickId: string | null; method: string; confidence: { kind: 'deterministic' } | { kind: 'probabilistic'; score: number }; isDeferred: boolean;};The method field is intentionally open to future server values. Route using data, and use isDeferred when behavior differs between an installed-app open and a deferred first install.
Observe delivery results
const installation = Ferry.onInstallation((result) => { console.log(result.attribution, result.isNewInstallation);});
const delivery = Ferry.onEventDelivery((result) => { result.rejected.forEach((item) => report(item.reason));});
// Laterinstallation.remove();delivery.remove();