Skip to main content
Facebook App Links allow you to deep link users from Facebook ads, posts, and other sources directly into specific content in your app. Deferred App Links work even if the user hasn’t installed your app yet. Deferred App Links enable you to send new users to the App Store or Google Play to install your app, and then deep link them to specific content after installation. This is particularly useful for:
  • Ad campaigns - Send users directly to a product page from an ad
  • Referral programs - Deep link to a referral signup page
  • Content sharing - Link to specific posts or articles
  • Promotional campaigns - Direct users to special offers

Basic Usage

import { AppLink } from 'react-native-fbsdk-next';

const url = await AppLink.fetchDeferredAppLink();

if (url) {
  console.log('Deferred App Link URL:', url);
  // Handle the deep link
} else {
  console.log('No deferred app link available');
}
import React, { useEffect } from 'react';
import { AppLink } from 'react-native-fbsdk-next';

export default function App() {
  useEffect(() => {
    checkForDeferredDeepLink();
  }, []);

  const checkForDeferredDeepLink = async () => {
    try {
      const url = await AppLink.fetchDeferredAppLink();
      
      if (url) {
        console.log('Received deferred deep link:', url);
        handleDeepLink(url);
      }
    } catch (error) {
      console.error('Error fetching deferred app link:', error);
    }
  };

  const handleDeepLink = (url) => {
    // Parse the URL and navigate to the appropriate screen
    // Example: myapp://product/12345
    const productId = url.split('/').pop();
    // Navigate to product page
  };

  return (
    // Your app content
  );
}

Complete Examples

import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import { AppLink } from 'react-native-fbsdk-next';
import { useNavigation } from '@react-navigation/native';

export default function DeepLinkHandler() {
  const [loading, setLoading] = useState(true);
  const navigation = useNavigation();

  useEffect(() => {
    handleDeferredLink();
  }, []);

  const handleDeferredLink = async () => {
    try {
      const url = await AppLink.fetchDeferredAppLink();
      
      if (url) {
        const linkType = parseLinkType(url);
        
        switch (linkType.type) {
          case 'product':
            navigation.navigate('Product', { id: linkType.id });
            break;
          case 'category':
            navigation.navigate('Category', { id: linkType.id });
            break;
          case 'offer':
            navigation.navigate('Offer', { code: linkType.id });
            break;
          default:
            navigation.navigate('Home');
        }
      } else {
        navigation.navigate('Home');
      }
    } catch (error) {
      console.error('Deferred link error:', error);
      navigation.navigate('Home');
    } finally {
      setLoading(false);
    }
  };

  const parseLinkType = (url) => {
    // Example URL: myapp://product/12345
    const parts = url.replace('myapp://', '').split('/');
    return {
      type: parts[0],
      id: parts[1],
    };
  };

  if (loading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" />
        <Text>Loading...</Text>
      </View>
    );
  }

  return null;
}

Using with React Navigation

