React Native Deep Links Guide

Complete step-by-step guide to implement, configure, and test deep links in your React Native application

1. Overview & Prerequisites

What are React Native Deep Links?

React Native deep links allow users to navigate directly to specific content within your app from external sources like websites, emails, or other apps. They provide a seamless user experience by opening your app and navigating to the right screen.

Types of Deep Links

Custom URL Schemes

App-specific URL schemes

myapp://product/123
Universal Links (iOS)

Verified HTTPS URLs for iOS

https://domain.com/product/123
App Links (Android)

Verified HTTPS URLs for Android

https://domain.com/product/123
Key Benefits
  • • Cross-platform deep linking with single codebase
  • • Seamless integration with React Navigation
  • • Automatic fallback to web when app isn't installed
  • • Better user engagement and retention
  • • Unified URL handling across platforms

Prerequisites

Development
  • • React Native 0.70+
  • • React Navigation v6+
  • • Node.js 16+
  • • Android Studio / Xcode
What We Provide
  • • Managed domain and hosting for verification files
  • • Automatic HTTPS with valid SSL certificates
  • • Auto-generated assetlinks.json and AASA files
  • • Seamless cross-platform verification support

2. React Navigation Setup

Install React Navigation

React Navigation provides built-in deep linking support. Install the required packages for your navigation setup.

Installation Commands
# Install React Navigation core
npm install @react-navigation/native

# Install navigation container
npm install @react-navigation/native-stack

# Install additional dependencies
npm install react-native-screens react-native-safe-area-context

# For iOS, install pods
cd ios && pod install && cd ..

# For Android, no additional setup needed

Configure Deep Linking

App.js / App.tsx
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

const App = () => {
  const linking = {
    prefixes: [
      'https://yourdomain.com',
      'myapp://',
      'https://www.yourdomain.com'
    ],
    config: {
      screens: {
        Home: {
          path: '',
          screens: {
            Main: '',
            Profile: 'profile/:userId',
            Settings: 'settings',
          },
        },
        Product: {
          path: 'product/:productId',
          parse: {
            productId: (productId: string) => productId,
          },
        },
        Dashboard: 'dashboard',
        Search: 'search/:query',
        Category: 'category/:categoryId',
      },
    },
  };

  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Product" component={ProductScreen} />
        <Stack.Screen name="Dashboard" component={DashboardScreen} />
        <Stack.Screen name="Search" component={SearchScreen} />
        <Stack.Screen name="Category" component={CategoryScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

Screen Configuration Examples

Basic Path

Home: {
  path: '',
  screens: {
    Main: '',
    Profile: 'profile/:userId',
  },
}

Parameter Parsing

Product: {
  path: 'product/:productId',
  parse: {
    productId: (id: string) => id,
  },
}

Query Parameters

Search: {
  path: 'search/:query',
  parse: {
    query: (query: string) => decodeURIComponent(query),
  },
}

Nested Navigation

Home: {
  path: '',
  screens: {
    Main: '',
    Profile: {
      path: 'profile/:userId',
      screens: {
        Details: 'details',
        Edit: 'edit',
      },
    },
  },
}

3. Android Configuration

Add Intent Filters

Configure your Android app to handle deep links by adding intent filters to your main activity.

android/app/src/main/AndroidManifest.xml
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme"
    android:windowSoftInputMode="adjustResize">
    
    <!-- Standard activity intent filter -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    
    <!-- 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="yourdomain.com" />
    </intent-filter>
    
    <!-- Custom URL scheme intent filter -->
    <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>

Digital Asset Links

For Android App Links, you need to verify domain ownership. Our service automatically generates and hosts the required assetlinks.json file.

Important
  • • The assetlinks.json file is automatically generated and hosted by our service
  • • File is accessible at: https://yourdomain.com/.well-known/assetlinks.json
  • • Must include your app's SHA256 certificate fingerprint
  • • Android will verify this file when users install your app

4. iOS Configuration

Add Associated Domains

Configure your iOS app to handle Universal Links by adding the Associated Domains capability.

Xcode Project Settings

1. Open your Xcode project

2. Select your app target

3. Go to Signing & Capabilities tab

4. Click + Capability

5. Add "Associated Domains"

6. Add your domains with applinks: prefix

Domain Configuration

Associated Domains
applinks:yourdomain.com
applinks:www.yourdomain.com

// For development/testing
applinks:dev.yourdomain.com

Apple App Site Association

Our service automatically generates and hosts the apple-app-site-association file required for Universal Links.

Automated Setup
  • • AASA file is automatically generated and hosted
  • • Accessible at: https://yourdomain.com/.well-known/apple-app-site-association
  • • Includes proper Content-Type headers
  • • Supports both applinks and webcredentials

5. URL Handling

Screen Implementation

ProductScreen.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const ProductScreen = ({ route, navigation }) => {
  const { productId } = route.params;

  React.useEffect(() => {
    // Handle deep link parameters
    if (productId) {
      // Fetch product data or handle navigation
      console.log('Product ID from deep link:', productId);
    }
  }, [productId]);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Product Details</Text>
      <Text style={styles.subtitle}>Product ID: {productId}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
  },
});

