React Native Deep Links Guide
Complete step-by-step guide to implement, configure, and test deep links in your React Native application
Table of Contents
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
- • 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
- • React Native 0.70+
- • React Navigation v6+
- • Node.js 16+
- • Android Studio / Xcode
- • 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
3. Android Configuration
Add Intent Filters
Configure your Android app to handle deep links by adding intent filters to your main activity.
<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.
- • 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.
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
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.
- • 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
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
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
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
- • 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.)