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

@humanlabs-kr/link-expo-sdk

v1.7.0

Published

Expo SDK for HumanlabsLink - open-source alternative to Branch.io, AppsFlyer OneLink, and Firebase Dynamic Links. Deferred deep linking, attribution, and smart routing.

Readme

HumanlabsLink Expo SDK

Expo SDK for HumanlabsLink — the open-source alternative to Branch.io, AppsFlyer OneLink, and Firebase Dynamic Links. Add deferred deep linking, mobile attribution, and smart link routing to your Expo app. Self-hosted, privacy-first, no per-click pricing. Pure Expo modules — no native linking required.

npm version License: MIT

Features

  • Deferred deep linking (install attribution) — deterministic on Android (Play Install Referrer) and iOS (clipboard hand-off token, no fingerprinting), with a probabilistic device-fingerprint fallback on Android/web
  • Direct deep linking with server-side URL resolution
  • Event tracking with offline queue (persists across app restarts)
  • Revenue tracking
  • Programmatic link creation
  • Pure Expo modules - no native linking required (expo-device, expo-application, expo-localization, expo-linking; expo-clipboard optional, enables iOS deferred attribution)

Installation

npx expo install @humanlabs-kr/link-expo-sdk expo-device expo-application expo-localization expo-linking @react-native-async-storage/async-storage

expo-clipboard is an optional peer dependency that enables iOS deferred attribution (the clipboard hand-off token). Add it if you ship on iOS:

npx expo install expo-clipboard

Without it, iOS deferred deep links fall back to organic (a one-time warning is logged); Android is unaffected (it uses the Play Install Referrer). The SDK imports expo-clipboard lazily, so its absence never breaks the build.

Quick Start

import HumanlabsLink from '@humanlabs-kr/link-expo-sdk';

// Initialize (call once at app startup)
const response = await HumanlabsLink.initialize({
  baseUrl: 'https://go.yourdomain.com',
  apiKey: 'your-api-key',       // Optional, required for link creation
  appToken: 'at_a1b2c3d4...',   // Recommended for Cloud — enables organic-install attribution
  debug: true,                   // Optional, enables verbose logging
  attributionWindowHours: 168,   // Optional, default 7 days
});

// Check attribution
if (response.attributed) {
  console.log('Install attributed!', response.deepLinkData);
}

// Listen for deferred deep links (new installs)
HumanlabsLink.onDeferredDeepLink((data) => {
  if (data) {
    console.log('Deferred deep link:', data.shortCode);
    // Navigate to content
  }
});

// Listen for direct deep links (existing users)
HumanlabsLink.onDeepLink((url, data) => {
  console.log('Deep link received:', url);
  if (data?.customParameters?.route) {
    // Navigate to route
  }
});

Expo Router: add app/+native-intent.ts (required)

HumanlabsLink links open your app on the path /<app-slug>/<code>, which is not a screen in your app — so Expo Router renders its built-in "Unmatched Route" screen on every link open unless you intercept it. The SDK already resolves the URL and navigates via your onDeepLink / onDeferredDeepLink callback; +native-intent.ts just drops the raw short-link path so Expo Router doesn't claim it first. Don't resolve the short code with your own fetch — the SDK owns resolution.

// app/+native-intent.ts
const APP_SLUG = 'myapp'; // must equal your HumanlabsLink registry slug

