Skip to main content

Deep Links

Deep links allow users to open your app directly from a URL, enabling features like email verification links, social sharing, and custom integrations.
Deep links use URL schemes (like myapp://) to open your app and optionally navigate to specific content within it.

Overview

When you configure deep link schemes in your build.yaml, a0 automatically:
  1. Registers the URL schemes with iOS (Info.plist)
  2. Adds intent filters to Android (AndroidManifest.xml)
  3. Configures Expo to recognize the schemes at runtime
Your app’s bundle ID is automatically added as a scheme, so you always have at least one working deep link scheme without any configuration.

Configuration

Add the schemes property to your .a0/build.yaml file:
general:
  runtimeVersion: "exposdk:54.0.0"

schemes:
  - myapp
  - myapp-dev

ios:
  versionName: "1.0.0"

android:
  versionName: "1.0.0"
Schemes must be lowercase and start with a letter. They can only contain letters, digits, plus signs (+), hyphens (-), and dots (.).
Use the expo-linking library to handle incoming deep links in your app.

Basic Setup

import * as Linking from 'expo-linking';
import { useEffect } from 'react';

export default function App() {
  useEffect(() => {
    // Handle deep link when app is already open
    const subscription = Linking.addEventListener('url', ({ url }) => {
      handleDeepLink(url);
    });

    // Handle deep link that opened the app
    Linking.getInitialURL().then((url) => {
      if (url) {
        handleDeepLink(url);
      }
    });

    return () => subscription.remove();
  }, []);

  const handleDeepLink = (url: string) => {
    const parsed = Linking.parse(url);
    console.log('Deep link received:', parsed);
    // Navigate based on parsed.path and parsed.queryParams
  };

  return (
    // Your app content
  );
}
Generate URLs that open your app:
import * as Linking from 'expo-linking';

// Create a URL with your custom scheme
const url = Linking.createURL('profile/123', {
  scheme: 'myapp',
  queryParams: { ref: 'email' }
});
// Result: myapp://profile/123?ref=email

With React Navigation

If you’re using React Navigation, configure deep linking in your navigation container:
import { NavigationContainer } from '@react-navigation/native';

const linking = {
  prefixes: ['myapp://', 'myapp-dev://'],
  config: {
    screens: {
      Home: '',
      Profile: 'profile/:id',
      Settings: 'settings',
    },
  },
};

export default function App() {
  return (
    <NavigationContainer linking={linking}>
      {/* Your navigators */}
    </NavigationContainer>
  );
}
Use the xcrun command to test deep links on iOS:
xcrun simctl openurl booted "myapp://profile/123"

Common Use Cases

Send users a verification link that opens your app and marks their email as verified:
// In your email: myapp://verify?token=abc123

const handleDeepLink = (url: string) => {
  const { path, queryParams } = Linking.parse(url);
  if (path === 'verify' && queryParams?.token) {
    verifyEmail(queryParams.token);
  }
};
Allow users to reset their password from an email link:
// In your email: myapp://reset-password?token=xyz789

const handleDeepLink = (url: string) => {
  const { path, queryParams } = Linking.parse(url);
  if (path === 'reset-password' && queryParams?.token) {
    navigation.navigate('ResetPassword', { token: queryParams.token });
  }
};
Let users share specific content that opens directly in your app:
// Shared link: myapp://post/456

const handleDeepLink = (url: string) => {
  const { path } = Linking.parse(url);
  const match = path?.match(/^post\/(\d+)$/);
  if (match) {
    navigation.navigate('Post', { id: match[1] });
  }
};

Automatic Bundle ID Scheme

Your app’s bundle ID (e.g., dev.a0.apps.myapp) is automatically registered as a URL scheme. This ensures you always have a unique, collision-free scheme available even without explicit configuration.
While the bundle ID scheme works, custom schemes like myapp:// are shorter and more user-friendly for sharing.