Skip to Content
React Native SDK

React Native SDK

React Native SDK for Redirectly  - Deep-link handling and attribution tracking for your mobile apps.

npm version license

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-redirectly

Optional: 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-storage

iOS 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 />; }

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)

  1. In Xcode, go to your target’s Signing & Capabilities
  2. Add Associated Domains capability
  3. 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 identifier
  • matched: Whether install was attributed to a link click
  • type: '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

  1. Initialization: Call initialize() with your API key
  2. Deep Link Capture: SDK automatically listens for incoming Redirectly URLs
  3. Link Resolution: When a link is clicked, SDK resolves it and emits events
  4. Install Tracking: On first launch, SDK tracks the install and checks for attribution
  5. Attribution: If user clicked a link before installing, install is attributed to that link

Testing Install Attribution

During development, test install attribution by:

  1. Delete and reinstall your app to simulate first install
  2. Clear app data on Android or delete from device on iOS
  3. Click a Redirectly link → install app → open app
  4. The onAppInstalled callback should fire with matched: true

The SDK automatically prevents duplicate install logging by creating a tracking file on first launch.

Best Practices

  1. Initialize Early - Initialize Redirectly as early as possible in your app lifecycle
  2. Handle Errors - Always wrap API calls in try-catch blocks
  3. Test Deep Links - Test both app-installed and app-not-installed scenarios
  4. Privacy - Inform users about link tracking in your privacy policy
  5. Debug Mode - Use enableDebugLogging: true during development, false in production
  6. Cleanup - Always call dispose() and remove subscriptions when components unmount

Troubleshooting

  • 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() before initialize()

Roadmap

  • 🔜 Link management API (create, update, delete links)
  • 🔜 Link click event subscriptions
  • 🔜 Initial link retrieval for cold starts

Support

Package Info

Last updated on