React Native SDK
React Native SDK for Redirectly - Deep-link handling and attribution tracking for your mobile apps.
Features
- 🔀 Deep Link Handling - Automatically capture and process incoming Redirectly links
- 📊 Attribution Tracking - Track app installs and attribute them to link clicks
- 📱 React Native & Expo - Works with both bare React Native and Expo projects
- 🎯 TypeScript - Full TypeScript support with complete type definitions
- 🚀 Pure TypeScript - No native code required, works out of the box
Note: Link management features (create, update, delete links) are currently private and will be available in a future release.
Installation
Install the package using npm or yarn:
npm install react-native-redirectly
# or
yarn add react-native-redirectlyOptional: AsyncStorage for Persistent Install Tracking
For persistent install tracking across app restarts, install AsyncStorage:
npm install @react-native-async-storage/async-storage
# or
yarn add @react-native-async-storage/async-storageiOS Setup (Bare React Native)
For iOS, you need to install pods:
cd ios && pod install && cd ..Quick Start
import { useEffect } from 'react';
import Redirectly from 'react-native-redirectly';
export function App() {
useEffect(() => {
const redirectly = Redirectly.getInstance();
// Initialize the SDK
await redirectly.initialize({
apiKey: 'your-api-key',
enableDebugLogging: __DEV__,
});
// Listen for install attribution
const installSub = redirectly.onAppInstalled((install) => {
if (install.matched) {
console.log('Install attributed to:', install.matchedClick?.slug);
console.log('Matched link:', install.matchedLink?.target);
} else {
console.log('Organic install (no prior link click)');
}
});
// Check if SDK is ready
if (redirectly.isInitialized) {
console.log('Redirectly SDK ready');
}
return () => {
installSub.remove();
redirectly.dispose();
};
}, []);
return <YourApp />;
}Deep Link Configuration
The SDK automatically handles incoming Redirectly deep links. You need to configure your app to receive universal links (iOS) or app links (Android).
iOS (Expo)
Add to your app.json:
{
"expo": {
"ios": {
"associatedDomains": [
"applinks:yourname.redirectly.app"
]
}
}
}iOS (Bare React Native)
- In Xcode, go to your target’s Signing & Capabilities
- Add Associated Domains capability
- Add
applinks:yourname.redirectly.app
Alternatively, add to ios/YourApp/YourApp.entitlements:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yourname.redirectly.app</string>
</array>
</dict>
</plist>Important iOS Notes:
- Ensure your app is properly signed
- Enable Associated Domains capability in your Apple Developer account
- Add the domain to your App ID in Apple Developer Portal
Android (Expo)
Add to your app.json:
{
"expo": {
"android": {
"intentFilters": [
{
"action": "VIEW",
"autoVerify": true,
"data": [
{
"scheme": "https",
"host": "yourname.redirectly.app",
"pathPrefix": "/"
}
],
"category": ["BROWSABLE", "DEFAULT"]
}
]
}
}
}Android (Bare React Native)
Add an intent filter to android/app/src/main/AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:exported="true"
...>
<!-- Existing intent filters -->
<!-- Add Redirectly deep link intent filter -->
<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="yourname.redirectly.app"
android:pathPattern=".*" />
</intent-filter>
</activity>Replace yourname with your actual subdomain (e.g., myapp.redirectly.app).
API Reference
Initialization
Redirectly.getInstance()
Returns the singleton instance of the Redirectly SDK.
const redirectly = Redirectly.getInstance();initialize(config: RedirectlyConfig): Promise<void>
Initializes the SDK. Must be called before using any other methods.
interface RedirectlyConfig {
apiKey: string; // Your Redirectly API key
baseUrl?: string; // Custom API URL (default: https://redirectly.app)
enableDebugLogging?: boolean; // Enable console logging (default: false)
}
await redirectly.initialize({
apiKey: 'your-api-key',
enableDebugLogging: __DEV__,
});dispose(): void
Cleans up listeners and resets the SDK state. Call this before reinitializing with different config.
redirectly.dispose();isInitialized: boolean
Read-only property to check if the SDK has been initialized.
if (redirectly.isInitialized) {
// SDK is ready
}Event Subscriptions
onAppInstalled(callback): Subscription
Subscribe to app install attribution events. This fires when the SDK tracks an app install and determines if it was attributed to a prior link click (deferred deep link).
const subscription = redirectly.onAppInstalled((install) => {
if (install.matched) {
// User installed after clicking a Redirectly link
console.log('Attributed install');
console.log('Matched to:', install.matchedClick?.slug);
console.log('Link target:', install.matchedLink?.target);
// Navigate to the original link target
if (install.matchedLink?.target) {
navigateToTarget(install.matchedLink.target);
}
} else {
// Organic install (no prior link click)
console.log('Organic install');
showStandardOnboarding();
}
});
// Unsubscribe when done
subscription.remove();The install object contains:
id: Unique install identifiermatched: Whether install was attributed to a link clicktype:'organic'or'non-organic'username: Username of matched link (if matched)slug: Slug of matched link (if matched)matchedLink: Full link details (if matched)matchedClick: Original click event (if matched)processedAt: ISO timestamp when install was processed
Complete Example
Here’s a complete example using React hooks:
import React, { useEffect, useState } from 'react';
import { View, Text, Alert } from 'react-native';
import Redirectly from 'react-native-redirectly';
const App = () => {
const [initialized, setInitialized] = useState(false);
useEffect(() => {
const redirectly = Redirectly.getInstance();
const setupRedirectly = async () => {
try {
// Initialize the SDK
await redirectly.initialize({
apiKey: 'your-api-key',
enableDebugLogging: __DEV__,
});
setInitialized(true);
// Listen for install attribution
const installSub = redirectly.onAppInstalled((install) => {
if (install.matched) {
// Show personalized welcome
Alert.alert(
'Welcome!',
`Thanks for installing from our ${install.slug} link!`,
[
{
text: 'Get Started',
onPress: () => {
// Navigate to the content they were originally trying to reach
if (install.matchedLink?.target) {
navigateToTarget(install.matchedLink.target);
}
},
},
]
);
} else {
// Show standard onboarding
showStandardOnboarding();
}
});
return () => {
installSub.remove();
redirectly.dispose();
};
} catch (error) {
console.error('Error initializing Redirectly:', error);
}
};
setupRedirectly();
}, []);
const navigateToTarget = (target: string) => {
// Handle navigation based on your app's routing
console.log('Navigating to:', target);
// Example: Use React Navigation or your routing library
};
const showStandardOnboarding = () => {
// Show your standard onboarding flow
};
if (!initialized) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Initializing...</Text>
</View>
);
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Welcome to My App</Text>
</View>
);
};
export default App;Using with React Navigation
If you’re using React Navigation, here’s how to integrate:
import { NavigationContainer } from '@react-navigation/native';
import { useRef } from 'react';
import Redirectly from 'react-native-redirectly';
function App() {
const navigation = useRef(null);
useEffect(() => {
const redirectly = Redirectly.getInstance();
const setupRedirectly = async () => {
await redirectly.initialize({
apiKey: 'your-api-key',
enableDebugLogging: __DEV__,
});
redirectly.onAppInstalled((install) => {
if (install.matched && install.matchedLink?.target) {
const route = parseTargetToRoute(install.matchedLink.target);
navigation.current?.navigate(route.name, route.params);
}
});
};
setupRedirectly();
}, []);
const parseTargetToRoute = (target: string) => {
// Parse your target URL and return navigation route
// Example: 'https://example.com/product/123' -> { name: 'Product', params: { id: '123' } }
return { name: 'Home', params: {} };
};
return (
<NavigationContainer ref={navigation}>
{/* Your navigation structure */}
</NavigationContainer>
);
}Types
The SDK exports all TypeScript types for your convenience:
import type {
RedirectlyConfig,
RedirectlyAppInstallResponse,
RedirectlyLinkClick,
RedirectlyLinkResolution,
RedirectlyLink,
RedirectlyTempLink,
RedirectlyInstallType,
Subscription,
} from 'react-native-redirectly';Error Handling
All async methods may throw RedirectlyError:
import { RedirectlyError } from 'react-native-redirectly';
try {
const redirectly = Redirectly.getInstance();
await redirectly.initialize({
apiKey: 'your-api-key',
});
} catch (error) {
if (error instanceof RedirectlyError) {
console.log(error.type); // 'api' | 'network' | 'config' | 'link'
console.log(error.statusCode); // HTTP status code (for API errors)
console.log(error.details); // Additional error details
}
}How It Works
- Initialization: Call
initialize()with your API key - Deep Link Capture: SDK automatically listens for incoming Redirectly URLs
- Link Resolution: When a link is clicked, SDK resolves it and emits events
- Install Tracking: On first launch, SDK tracks the install and checks for attribution
- Attribution: If user clicked a link before installing, install is attributed to that link
Testing Install Attribution
During development, test install attribution by:
- Delete and reinstall your app to simulate first install
- Clear app data on Android or delete from device on iOS
- Click a Redirectly link → install app → open app
- The
onAppInstalledcallback should fire withmatched: true
The SDK automatically prevents duplicate install logging by creating a tracking file on first launch.
Best Practices
- Initialize Early - Initialize Redirectly as early as possible in your app lifecycle
- Handle Errors - Always wrap API calls in try-catch blocks
- Test Deep Links - Test both app-installed and app-not-installed scenarios
- Privacy - Inform users about link tracking in your privacy policy
- Debug Mode - Use
enableDebugLogging: trueduring development,falsein production - Cleanup - Always call
dispose()and remove subscriptions when components unmount
Troubleshooting
Links not opening app
- Verify deep link configuration in AndroidManifest.xml / entitlements
- Check that your subdomain matches exactly
- Ensure app is properly signed (iOS)
- Test with
adb(Android) or device logs (iOS)
Install attribution not working
- Ensure you’ve deleted and reinstalled the app
- Check that tracking file is being created
- Verify API key is correct
- Check debug logs for errors
SDK not initializing
- Verify API key is correct
- Check network connectivity
- Enable debug logging to see detailed error messages
- Ensure you’re calling
getInstance()beforeinitialize()
Roadmap
- 🔜 Link management API (create, update, delete links)
- 🔜 Link click event subscriptions
- 🔜 Initial link retrieval for cold starts
Support
Package Info
- Package: react-native-redirectly on npm
- License: MIT