How to Use Custom Deep Links in a React Native Expo App

Mobile applications often need to be accessed quickly using a URL link targeted at the precise app. Deep linking is how this inter-app navigation process is made possible. 

In case you’re unfamiliar, deep linking is an approach that guides a user to specific in-app content in a mobile app by clicking on a custom or universal uniform resource identifier (URI), otherwise known as mobile deep links.

Prefixed at the start of every deep link is a URL scheme that references the protocol used to access the app. The custom URL scheme is distinct to a particular app and serves to locate that app.

In this tutorial, you will use a custom deep link to navigate users into an Expo React Native application. You will configure React navigation with linking options to handle and test deep links and define a route to catch unmatched links into a mobile app.


To complete this tutorial, you will need;

Project setup

For this tutorial, you will build on a sample React Native app created using expo-cli. A stack navigator has been set up using React Navigation.

Ensure you have Git installed on your local machine to clone this project.

The GitHub repository for the app features a main branch that you will clone as well as a complete branch that reflects what your app should look like at the end of this tutorial.

To get started, open your terminal and run the following command to clone the deeplink-guide app:

git clone

If successful, your terminal’s output will be similar to this:

Cloning into 'custom-deep-link-guide'...
remote: Enumerating objects: 112, done.
remote: Counting objects: 100% (112/112), done.
remote: Compressing objects: 100% (98/98), done.
remote: Total 112 (delta 3), reused 112 (delta 3), pack-reused 0
Receiving objects: 100% (112/112), 291.25 KiB | 54.00 KiB/s, done.
Resolving deltas: 100% (3/3), done.

Now, cd into the deeplink-guide app and install the project’s dependencies as defined in the package.json:

npm install

To view the app, run npx expo start and launch it on a simulator, or scan the QR code to launch it on a physical device.

You need to include the expo-linking API module in your project. This API provides utilities that allow a mobile app to create and interact with deep links.

To install the linking API, run this command inside your project directory:

npx expo install expo-linking

Configure React navigation

React navigation can be integrated with Expo’s linking module to manage all incoming deep links. In your cloned project, a native stack navigator has been set up and wrapped in a NavigationContainer using React navigation.

This navigation container takes several parameters, including a linking param housing LinkingOptions. The entire app, located inside the navigation container, will be set up to handle deep links thanks to linking.

A prefixes and config option make up the LinkingOptions. The prefixes is a unique URL scheme that the app will utilize to create deep links.

Inside config is a screens object declaring all the screens the deep link can access.

To configure React navigation to handle deep links, create a prefix variable and assign its value to the createURL() method provided by expo-linking. The prefix will serve as the prefixes linking option.

Import expo-linking into the app.js file and call createURL():

import * as Linking from "expo-linking";

const prefix = Linking.createURL("/");

Linking.createURL() will produce a deep link into your app with optional paths and parameters. For this scenario, pass in a forward slash as the route.

Note: Using a forward slash as the route will open the app’s initial path defined in the stack navigator.

You can log prefixes to your console to see what it looks like.Next, create a linking object to hold the prefixes and config options:

const linking = {
    prefixes: [prefix],
    config: {
      screens: {
        Home: "home",
        Settings: "settings",

You have defined a Home screen and Settings screen inside the screens object.createURL() will use the declared path strings to match the screen name and create a deep link.

Ensure the screen names are identical to those given inside the navigation container’s stack.screen.

Lastly, declare linking={linking} in the navigation container:

<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>

Deep linking into your app

Congratulations! Your app is now ready to test deep links. 

At this stage, the deeplink-guide app is still running on the Expo network. When running a mobile app with the Expo Go app, you essentially run the build on the Expo LAN. 

If you pay attention to the terminal running your app, you will notice an address similar to exp:// with the Expo scheme prefixed at the start.

This address is essentially a deep link and will open the Expo Go app if searched in a mobile browser.

To test deep linking into your Expo Go app, run this command:

npx uri-scheme open exp:// --ios

You will be navigated into the settings screen in the app.

Be sure to use your app’s personal expo address and specify the platform flag the app is running on.Your app may display a warning error for failing to include a custom scheme for your standalone app. The above command will run regardless of this warning. You will include this custom scheme in your app.json file in the coming steps.

Adding a custom scheme

You must build a standalone app to use a custom scheme for your app’s deep links. You can build this standalone app locally with Xcode or Android Studio.

Install expo-dev-client and expo-updates beforehand, as you will need them to build a standalone app:

npx expo install expo-dev-client expo-updates

After installing the dependencies, be sure to specify a bundle identifier and custom scheme inside app.json:

  "expo": {
    "scheme": "deeplinkguide"
  "ios": {
    "bundleIdentifier": "deeplinkguide"

You can follow the official Expo Docs for up-to-date instructions on how to build, install, and launch your standalone app on a simulator. Once you do so, run the following command in your terminal to test the custom deep link with your standalone app:

npx uri-scheme open deeplinkguide://settings --ios

You will be navigated into the settings screen in the app.

Catching unmatched routes

In cases where a user tries to access a screen with an invalid link that does not match any route within the app, it would be appropriate to redirect them to a screen showing an error. 

Web pages usually handle this by showing a 404 error, an HTTP error indicating that the browser successfully connected to a server but could not find the requested page. We can configure React navigation to behave similarly by redirecting users to a route for invalid deep links.To redirect a user to an error screen, define a catch-all route inside the screens config object:

const linking = {
    prefixes: [prefix],
    config: {
      screens: {
        Home: 'home',
        Settings: 'settings',
        NotFound: '*',

The asterisk marker represents all paths not matching the screens defined. Users will be navigated to the NotFound screen if they attempt to access a screen that does not exist with a deep link.

Note: You must create the NotFound screen and add it to the native stack navigator.


In this tutorial, you learned what deep links are and how to configure React navigation to handle incoming deep links in a mobile app. You also tested custom deep links while developing with the Expo Go app and on a standalone app built using EAS. Additionally, you set configurations to handle unmatched deep links by navigating users to an error screen.

Deep links are handy for driving up user engagement on a mobile application. They create a more satisfactory experience on the client side by funneling navigation in a smooth and targeted manner. Utilizing deep links with your mobile application is an excellent practice for a better user experience. If you’re interested in learning more about how to implement new technologies, develop new features, or otherwise improve the performance of your application, browse the Mattermost Library and continue your learning.

This blog post was created as part of the Mattermost Community Writing Program and is published under the CC BY-NC-SA 4.0 license. To learn more about the Mattermost Community Writing Program, check this out.