The Linking API provides a general interface to interact with both incoming and outgoing app links. You can open URLs in the browser, launch other apps, and handle deep links into your app.
Import
import { Linking } from 'react-native';
Methods
openURL()
Attempts to open a URL with any of the installed apps.
The URL to open. Can be:
- Web URLs:
https://example.com
- Phone numbers:
tel:+1234567890
- SMS:
sms:+1234567890
- Email:
mailto:[email protected]
- App-specific schemes:
myapp://path
Returns: Promise<void> - Resolves when the URL is opened, rejects if no app can handle the URL.
canOpenURL()
Checks if an app is installed that can handle a given URL.
Returns: Promise<boolean> - Resolves to true if the URL can be opened, false otherwise.
iOS: You must add URL schemes to LSApplicationQueriesSchemes in Info.plist or canOpenURL() will always return false for third-party schemes.
getInitialURL()
Returns the URL that launched the app, if any.
Returns: Promise<string | null> - The initial URL, or null if the app wasn’t launched via a link.
addEventListener()
Listens for incoming app links while the app is running.
const subscription = Linking.addEventListener('url', handler);
Callback function that receives an object with a url property.
Returns: EventSubscription - Object with a remove() method to unsubscribe.
openSettings()
Opens the operating system settings for your app.
Returns: Promise<void>
sendIntent() (Android only)
Launches an Android intent with optional extras.
Linking.sendIntent(action, extras);
The Android intent action (e.g., 'android.intent.action.VIEW').
Array of extra data objects with key, value properties.
Returns: Promise<void>
Examples
Opening a Web URL
import React from 'react';
import { Button, Linking, Alert } from 'react-native';
const OpenURLButton = ({ url, children }) => {
const handlePress = async () => {
// Check if the URL can be opened
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
Alert.alert(`Don't know how to open this URL: ${url}`);
}
};
return <Button title={children} onPress={handlePress} />;
};
// Usage
<OpenURLButton url="https://react.dev">
Open React Website
</OpenURLButton>
Making a Phone Call
import { Button, Linking, Platform } from 'react-native';
const CallButton = ({ phoneNumber }) => {
const handlePress = async () => {
const url = `tel:${phoneNumber}`;
const canOpen = await Linking.canOpenURL(url);
if (canOpen) {
await Linking.openURL(url);
}
};
return <Button title="Call" onPress={handlePress} />;
};
// Usage
<CallButton phoneNumber="+1234567890" />
Sending an Email
import { Button, Linking } from 'react-native';
const EmailButton = () => {
const handlePress = async () => {
const email = '[email protected]';
const subject = 'App Feedback';
const body = 'Hello, I have some feedback...';
const url = `mailto:${email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
await Linking.openURL(url);
};
return <Button title="Send Email" onPress={handlePress} />;
};
Sending an SMS
import { Button, Linking, Platform } from 'react-native';
const SMSButton = ({ phoneNumber, message }) => {
const handlePress = async () => {
const separator = Platform.OS === 'ios' ? '&' : '?';
const url = `sms:${phoneNumber}${separator}body=${encodeURIComponent(message)}`;
await Linking.openURL(url);
};
return <Button title="Send SMS" onPress={handlePress} />;
};
// Usage
<SMSButton phoneNumber="+1234567890" message="Hello from React Native!" />
Handling Deep Links
import React, { useEffect } from 'react';
import { Linking, Alert } from 'react-native';
const DeepLinkHandler = () => {
useEffect(() => {
// Handle deep link when app is already open
const subscription = Linking.addEventListener('url', ({ url }) => {
console.log('Received URL:', url);
handleDeepLink(url);
});
// Handle deep link when app is opened from closed state
Linking.getInitialURL().then((url) => {
if (url) {
console.log('Initial URL:', url);
handleDeepLink(url);
}
});
return () => {
subscription.remove();
};
}, []);
const handleDeepLink = (url) => {
// Parse the URL and navigate accordingly
// Example: myapp://profile/123
const route = url.replace(/.*?:\/\//g, '');
const [screen, id] = route.split('/');
Alert.alert('Deep Link', `Navigate to ${screen} with ID: ${id}`);
// Navigate to the appropriate screen
};
return null;
};
Opening App Settings
import React from 'react';
import { Button, Linking } from 'react-native';
const SettingsButton = () => {
const openSettings = async () => {
await Linking.openSettings();
};
return (
<Button
title="Open App Settings"
onPress={openSettings}
/>
);
};
Opening Maps
import { Linking, Platform } from 'react-native';
const openMaps = async (latitude, longitude, label) => {
const scheme = Platform.select({
ios: 'maps:',
android: 'geo:',
});
const url = Platform.select({
ios: `${scheme}${latitude},${longitude}?q=${label}`,
android: `${scheme}${latitude},${longitude}?q=${label}`,
});
await Linking.openURL(url);
};
// Usage
openMaps(37.7749, -122.4194, 'San Francisco');
import { Linking, Alert } from 'react-native';
const openSocialMedia = async (platform, handle) => {
const urls = {
twitter: `twitter://user?screen_name=${handle}`,
twitterWeb: `https://twitter.com/${handle}`,
instagram: `instagram://user?username=${handle}`,
instagramWeb: `https://instagram.com/${handle}`,
facebook: `fb://profile/${handle}`,
facebookWeb: `https://facebook.com/${handle}`,
};
const appUrl = urls[platform];
const webUrl = urls[`${platform}Web`];
try {
const supported = await Linking.canOpenURL(appUrl);
if (supported) {
await Linking.openURL(appUrl);
} else {
await Linking.openURL(webUrl);
}
} catch (error) {
Alert.alert('Error', 'Failed to open link');
}
};
// Usage
openSocialMedia('twitter', 'reactnative');
Android Intent Example
import { Linking, Platform } from 'react-native';
const shareViaIntent = async () => {
if (Platform.OS === 'android') {
await Linking.sendIntent('android.intent.action.SEND', [
{ key: 'android.intent.extra.TEXT', value: 'Check out this app!' },
{ key: 'android.intent.extra.SUBJECT', value: 'App Recommendation' },
]);
}
};
Deep Link Configuration
iOS Setup
Add URL schemes to your Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tel</string>
<string>mailto</string>
<string>maps</string>
</array>
Android Setup
Add intent filters to your AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<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>
Common URL Schemes
| Type | URL Format | Example |
|---|
| HTTP/HTTPS | https:// | https://example.com |
| Phone | tel: | tel:+1234567890 |
| SMS | sms: | sms:+1234567890?body=Hello |
| Email | mailto: | mailto:[email protected] |
| Maps (iOS) | maps: | maps:37.7749,-122.4194?q=SF |
| Maps (Android) | geo: | geo:37.7749,-122.4194?q=SF |
| WhatsApp | whatsapp:// | whatsapp://send?phone=1234567890 |
| Twitter | twitter:// | twitter://user?screen_name=handle |
| Instagram | instagram:// | instagram://user?username=handle |
| Facebook | fb:// | fb://profile/userid |
Best Practices
Always check if a URL can be opened with canOpenURL() before calling openURL() to handle cases where required apps aren’t installed.
Wrap Linking.openURL() calls in try-catch blocks to handle errors gracefully.
On iOS, you must declare URL schemes you want to query in LSApplicationQueriesSchemes in Info.plist, or canOpenURL() will always return false.
Error Handling
const safeOpenURL = async (url) => {
try {
const supported = await Linking.canOpenURL(url);
if (!supported) {
Alert.alert('Error', `Cannot open URL: ${url}`);
return false;
}
await Linking.openURL(url);
return true;
} catch (error) {
Alert.alert('Error', `Failed to open URL: ${error.message}`);
return false;
}
};