Skip to content

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:

Terminal window
npm install ferry-react-native

React 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.

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');
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));
});
// Later
installation.remove();
delivery.remove();

Next steps