export function redirectSystemPath({ path }: { path: string; initial: boolean }) {
  try {
    const firstSegment = path.replace(/^\/+/, '').split(/[/?#]/)[0];
    if (firstSegment === APP_SLUG) return null; // HumanlabsLink short link → SDK routes it
  } catch {}
  return path;
}

Rebuild the app after adding this file — it's build-time native config, not a hot-reloadable JS change.

API Reference

Initialization

await HumanlabsLink.initialize(config);    // Returns InstallAttributionResponse
HumanlabsLink.isInitialized;               // boolean getter

Deep Linking

HumanlabsLink.onDeferredDeepLink(callback); // Deferred (install attribution)
HumanlabsLink.onDeepLink(callback);         // Direct (multiple callbacks supported)
HumanlabsLink.handleDeepLink(url);          // Manual URL pass-through

Event Tracking

await HumanlabsLink.trackEvent(name, properties?);
await HumanlabsLink.trackRevenue(amount, currency, properties?);
await HumanlabsLink.flushEvents();          // Flush offline queue
await HumanlabsLink.clearEventQueue();      // Clear without sending
HumanlabsLink.queuedEventCount;            // Queue size getter

Every tracked event (including auto screen views) is automatically attributed to the deep link that drove the visit using a last-click model — so re-engagement campaigns are credited to the link the user tapped, not their original install link.

Automatic Screen Tracking

Auto-emit a screen_view event on each navigation — no manual per-screen calls — so your dashboard can show an attributed screen-flow funnel per campaign. Opt-in, via React Navigation (an optional peer dependency):

import { createNavigationContainerRef } from '@react-navigation/native';

export const navigationRef = createNavigationContainerRef();

await HumanlabsLink.initialize({
  baseUrl: 'https://go.yourdomain.com',
  autoTrackNavigation: true, // screen names only (privacy-safe default)
  navigationRef,             // also pass this to <NavigationContainer ref={navigationRef}>
});

Route params are OFF by default (they can contain PII). To capture specific non-PII params, opt in with an explicit allow-list:

autoTrackNavigation: { captureParams: ['productId', 'category'] }

Apps that don't use React Navigation simply omit navigationRef — nothing changes and there's no required dependency. Rapid transitions are debounced and same-screen re-renders deduped.

Link Creation

Requires apiKey in config.

const result = await HumanlabsLink.createLink({
  deepLinkParameters: { route: 'PRODUCT', id: '123' },
  title: 'Check out this product',
  utmParameters: { source: 'app', medium: 'share' },
});
console.log(result.url); // https://go.yourdomain.com/tmpl/abc123

Attribution Data

await HumanlabsLink.getInstallId();    // Cached install UUID
await HumanlabsLink.getInstallData();  // Cached DeepLinkData
await HumanlabsLink.isFirstLaunch();   // First launch status

Data Management

await HumanlabsLink.clearData();  // Wipe all stored SDK data
HumanlabsLink.reset();             // Return to uninitialized state

Named Exports

import { HumanlabsLinkSDK, HumanlabsLinkError, HumanlabsLinkErrorCode } from '@humanlabs-kr/link-expo-sdk';
import type {
  HumanlabsLinkConfig,
  DeepLinkData,
  InstallAttributionResponse,
  UTMParameters,
  DeviceFingerprint,
  CreateLinkOptions,
  CreateLinkResult,
  EventRequest,
  AutoTrackNavigationOptions,
  DeferredDeepLinkCallback,
  DeepLinkCallback,
} from '@humanlabs-kr/link-expo-sdk';

Error Handling

All SDK errors are instances of HumanlabsLinkError with a .code property:

| Code | When | |-------------------------|----------------------------------------------------------------| | NOT_INITIALIZED | Method called before initialize() | | ALREADY_INITIALIZED | initialize() called twice | | INVALID_CONFIGURATION | Bad config (HTTP on non-localhost, invalid attribution window) | | NETWORK_ERROR | Network request failed after retries | | INVALID_RESPONSE | Server returned non-2xx response | | DECODING_ERROR | Failed to parse server response | | INVALID_EVENT_DATA | Empty event name or negative revenue | | MISSING_API_KEY | createLink() called without API key |

Offline Resilience

Events that fail to send are automatically queued in AsyncStorage (max 100 events, persists across app restarts). Successfully tracked events trigger a queue flush attempt. You can also manually flush or clear the queue.

Configuration

| Field | Type | Required | Default | Description | |--------------------------|-----------|------------|-----------|-----------------------------------| | baseUrl | string | Yes | - | HumanlabsLink server URL | | apiKey | string | No | - | API key for link creation | | debug | boolean | No | false | Enable verbose logging | | attributionWindowHours | number | No | 168 | Attribution window (1–2160 hours) | | autoTrackNavigation | boolean \| { captureParams?: string[]; debounceMs?: number } | No | false | Auto-emit screen_view from React Navigation (screen names only unless params are allow-listed) | | navigationRef | NavigationContainerRefLike | No | - | React Navigation ref; required when autoTrackNavigation is enabled |

Other SDKs

| Platform | Package | |----------|---------| | React Native | @humanlabs-kr/link-expo-sdk | | iOS (Swift) | HumanlabsLinkSDK | | Android (Kotlin) | HumanlabsLinkSDK |

Contributing

Contributions are welcome! Please open an issue or pull request.

License

MIT License - see LICENSE for details.

Support