@codlynk/react-native
v1.1.0
Published
CodLynk deep linking for React Native: Universal Links / App Links, deferred deep links and React Navigation integration.
Maintainers
Readme
@codlynk/react-native
Deep links for React Native apps using CodLynk short links and QR codes:
- App installed: the link or QR code opens the app at the right screen (iOS Universal Links / Android App Links).
- App not installed: the user goes to the App Store or Play Store. On first launch the app receives the link that was clicked before installing (deferred deep link).
- React Navigation: navigation is driven by the
pathconfigured on the link.
Requirements
- React Native 0.72+ with Expo Modules: an Expo app (SDK 50+, dev build /
expo prebuild) or a bare app that rannpx install-expo-modules. - Expo Go is not supported. Deep links still resolve there, but deferred deep linking needs the native module.
- An app registered in the CodLynk dashboard (Apps) on its own domain, for example
go.acme.com. Registering the app gives you theapiKey(clk_pk_...).
Installation
npm install @codlynk/react-nativeExpo (app.json / app.config.js)
{
"expo": {
"plugins": [["@codlynk/react-native", { "domains": ["go.acme.com"] }]]
}
}The plugin adds:
- iOS: the
applinks:go.acme.comentitlement (Associated Domains). - Android: an
autoVerifyintent filter forhttps://go.acme.comon the main activity.
| Plugin option | Type | Default | Description |
|---|---|---|---|
| domains | string[] | required | Short-link domains registered for this app in CodLynk. |
| webCredentials | boolean | false | Also adds webcredentials:{domain} on iOS, so passkeys and saved passwords (e.g. react-native-passkey) work with these domains. Enable "Login with saved credentials" for the app in CodLynk too, which publishes webcredentials in the AASA and get_login_creds in assetlinks.json. Android needs no manifest change. |
After adding it, run npx expo prebuild or a new dev build.
Bare React Native
Add the same configuration by hand:
- iOS: under Signing & Capabilities, enable Associated Domains and add
applinks:go.acme.com(andwebcredentials:go.acme.comfor passkeys and saved passwords). - Android: add to
AndroidManifest.xml:<intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" android:host="go.acme.com" /> </intent-filter>
Then run cd ios && pod install.
Usage
import { NavigationContainer } from '@react-navigation/native';
import Codlynk, { createCodlynkLinking } from '@codlynk/react-native';
Codlynk.init({
apiKey: 'clk_pk_xxxxxxxx',
domains: ['go.acme.com'],
appVersion: '1.4.0',
});
const linking = createCodlynkLinking({
prefixes: ['acme://'], // your own prefixes keep working
config: {
screens: {
Home: '',
Product: 'produto/:id', // link path "/produto/123" -> Product { id: "123" }
},
},
});
export default function App() {
return <NavigationContainer linking={linking}>{/* ... */}</NavigationContainer>;
}Reading the link's data
// Launch link (direct or deferred). Resolved once per launch.
const link = await Codlynk.getInitialDeepLink();
link?.data?.promo; // "10off"
// Links opened while the app is running
const unsubscribe = Codlynk.onDeepLink((link) => {
analytics.track('deep_link', { path: link.path, deferred: link.isDeferred });
});
// Most recent link, e.g. on the screen you navigated to
Codlynk.getLatestDeepLink();
// A link that arrived some other way (push notification, QR scanner inside the app)
await Codlynk.handleUrl('https://go.acme.com/abc123');CodlynkLink:
| Field | Description |
|---|---|
| matched | true when the link belongs to this app |
| path / data | In-app route and payload configured on the link |
| isDeferred | true when it came from the install (link clicked before installing) |
| matchType | Direct, InstallReferrer, Clipboard, Probabilistic |
| confidence | 1 for deterministic matches; 0–0.95 for Probabilistic |
| originalUrl, shortUrl, urlId | Link metadata |
Options
| Option | Default | Description |
|---|---|---|
| apiKey | — | Publishable key (clk_pk_...). Can be embedded in the app. |
| domains | — | CodLynk domains of this app. |
| baseUrl | https://{domains[0]} | API URL. |
| appVersion | — | Reported in analytics. |
| iosClipboard | true | Reads the click token from the clipboard on the first launch on iOS. |
| minConfidence | 0.8 | Minimum confidence to accept a probabilistic match. |
| openUnmatchedInBrowser | true | Plain links on your domain open in the browser. |
| timeoutMs | 5000 | Network timeout. |
| debug | false | Logs to the console. |
How deferred deep links work
| Platform | Method | Accuracy |
|---|---|---|
| Android | Play Install Referrer (referrer on the store URL) | Deterministic |
| iOS | Clipboard: the "Download on the App Store" button copies a token, which the SDK reads on first launch | Deterministic when the user allows paste |
| iOS (optional) | Probabilistic: IP + iOS version + screen/language/timezone within a time window. Enabled per app in the dashboard | Hint only; check confidence |
iOS clipboard: the SDK only reads the clipboard when iOS reports that it holds a URL (
UIPasteboard.detectPatterns, which shows no prompt). If it does, iOS 16+ shows "Allow Paste" once. Turn it off withiosClipboard: false.Probabilistic mode: off by default. It relies on device signals and may conflict with App Store rule 5.1.2 (fingerprinting) and the LGPD. Evaluate it with your legal team before enabling it.
Troubleshooting
- The link opens the browser instead of the app:
- Check that
https://go.acme.com/.well-known/apple-app-site-associationand/.well-known/assetlinks.jsonreturn 200. - Apple's validator:
https://app-site-association.cdn-apple.com/a/v1/go.acme.com. - Android:
adb shell pm get-app-links <package>.
- Check that
- iOS: Universal Links do not open from a link typed in Safari's address bar, nor from a link inside the same domain. This is iOS behavior.
- Deferred deep links only happen on the first launch after install. To test again, uninstall the app and click the link again.
