React Native SDK for Appfastfly — mobile deep linking & attribution.
- Deep Linking — Universal Links (iOS) + App Links (Android) + URI schemes
- Deferred Deep Links — attribute installs to the original link via device fingerprint, clipboard token, and install referrer
- Link Creation — generate trackable short links with custom payloads and Open Graph metadata
- User Identity — associate devices with user IDs for cross-device attribution
- Event-driven — subscribe to deep link events with automatic caching
| Platform | Minimum version |
|---|---|
| iOS | 15.0+ |
| Android | API 24+ (7.0) |
| React Native | 0.76+ (New Architecture / TurboModules) |
Note: This SDK requires the New Architecture (TurboModules) which is enabled by default starting from React Native 0.76. It does not support the old architecture (Bridge).
yarn add @appfastfly/react-native
# or
npm install @appfastfly/react-nativeiOS — install CocoaPods:
cd ios && bundle exec pod installAndroid — no additional steps, Gradle auto-links the module.
<key>AppfastflyApiKey</key>
<string>YOUR_API_KEY</string>Optionally override the service URL (defaults to https://api.appfastfly.io.vn):
<key>AppfastflyServiceUrl</key>
<string>https://your-custom-api.com</string>Add inside the <application> tag:
<meta-data
android:name="com.appfastfly.API_KEY"
android:value="YOUR_API_KEY" />Optionally override the service URL:
<meta-data
android:name="com.appfastfly.SERVICE_URL"
android:value="https://your-custom-api.com" />Get your API key from the Appfastfly Dashboard.
In Xcode > target > Signing & Capabilities > Associated Domains, add:
applinks:link.yourdomain.com
// AppDelegate.mm
#import <AppfastflyDeepLinkModule.h>
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *))handler
{
[AppfastflyDeepLinkModule continueUserActivity:userActivity];
return YES;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
[AppfastflyDeepLinkModule openURL:url];
return YES;
}// AppDelegate.swift
import AppfastflyDeepLinkModule
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
AppfastflyDeepLinkModule.continue(userActivity)
return true
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
AppfastflyDeepLinkModule.open(url)
return true
}In Xcode > target > Info > URL Types, add your custom scheme (e.g. myapp).
Add inside your MainActivity tag:
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<!-- App Links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="link.yourdomain.com" />
</intent-filter>
<!-- URI Scheme -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>import android.content.Intent
import android.os.Bundle
import com.appfastfly.deeplink.AppfastflyDeepLinkModule
class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppfastflyDeepLinkModule.handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
AppfastflyDeepLinkModule.handleIntent(intent)
}
}Call once at app startup, before any navigation:
import { Appfastfly } from '@appfastfly/react-native';
await Appfastfly.init();const unsubscribe = Appfastfly.subscribe((event) => {
console.log('Payload:', event.payload);
console.log('First session?', event.isFirstSession);
if (event.payload.screen) {
navigation.navigate(event.payload.screen, event.payload);
}
});
// Clean up when done
unsubscribe();import React, { useEffect } from 'react';
import { Appfastfly } from '@appfastfly/react-native';
function App() {
useEffect(() => {
Appfastfly.init();
const unsubscribe = Appfastfly.subscribe((event) => {
if (event.payload.productId) {
navigation.navigate('Product', { id: event.payload.productId });
}
});
return unsubscribe;
}, []);
return <MainNavigator />;
}const latest = Appfastfly.getLatestParams();
const first = Appfastfly.getFirstParams();const link = await Appfastfly.createLink({
payload: { screen: 'Product', productId: '123' },
channel: 'social',
campaign: 'summer-sale',
ogTitle: 'Check out this product!',
ogDescription: 'Get 20% off with this link',
ogImageUrl: 'https://example.com/product.jpg',
});
console.log(link.url);
// → https://link.myapp.com/l/abc123// Associate device with a user
await Appfastfly.setIdentity('user-456');
// Remove association
await Appfastfly.logout();Initialize the SDK. Must be called once before any other method. Reads configuration from native (Info.plist / AndroidManifest).
Returns: Promise<void>
Listen for deep link events. If params are already available, fires the callback immediately.
| Parameter | Type | Description |
|---|---|---|
listener |
(event: DeepLinkEvent) => void |
Callback on event |
Returns: () => void — unsubscribe function
interface DeepLinkEvent {
url?: string;
payload: Record<string, any>;
matchMethod?: string;
matchConfidence?: number;
isFirstSession: boolean;
}Returns the most recent deep link payload, or null.
Returns the payload from the install-attributed deep link (first session only), or null.
Create a trackable short link.
interface CreateLinkParams {
payload: Record<string, any>;
ogTitle?: string;
ogDescription?: string;
ogImageUrl?: string;
channel?: string;
campaign?: string;
tags?: string[];
iosRedirectUrl?: string;
androidRedirectUrl?: string;
webRedirectUrl?: string;
expiresAt?: string;
}Returns: Promise<{ shortCode: string; url: string }>
Associate the current device with a user ID for cross-device attribution.
Remove the current device-user association.
- Verify
applinks:in Associated Domains matches your link domain exactly - Ensure the Apple App Site Association (AASA) file is served over HTTPS with a valid certificate
- Long-press a link in Safari to verify "Open in App" appears
- Verify
assetlinks.jsonis accessible athttps://your-domain/.well-known/assetlinks.json - The SHA-256 fingerprint must match your signing certificate
android:autoVerify="true"must be set on the intent-filter
- Ensure
init()is called beforesubscribe() - Verify
continueUserActivity:(iOS) orhandleIntent()(Android) is wired in your AppDelegate / MainActivity - Check native logs for
[Appfastfly]warnings
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT