npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@smler/deferred-link

v1.0.0

Published

Lightweight React Native plugin enabling Android Install Referrer & iOS clipboard deferred deep linking to land users on exact screens.

Readme

React Native Deferred Deep Link

npm version

A powerful yet lightweight React Native plugin for deferred deep linking built for real production apps. It helps you extract referral information and deep link parameters on both Android and iOS without heavy attribution SDKs. Full TypeScript support included.

This is the React Native equivalent of the Flutter smler_deferred_link package, with 1:1 feature parity.

📌 What Is Deferred Deep Linking?

Deferred deep linking allows your user to install your app after clicking a link, and still land on the correct screen or carry referral metadata after install.

📘 How It Works

If the user has not installed the app and they click a deep link, it will first open in the phone's default browser. From the browser, the system automatically detects the platform and redirects to the respective store:

Android → Google Play Store

iOS → Apple App Store

After installation and first app launch, the app reads the deferred deep-link parameters and navigates to the exact intended screen.

Platform Behavior

Android

Uses the Google Play Install Referrer API (officially supported by Google). Reads details from:

https://play.google.com/store/apps/details?id=<package>&referrer=<encoded_params>

From the referrer parameter, we decode and route the user to the correct screen.

iOS

Uses a clipboard deep link fallback that works even under iCloud+ Private Relay:

✔ The deep link is copied to the clipboard
✔ When the app is opened the first time, we read the clipboard
✔ If the link matches your allowed domains, we extract parameters and navigate

Installation

npm install react-native-smler-deferred-link
# or
yarn add react-native-smler-deferred-link

iOS

cd ios && pod install

Android

No additional setup needed. The Google Play Install Referrer library is bundled automatically.

Peer Dependencies (optional)

For probabilistic matching (device fingerprint fallback), install:

npm install react-native-device-info

For iOS clipboard access (required for iOS deferred deep linking):

React Native's built-in Clipboard is used by default. For newer React Native versions where it has been extracted, install:

npm install @react-native-clipboard/clipboard

Quick Start

1. Android — Install Referrer

import { SmlerDeferredLink } from 'react-native-smler-deferred-link';

try {
  const info = await SmlerDeferredLink.getInstallReferrerAndroid();
  console.log('Raw referrer:', info.installReferrer);

  // Parse as query parameters
  const params = SmlerDeferredLink.parseReferrerParams(info);
  console.log('utm_source:', params.utm_source);
  console.log('utm_campaign:', params.utm_campaign);

  // Get a single param
  const uid = SmlerDeferredLink.getReferrerParam(info, 'uid');

  // Extract shortCode and dltHeader
  const { shortCode, dltHeader } =
    SmlerDeferredLink.extractShortCodeAndDltHeader(info);

  // Track click (automatic — reads clickId from referrer)
  const tracking = await SmlerDeferredLink.trackClick(info);
  if (tracking) console.log('Tracking response:', tracking);
} catch (e) {
  console.error(e);
}

ReferrerInfo fields:

| Field | Type | Description | |---|---|---| | installReferrer | string \| null | Raw referrer string from Google Play | | referrerClickTimestampSeconds | number | Client-side click timestamp (seconds) | | installBeginTimestampSeconds | number | Client-side install-begin timestamp (seconds) | | referrerClickTimestampServerSeconds | number | Server-side click timestamp (seconds) | | installBeginTimestampServerSeconds | number | Server-side install-begin timestamp (seconds) | | installVersion | string \| null | App version at first install | | googlePlayInstantParam | boolean | Whether instant experience launched in last 7 days |


2. iOS — Clipboard Deep Link

import { SmlerDeferredLink } from 'react-native-smler-deferred-link';

try {
  const result = await SmlerDeferredLink.getInstallReferrerIos({
    deepLinks: [
      'https://example.com/profile',
      'http://example.com/profile',
      'example.com/profile',
      'example.com',                  // base domain only
      '*.example.com/profile/*',      // wildcard subdomain + path
    ],
  });

  if (result) {
    console.log('Deep link:', result.fullDeepLink);
    console.log('Params:', result.queryParameters);
    console.log('referrer:', result.queryParameters.referrer);
    console.log('Short code:', result.pathParams.shortCode);
  } else {
    console.log('No matching deep link in clipboard');
  }
} catch (e) {
  console.error(e);
}

IosClipboardDeepLinkResult fields:

| Field | Type | Description | |---|---|---| | fullDeepLink | string | Full clipboard text matched | | fullReferralDeepLinkPath | string | Alias for fullDeepLink | | queryParameters | Record<string, string> | Parsed ?key=value pairs | | pathParams | PathParams | Extracted shortCode and dltHeader |

Pattern matching rules:

  • Supports http://, https://, and schemeless patterns
  • Strips www. for comparison
  • Matches any subdomain: sub.example.com matches pattern example.com
  • Wildcard host: *.example.com
  • Wildcard path: example.com/*, example.com/profile/*
  • Global wildcard: * matches any parseable URL

3. Runtime Deep Links: resolveDeepLink()

When a user opens a deep link while the app is already installed, call this to resolve the short link and retrieve its full metadata.

import { Linking } from 'react-native';
import { SmlerDeferredLink } from 'react-native-smler-deferred-link';

Linking.addEventListener('url', async (event) => {
  try {
    const data = await SmlerDeferredLink.resolveDeepLink(event.url);
    console.log('shortCode:', data.shortCode);
    console.log('domain:', data.domain);
    console.log('originalUrl:', data.originalUrl);
  } catch (e) {
    console.error('Error resolving link:', e);
  }
});

Pass triggerWebhook: true to instruct the Smler backend to fire the configured webhook automatically in the same request — no second API call needed:

const data = await SmlerDeferredLink.resolveDeepLink(url, {
  triggerWebhook: true,
});

Parameters:

  • url (string): The full deep link URL that was opened
  • options.triggerWebhook (boolean, optional): When true, triggers the webhook server-side

Returns: ResolvedDeepLinkData with:

  • shortCode (string): The short URL code
  • domain (string): The domain the link belongs to
  • dltHeader (string?): Optional campaign/category header
  • originalUrl (string?): The original destination URL

4. Webhook Notification: triggerWebhook()

Call this after resolveDeepLink() to notify the Smler backend that the link was opened.

Tip: You can skip this separate call by passing triggerWebhook: true directly to resolveDeepLink() (see above).

import { HelperReferrer } from 'react-native-smler-deferred-link';

const data = await SmlerDeferredLink.resolveDeepLink(deepLinkUrl);

if (data.shortCode && data.domain) {
  await HelperReferrer.triggerWebhook({
    shortCode: data.shortCode,
    domain: data.domain,
    dltHeader: data.dltHeader,
  });
}

Parameters:

  • shortCode (required): Short code from the resolved link
  • domain (required): Domain from the resolved link
  • dltHeader (optional): Campaign header, if present

Returns: WebhookResponse{ success: true } on success, or an error object.


📊 Probabilistic Matching (Advanced Attribution)

Probabilistic matching enables accurate install attribution by analyzing device fingerprints when traditional methods fail. Particularly useful for iOS when clipboard matching fails.

When to Use

iOS Fallback: When getInstallReferrerIos() returns null
Cross-Platform Validation: Confirm attribution on both platforms
Enhanced Attribution: Get additional click metadata

Usage

import { HelperReferrer } from 'react-native-smler-deferred-link';

const result = await HelperReferrer.getProbabilisticMatch({
  domain: 'example.com',
  clickId: 'optional-click-id', // optional
});

if (result.matched) {
  console.log('Score:', result.score);
  console.log('Short code:', result.pathParams?.shortCode);
  console.log('Domain:', result.pathParams?.domain);
}

Returns: ProbabilisticMatchResult with:

  • matched (boolean): Whether a match was found
  • score (number | null): Confidence score (0.0 – 1.0)
  • matchedAttributes: Attributes that matched
  • clickDetails: Details of the matched click
  • shortUrl: Complete short URL object with metadata
  • fingerprint: Device fingerprint data
  • pathParams: { shortCode, dltHeader, domain } if matched

Note: Requires react-native-device-info to be installed for automatic device/OS detection. Falls back to 'Unknown' if not available.


Recommended First-Install Flow

import AsyncStorage from '@react-native-async-storage/async-storage';
import { Platform } from 'react-native';
import {
  SmlerDeferredLink,
  HelperReferrer,
} from 'react-native-smler-deferred-link';

async function runDeferredAttribution() {
  const isFirstInstall = await AsyncStorage.getItem('smler_first_install');
  if (isFirstInstall !== null) return; // Already ran

  if (Platform.OS === 'android') {
    const info = await SmlerDeferredLink.getInstallReferrerAndroid();
    const params = SmlerDeferredLink.parseReferrerParams(info);
    // Route based on params.utm_campaign, etc.
  } else if (Platform.OS === 'ios') {
    const result = await SmlerDeferredLink.getInstallReferrerIos({
      deepLinks: ['https://yourdomain.com', 'yourdomain.com'],
    });

    if (result) {
      // Clipboard match found — resolve it
      const data = await SmlerDeferredLink.resolveDeepLink(
        result.fullDeepLink,
        { triggerWebhook: true }
      );
      // Route to screen based on data
    } else {
      // Fallback to probabilistic matching
      const match = await HelperReferrer.getProbabilisticMatch({
        domain: 'yourdomain.com',
      });
      if (match.matched && (match.score ?? 0) > 0.65) {
        // High confidence match — route based on match.pathParams
      }
    }
  }

  await AsyncStorage.setItem('smler_first_install', 'done');
}

Backend Support (Important)

You must handle one small backend/website step: When a user clicks a deep link, your web page should redirect them to the appropriate store.

Android:

https://play.google.com/store/apps/details?id=<package>&referrer=<URL-encoded referrer>

iOS:

Copy the deep link to the clipboard, then redirect to the App Store:

// On your landing page
navigator.clipboard.writeText(window.location.href);
window.location.href = 'https://apps.apple.com/app/id<YOUR_APP_ID>';

API Reference

SmlerDeferredLink

| Method | Platform | Description | |---|---|---| | getInstallReferrerAndroid() | Android | Read Google Play Install Referrer | | parseReferrerParams(info) | Android | Parse referrer string as query params | | getReferrerParam(info, key) | Android | Get a single referrer param | | extractShortCodeAndDltHeader(info) | Android | Extract shortCode/dltHeader from referrer URL | | trackClick(info) | Android | Track click via referrer's clickId | | getInstallReferrerIos(options) | iOS | Read clipboard and match against deep link patterns | | resolveDeepLink(url, options?) | Both | Resolve a deep link URL via Smler API |

HelperReferrer

| Method | Description | |---|---| | matchesDeepLinkPattern(clipboard, pattern) | Check if a URL matches a deep link pattern | | fetchTrackingData(clickId, pathParams, domain?) | Fetch tracking data from Smler API | | getProbabilisticMatch(options) | Probabilistic install attribution | | resolveDeepLinkData(url, options?) | Resolve deep link URL | | triggerWebhook(options) | Trigger webhook notification | | extractShortCodeAndDltHeader(url) | Extract shortCode/dltHeader from URL | | parseReferrerAsQueryParams(referrer) | Parse referrer string as params |


TypeScript Types

All types are exported from the package:

import type {
  ReferrerInfo,
  IosClipboardDeepLinkResult,
  ProbabilisticMatchResult,
  TrackingResponse,
  WebhookResponse,
  ResolvedDeepLinkData,
  PathParams,
} from 'react-native-smler-deferred-link';

License

MIT © Bokimo Technologies LLP