export default ProductScreen;

Advanced URL Handling

Advanced Linking Configuration
const linking = {
  prefixes: ['https://yourdomain.com', 'myapp://'],
  config: {
    screens: {
      Home: {
        path: '',
        screens: {
          Main: '',
          Profile: {
            path: 'profile/:userId',
            parse: {
              userId: (userId: string) => userId,
            },
          },
        },
      },
      Product: {
        path: 'product/:productId',
        parse: {
          productId: (productId: string) => productId,
        },
      },
      Search: {
        path: 'search/:query',
        parse: {
          query: (query: string) => decodeURIComponent(query),
        },
      },
    },
  },
  // Custom URL handling
  getInitialURL() {
    // Handle initial URL when app is opened from deep link
    return null;
  },
  subscribe(listener) {
    // Handle URL changes when app is already running
    return () => {
      // Cleanup subscription
    };
  },
};

🔒 Security Considerations

Input Validation

Critical

Always validate and sanitize incoming URL parameters to prevent security vulnerabilities.

// ✅ Good: Validate parameters
const ProductScreen = ({ route }) => {
  const { productId } = route.params;
  
  // Validate product ID format
  const isValidProductId = (id) => {
    return /^[a-zA-Z0-9_-]{1,50}$/.test(id);
  };
  
  React.useEffect(() => {
    if (productId && isValidProductId(productId)) {
      // Safe to use productId
      fetchProduct(productId);
    } else {
      // Handle invalid product ID
      navigation.navigate('Error', { message: 'Invalid product ID' });
    }
  }, [productId]);
};

// ❌ Bad: Direct usage without validation
const ProductScreen = ({ route }) => {
  const { productId } = route.params;
  
  // Direct usage without validation
  fetchProduct(productId); // Could be dangerous
};

Authentication & Authorization

Important
  • • Always verify user authentication before accessing sensitive content
  • • Validate user permissions for accessed resources
  • • Don't expose sensitive data through URL parameters
  • • Use secure tokens for authenticated deep links
  • • Implement rate limiting for URL processing

7. Testing & Debugging

Testing Methods

1. Android Testing (ADB)

adb shell am start \
    -W -a android.intent.action.VIEW \
    -d "https://yourdomain.com/product?id=123" \
    com.yourcompany.yourapp

2. iOS Testing (Simulator)

xcrun simctl openurl booted "https://yourdomain.com/product?id=123"

3. React Native Development

npx react-native start --reset-cache
npx react-native run-android
npx react-native run-ios

Debugging Tips

  • • Use Metro bundler console to monitor deep link events
  • • Add console.log statements in your screen components
  • • Test on physical devices for best results
  • • Use Flipper for advanced debugging
  • • Check platform-specific logs (Android Logcat, iOS Console)

8. Common Issues & Solutions

❌ Deep links not working

  • • Check if linking configuration matches your URL structure
  • • Verify domain verification files are accessible
  • • Ensure proper Content-Type headers for verification files
  • • Test on physical devices (not just simulators)

⚠️ Navigation not working

  • • Verify screen names match your navigation structure
  • • Check parameter parsing in linking configuration
  • • Ensure screens are properly registered in navigator
  • • Test with simple URLs first

ℹ️ Platform-specific issues

  • • Android: Check assetlinks.json accessibility and format
  • • iOS: Verify Associated Domains capability and AASA file
  • • Both: Ensure HTTPS is used for verification files
  • • Both: Check for proper certificate fingerprints

✅ Best Practices

  • • Always test on physical devices
  • • Use consistent URL patterns across platforms
  • • Implement proper error handling for invalid URLs
  • • Keep linking configuration simple and focused
  • • Test deep links from various sources (Safari, Messages, etc.)

🎉 You're All Set!

Your React Native app should now handle deep links seamlessly across both platforms. Test thoroughly on physical devices.