import React, { useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { AppLink } from 'react-native-fbsdk-next';

const Stack = createNativeStackNavigator();

export default function AppNavigator() {
  const navigationRef = React.useRef();
  const [initialRoute, setInitialRoute] = React.useState(null);

  useEffect(() => {
    loadInitialRoute();
  }, []);

  const loadInitialRoute = async () => {
    try {
      const url = await AppLink.fetchDeferredAppLink();
      
      if (url) {
        const route = parseUrlToRoute(url);
        setInitialRoute(route);
      } else {
        setInitialRoute({ name: 'Home' });
      }
    } catch (error) {
      console.error(error);
      setInitialRoute({ name: 'Home' });
    }
  };

  const parseUrlToRoute = (url) => {
    // Parse your URL format
    // Return route object: { name: 'RouteName', params: {} }
    return { name: 'Home' };
  };

  if (!initialRoute) {
    return null; // Or loading screen
  }

  return (
    <NavigationContainer ref={navigationRef}>
      <Stack.Navigator initialRouteName={initialRoute.name}>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Product" component={ProductScreen} />
        {/* Other screens */}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

App Tracking Transparency (iOS)

Important for iOS: Deferred App Links require App Tracking Transparency (ATT) permission on iOS. Both your app and the Facebook app must have ATT permission granted.

Requesting ATT Permission

import React, { useEffect } from 'react';
import { Platform } from 'react-native';
import { AppLink } from 'react-native-fbsdk-next';
import { requestTrackingPermissionsAsync } from 'expo-tracking-transparency';

export default function App() {
  useEffect(() => {
    setupAppLinks();
  }, []);

  const setupAppLinks = async () => {
    if (Platform.OS === 'ios') {
      // Request ATT permission first
      const { status } = await requestTrackingPermissionsAsync();
      
      if (status === 'granted') {
        // Now fetch deferred app links
        const url = await AppLink.fetchDeferredAppLink();
        if (url) {
          handleDeepLink(url);
        }
      } else {
        console.log('ATT permission denied - deferred links may not work');
      }
    } else {
      // Android doesn't need ATT
      const url = await AppLink.fetchDeferredAppLink();
      if (url) {
        handleDeepLink(url);
      }
    }
  };

  const handleDeepLink = (url) => {
    console.log('Deep link:', url);
  };

  return (
    // Your app
  );
}

URL Parsing Helpers

import { useEffect, useState } from 'react';
import { AppLink } from 'react-native-fbsdk-next';

export function useAppLink() {
  const [url, setUrl] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchDeferredLink();
  }, []);

  const fetchDeferredLink = async () => {
    try {
      const deferredUrl = await AppLink.fetchDeferredAppLink();
      setUrl(deferredUrl);
    } catch (error) {
      console.error('Error fetching app link:', error);
    } finally {
      setLoading(false);
    }
  };

  const parseUrl = () => {
    if (!url) return null;

    try {
      const urlObj = new URL(url);
      return {
        protocol: urlObj.protocol,
        host: urlObj.host,
        pathname: urlObj.pathname,
        params: Object.fromEntries(urlObj.searchParams),
      };
    } catch {
      return null;
    }
  };

  return { url, loading, parsed: parseUrl() };
}

Usage

import React from 'react';
import { View, Text } from 'react-native';
import { useAppLink } from './hooks/useAppLink';

export default function AppLinkDemo() {
  const { url, loading, parsed } = useAppLink();

  if (loading) {
    return <Text>Checking for deep links...</Text>;
  }

  if (url) {
    return (
      <View>
        <Text>Deep Link Received!</Text>
        <Text>URL: {url}</Text>
        {parsed && (
          <View>
            <Text>Path: {parsed.pathname}</Text>
            <Text>Params: {JSON.stringify(parsed.params)}</Text>
          </View>
        )}
      </View>
    );
  }

  return <Text>No deep link</Text>;
}

Best Practices

  1. Check early - Fetch deferred app links as soon as possible during app startup
  2. Request ATT on iOS - Always request tracking permission before fetching deferred links
  3. Handle null gracefully - fetchDeferredAppLink() returns null if no link is available
  4. Parse defensively - Always validate and sanitize deep link URLs
  5. Track attribution - Use deep link parameters to track campaign performance
  6. Test thoroughly - Test on both fresh installs and existing users
  7. One-time fetch - Deferred links are typically only available on first launch

Troubleshooting

  1. Check ATT permission - Both your app and Facebook app need ATT permission
  2. Verify Facebook app is installed - The Facebook app must be logged in
  3. Check app configuration - Ensure your app is properly configured in Facebook dashboard
  4. Test on a real device - Deferred links don’t work in simulators
  1. Call fetchDeferredAppLink early - Call it during app initialization
  2. Check only once - Deferred links are consumed on first fetch
  3. Verify link format - Ensure your deep link URLs match your app’s URL scheme
  4. Check Facebook campaign - Verify your Facebook ad/post is configured for App Links

API Reference

MethodReturn TypeDescription
fetchDeferredAppLink()Promise<string | null>Fetch deferred deep link URL

Build docs developers (and LLMs) love