Cross-platform frameworks add a layer between your app code and the native platform. Deep linking SDKs need to bridge this gap: the native OS delivers the URL, the SDK processes it, and the result reaches your JavaScript, Dart, or TypeScript code. This guide covers SDK integration patterns for the major cross-platform frameworks.
For framework-specific deep linking setup (without an SDK), see React Native Deep Linking and Flutter Deep Linking. For the SDK feature comparison, see Deferred Deep Linking SDKs: Feature Comparison.
Why Use an SDK
You can implement basic deep linking without any SDK. The OS delivers the URL, and your router handles it. An SDK adds value when you need:
- Deferred deep linking: Matching a link click to an app install that happens later. This requires server-side fingerprinting that you can't build into a URL alone.
- Attribution: Knowing which link, campaign, or channel led to an install or conversion.
- Link creation: Generating short links programmatically from within the app.
- Analytics: Click counts, conversion rates, and device breakdown for your links.
If you only need direct deep linking (app is installed, user taps link, app opens to the right screen), the platform's built-in linking APIs are sufficient. No SDK required.
React Native Integration
Installation
npm install @tolinku/react-native-sdk
# or
yarn add @tolinku/react-native-sdk
cd ios && pod install
Initialization
import { Tolinku } from '@tolinku/react-native-sdk';
// Initialize early in your app's entry point
Tolinku.init({
apiKey: 'tolk_pub_your_publishable_key',
});
Deferred Deep Link Handling
import { Tolinku } from '@tolinku/react-native-sdk';
useEffect(() => {
// Check for deferred deep link on first launch
Tolinku.checkDeferredLink().then((result) => {
if (result) {
navigation.navigate(result.screen, result.params);
}
});
}, []);
Link Creation
const link = await Tolinku.createLink({
path: '/invite/' + userId,
campaign: 'referral',
ogTitle: 'Join me on the app',
ogDescription: 'Use my referral link to get started',
});
// link.url = "https://go.yourapp.com/abc123"
Native Setup
The React Native SDK still requires the same native configuration as manual deep linking:
- iOS: Associated Domains entitlement, AppDelegate
continueUserActivityhandler - Android: Intent filters with
autoVerify, Digital Asset Links file
The SDK doesn't replace this configuration; it adds deferred linking and analytics on top of it.
See the React Native SDK docs for the full API reference.
Flutter Integration
Installation
# pubspec.yaml
dependencies:
tolinku: ^1.0.0
Initialization
import 'package:tolinku/tolinku.dart';
void main() {
Tolinku.init(apiKey: 'tolk_pub_your_publishable_key');
runApp(MyApp());
}
Deferred Deep Link Handling
import 'package:tolinku/tolinku.dart';
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_checkDeferredLink();
}
Future<void> _checkDeferredLink() async {
final result = await Tolinku.checkDeferredLink();
if (result != null) {
router.go(result.path);
}
}
}
Link Creation
final link = await Tolinku.createLink(
path: '/invite/$userId',
campaign: 'referral',
ogTitle: 'Join me on the app',
ogDescription: 'Use my referral link to get started',
);
// link.url = "https://go.yourapp.com/abc123"
Native Setup
Same as React Native: the Flutter SDK requires Associated Domains (iOS) and intent filters (Android) to be configured in the native project.
See the Flutter SDK docs for the full API reference.
Capacitor / Ionic Integration
Capacitor apps use the @capacitor/app plugin to receive deep links, similar to React Native's Linking module.
Configuration
// capacitor.config.ts
const config: CapacitorConfig = {
appId: 'com.yourapp',
plugins: {
App: {
// Deep linking configuration
},
},
};
iOS Setup
Add Associated Domains in Xcode (same as native iOS or React Native).
Android Setup
Add intent filters to AndroidManifest.xml (same as native Android).
Link Handling
import { App } from '@capacitor/app';
App.addListener('appUrlOpen', (event) => {
const url = new URL(event.url);
const path = url.pathname;
const params = Object.fromEntries(url.searchParams);
// Route to the correct page
router.navigateByUrl(path);
});
Using Tolinku Web SDK in Capacitor
Since Capacitor runs a web view, you can use the Tolinku Web SDK for analytics and link creation:
import { Tolinku } from '@tolinku/web-sdk';
Tolinku.init({ apiKey: 'tolk_pub_your_publishable_key' });
// Create a link
const link = await Tolinku.createLink({
path: '/invite/' + userId,
});
For deferred deep linking in Capacitor, combine the native deep link listener with a server-side check:
App.addListener('appUrlOpen', async (event) => {
// Handle direct deep links
handleDeepLink(event.url);
});
// On first launch, check for deferred link
const deferred = await fetch('https://api.tolinku.com/v1/deferred-link', {
method: 'POST',
headers: { 'x-api-key': 'tolk_pub_your_key' },
body: JSON.stringify({ fingerprint: getDeviceFingerprint() }),
});
Integration Architecture
Where the SDK Fits
User taps link
│
▼
OS receives URL → checks App Links / Universal Links
│
▼
App launches (or comes to foreground)
│
▼
Native layer receives URL
│
▼
SDK processes URL:
- Records click event
- Extracts parameters
- Checks for deferred link (first launch only)
│
▼
Cross-platform bridge (React Native bridge / Flutter platform channel)
│
▼
Your JavaScript/Dart code receives parsed result
│
▼
Router navigates to the correct screen
What the SDK Handles
| Capability | Without SDK | With SDK |
|---|---|---|
| Direct deep links | Yes (built-in) | Yes |
| URL parsing | Manual | Automatic |
| Deferred deep links | No | Yes |
| Link creation | Manual API calls | SDK method |
| Click analytics | No | Automatic |
| Attribution | No | Automatic |
| Fingerprinting | No | Built-in |
Best Practices
Initialize Early
Initialize the SDK before your app's navigation is ready. The deferred deep link check should happen before the user sees the home screen, so they're routed directly to the intended content.
Don't Block the UI
The deferred deep link check makes a network request. Show a splash or loading screen while the check runs, but set a timeout (2-3 seconds) to ensure the app isn't stuck waiting.
// React Native example with timeout
const result = await Promise.race([
Tolinku.checkDeferredLink(),
new Promise(resolve => setTimeout(() => resolve(null), 3000)),
]);
Test on Physical Devices
SDK features like deferred deep linking rely on device fingerprinting (IP address, user agent, device model). These signals are different in simulators and emulators. Always test on physical devices.
Handle Both Direct and Deferred
Your routing code should handle links from both sources:
function handleLink(result) {
if (result.path.startsWith('/product/')) {
navigation.navigate('Product', { id: result.params.id });
} else if (result.path.startsWith('/invite/')) {
navigation.navigate('Invite', { code: result.params.code });
}
}
// Direct deep links
Linking.addEventListener('url', ({ url }) => {
handleLink(parseUrl(url));
});
// Deferred deep links
Tolinku.checkDeferredLink().then((result) => {
if (result) handleLink(result);
});
The same routing function handles both cases. This keeps your code DRY and ensures consistent behavior.
For the SDK swap process, see SDK Swap Guide. For all SDK documentation, see Tolinku SDK docs. For deep linking features, see Tolinku deep linking.
Get deep linking tips in your inbox
One email per week. No spam.