Deep Links
Learn how deep links are implemented and how to configure them for your Expo application.
Deep linking allows your app to be opened from a URL, navigating the user directly to a specific page with pre-filled data. In this boilerplate, we use Expo Router which handles deep linking automatically based on your file-based routing structure.
Current Implementation
The boilerplate currently implements deep linking primarily for the Reset Password flow.
1. Project Configuration
The custom scheme is configured in mobile-app/app.config.ts.
{
"expo": {
"scheme": "expolate",
"ios": {
"bundleIdentifier": "com.soewidiputra.expolate.mobile"
},
"android": {
"package": "com.soewidiputra.expolate.mobile"
}
}
}- Scheme:
expolate(This allows you to open the app usingexpolate://) - Bundle/Package: Used for identifying the app on the respective platforms.
2. Deep Link Handling (Expo Router)
Expo Router maps incoming URIs directly to the files in the app directory. For example:
expolate://reset-passwordmaps toapp/(auth)/reset-password.tsxexpolate://settings/appearancemaps toapp/settings/appearance.tsx
The routing group (auth) is ignored in the URL path, allowing for cleaner deep links.
3. Handling Parameters
Pages can receive data from deep links using the useLocalSearchParams hook from expo-router. For example, in app/(auth)/reset-password.tsx:
import { useLocalSearchParams } from 'expo-router';
export default function ResetPasswordScreen() {
// Automatically extracts ?token=... and &email=... from the URL
const params = useLocalSearchParams<{ token: string; email: string }>();
const { token, email } = params;
// Use token and email to verify the reset request with your backend
}4. Universal Links & Android App Links
While Custom Schemes (expolate://) work out of the box, Universal Links (iOS) and App Links (Android) require additional configuration for seamless web-to-app transitions.
Android App Links
To support https://yourdomain.com/reset-password, add intentFilters to the android section in app.json:
"android": {
"intentFilters": [
{
"action": "VIEW",
"data": [
{
"scheme": "https",
"host": "yourdomain.com",
"pathPrefix": "/reset-password"
}
],
"category": ["BROWSABLE", "DEFAULT"]
}
]
}iOS Universal Links
Add associatedDomains to the ios section in app.json:
"ios": {
"associatedDomains": ["applinks:yourdomain.com"]
}Note: Both require hosting verification files (assetlinks.json for Android and apple-app-site-association for iOS) on your web server.
Testing Deep Links
Using Expo CLI (Recommended)
The easiest way to test deep links during development using the uri-scheme tool:
# Test on Android
npx uri-scheme open "expolate://reset-password?token=TEST_TOKEN&email=user@example.com" --android
# Test on iOS
npx uri-scheme open "expolate://reset-password?token=TEST_TOKEN&email=user@example.com" --iosAndroid (ADB)
Simulate a deep link on an Android emulator:
adb shell am start -W -a android.intent.action.VIEW \
-d "expolate://reset-password?token=MY_TOKEN&email=user@example.com" \
com.soewidiputra.expolate.mobileiOS (Simulator)
Test on the iOS simulator:
xcrun simctl openurl booted "expolate://reset-password?token=MY_TOKEN&email=user@example.com"Customizing the Scheme
To change the deep link scheme (e.g., from expolate to myapp):
-
Update the
schemefield inmobile-app/app.config.ts. -
If you are using a Development Build, rebuild your development client:
npx eas build --profile development --platform android -
Ensure your backend (e.g., Laravel) matches this scheme when generating reset links.
