New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@layers/react-native

Package Overview
Dependencies
Maintainers
4
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@layers/react-native

Layers Analytics React Native SDK — thin wrapper over Rust core via WASM

latest
Source
npmnpm
Version
2.2.0
Version published
Weekly downloads
214
-62.06%
Maintainers
4
Weekly downloads
 
Created
Source

Layers React Native SDK

@layers/react-native is the Layers analytics SDK for React Native apps. It provides event tracking, screen tracking, user identification, App Tracking Transparency (ATT), SKAdNetwork (SKAN), deep link handling, clipboard-based deferred deep links, consent management, and automatic lifecycle and connectivity handling.

Use this package for bare React Native projects. For Expo managed workflow projects, use @layers/expo instead.

Requirements

  • React Native 0.70.0+
  • React 18.0+
  • iOS 14.0+ / Android API 21+

Installation

npm install @layers/react-native
# or
yarn add @layers/react-native
npm install @react-native-async-storage/async-storage @react-native-community/netinfo

These are optional but strongly recommended:

  • @react-native-async-storage/async-storage (>=1.21.0) -- Enables persistent event storage across app restarts. Without it, events are stored in memory only.
  • @react-native-community/netinfo (>=11.0.0) -- Enables automatic flush when the device reconnects to the network.
  • @react-native-clipboard/clipboard (>=1.13.0) -- Enables clipboard attribution for iOS deferred deep links.

iOS Setup

cd ios && pod install

Add NSUserTrackingUsageDescription to your Info.plist if you plan to use ATT.

Quick Start

import { LayersReactNative } from '@layers/react-native';

// Create and initialize
const layers = new LayersReactNative({
  appId: 'your-app-id',
  environment: 'production'
});
await layers.init();

// Track events
layers.track('button_tapped', { button_name: 'signup' });

// Track screen views
layers.screen('Home');

// Identify users
layers.setAppUserId('user_123');

Configuration

LayersRNConfig

interface LayersRNConfig {
  appId: string;
  environment: 'development' | 'staging' | 'production';
  appUserId?: string;
  enableDebug?: boolean; // default: false
  baseUrl?: string; // default: "https://in.layers.com"
  flushIntervalMs?: number; // default: 30000
  flushThreshold?: number; // default: 10
  maxQueueSize?: number; // default: 1000
  autoTrackAppOpen?: boolean; // default: true
  autoTrackDeepLinks?: boolean; // default: true
}
OptionTypeDefaultDescription
appIdstringrequiredYour Layers application identifier.
environmentEnvironmentrequired'development', 'staging', or 'production'.
appUserIdstringundefinedOptional user ID to set at construction time.
enableDebugbooleanfalseEnable verbose console logging.
baseUrlstring"https://in.layers.com"Custom ingest API endpoint.
flushIntervalMsnumber30000Automatic flush interval in milliseconds.
flushThresholdnumber10Queue size that triggers an automatic flush.
maxQueueSizenumber1000Maximum events in the queue before dropping.
autoTrackAppOpenbooleantrueAutomatically track app_open on init.
autoTrackDeepLinksbooleantrueAutomatically track deep_link_opened events.

Core API

Constructor & Initialization

const layers = new LayersReactNative(config: LayersRNConfig);
await layers.init();

The constructor creates the SDK instance with an in-memory queue. Calling init() upgrades to AsyncStorage-backed persistence, collects device info, fetches remote config, reads clipboard attribution (iOS), fires app_open, and sets up auto-tracking.

You can call track() and screen() before init() completes -- events are queued in memory.

Event Tracking

track(eventName: string, properties?: EventProperties): void
layers.track('purchase_completed', {
  product_id: 'sku_123',
  price: 9.99,
  currency: 'USD'
});

Screen Tracking

screen(screenName: string, properties?: EventProperties): void
layers.screen('ProductDetail', { product_id: 'sku_123' });

User Identity

// Set the app user ID (set-user-once: ignored if already set)
setAppUserId(appUserId: string): void

// Clear the current user ID (allows setting a new one)
clearAppUserId(): void

// Get the current user ID
getAppUserId(): string | undefined

// Set user properties
async setUserProperties(properties: UserProperties): Promise<void>
// After login
layers.setAppUserId('user_123');
await layers.setUserProperties({
  email: 'user@example.com',
  plan: 'premium'
});

// On logout
layers.clearAppUserId();

Set-user-once semantics: Once setAppUserId() is called, subsequent calls are ignored until clearAppUserId() is called. This prevents accidental user ID changes.

async setConsent(consent: ConsentState): Promise<void>
getConsentState(): ConsentState
interface ConsentState {
  analytics?: boolean;
  advertising?: boolean;
}
// User accepts all tracking
await layers.setConsent({ analytics: true, advertising: true });

// User denies advertising
await layers.setConsent({ analytics: true, advertising: false });

// Read current consent
const consent = layers.getConsentState();

Flush & Shutdown

// Flush queued events to the server
async flush(): Promise<void>

// Shut down the SDK (removes listeners, stops timers)
shutdown(): void

Session & Device

// Get the current session ID
getSessionId(): string

// Override device context fields
setDeviceInfo(deviceInfo: DeviceContext): void

Error Handling

// Register an error listener
on(event: 'error', listener: (error: Error) => void): this

// Remove an error listener
off(event: 'error', listener: (error: Error) => void): this
layers.on('error', (error) => {
  console.error('Layers error:', error.message);
  // Forward to your crash reporting service
});

App Tracking Transparency (ATT) -- iOS

The requestTrackingPermission() method on the SDK instance handles the full ATT flow:

const status = await layers.requestTrackingPermission();
// Returns: 'authorized' | 'denied' | 'restricted' | 'not_determined'

This method automatically:

  • Shows the ATT dialog (or uses expo-tracking-transparency if available)
  • Collects IDFA if authorized
  • Updates device context with IDFA and ATT status
  • Sets advertising consent based on the result

Standalone ATT Functions

For more granular control, use the exported functions:

import {
  getATTStatus,
  getAdvertisingId,
  getVendorId,
  isATTAvailable,
  requestTrackingAuthorization
} from '@layers/react-native';

const status = await getATTStatus();
const isAvailable = await isATTAvailable();
const idfa = await getAdvertisingId(); // null if not authorized
const idfv = await getVendorId(); // always available on iOS

ATTStatus

type ATTStatus = 'not_determined' | 'restricted' | 'denied' | 'authorized';

Important: Add NSUserTrackingUsageDescription to your Info.plist.

SKAdNetwork (SKAN) -- iOS

SKAN is auto-configured from the server's remote config. The SDK creates a SKANManager instance and automatically forwards every track() call through the SKAN rule engine.

Accessing the Auto-Configured Manager

const skanManager = layers.getSkanManager();
if (skanManager) {
  const metrics = skanManager.getMetrics();
  console.log('SKAN value:', metrics.currentValue);
  console.log('SKAN preset:', metrics.currentPreset);
}

Manual SKAN Configuration

If you need to configure SKAN manually instead of relying on remote config:

import { SKANManager } from '@layers/react-native';

const skan = new SKANManager((data) => {
  console.log(`Conversion value updated: ${data.previousValue} -> ${data.newValue}`);
});

// Use a built-in preset
skan.setPreset('subscriptions'); // or 'engagement' or 'iap'
await skan.initialize();

// Or define custom rules
skan.setCustomRules([
  {
    eventName: 'purchase_success',
    conditions: { revenue: { '>=': 10 } },
    conversionValue: 63,
    coarseValue: 'high',
    priority: 10
  },
  {
    eventName: 'trial_start',
    conversionValue: 20,
    priority: 5
  }
]);
await skan.initialize();

// Process events manually
await skan.processEvent('purchase_success', { revenue: 49.99 });

SKANConversionRule

interface SKANConversionRule {
  eventName: string;
  conditions?: Record<string, unknown>; // Operator-based: { '>': 10, '<': 100 }
  conversionValue: number; // 0-63 (SKAN 3.0) or 0-7 (SKAN 4.0)
  coarseValue?: 'low' | 'medium' | 'high'; // SKAN 4.0 only
  lockWindow?: boolean; // SKAN 4.0 only
  priority?: number;
  description?: string;
}

SKANMetrics

interface SKANMetrics {
  isSupported: boolean;
  version: string;
  currentValue: number | null;
  currentPreset: string | null;
  ruleCount: number;
  evaluationCount: number;
}

Available Presets

  • subscriptions -- Optimized for subscription apps (trial start, subscription start/renew)
  • engagement -- Optimized for engagement-driven apps (content views, sessions, bookmarks)
  • iap -- Optimized for in-app purchase revenue tracking (purchase tiers by revenue)

Auto-Tracking (Default)

When autoTrackDeepLinks is true (default), the SDK automatically tracks a deep_link_opened event for every incoming deep link. The event includes the full URL, scheme, host, path, and all query parameters (UTM, click IDs) as flat top-level properties.

import { parseDeepLink, setupDeepLinkListener } from '@layers/react-native';

const unsubscribe = setupDeepLinkListener((data) => {
  console.log('Deep link:', data.url);
  console.log('Host:', data.host);
  console.log('Path:', data.path);
  console.log('UTM Source:', data.queryParams.utm_source);
  console.log('Click ID:', data.queryParams.fbclid);
});

// Later: unsubscribe()

The listener handles both:

  • Initial URL (cold start): Checks Linking.getInitialURL() on setup.
  • Subsequent URLs (warm start): Listens to Linking url events.
function parseDeepLink(url: string): DeepLinkData | null;
interface DeepLinkData {
  url: string;
  scheme: string;
  host: string;
  path: string;
  queryParams: Record<string, string>;
  timestamp: number;
}

Clipboard Attribution -- iOS

On iOS, the SDK reads the clipboard on first launch (during init()) for a Layers click URL. If found, the click URL and click ID are included as properties on the app_open event. This is controlled by the server's remote config (clipboard_attribution_enabled).

For manual reading:

import { readClipboardAttribution } from '@layers/react-native';

const data = await readClipboardAttribution();
if (data) {
  console.log('Click URL:', data.clickUrl);
  console.log('Click ID:', data.clickId);
}
interface ClipboardAttribution {
  clickUrl: string;
  clickId: string;
}

Requires @react-native-clipboard/clipboard as a peer dependency.

Expo Router Integration

For automatic screen tracking with Expo Router:

import { useLayersExpoRouterTracking } from '@layers/react-native';
import { usePathname, useGlobalSearchParams } from 'expo-router';

function RootLayout() {
  useLayersExpoRouterTracking(layers, usePathname, useGlobalSearchParams);

  return <Stack />;
}

This hook automatically tracks a screen event every time the Expo Router pathname changes, including route parameters as event properties.

Install ID

The SDK generates and persists a unique install ID via AsyncStorage:

import { getOrSetInstallId } from '@layers/react-native';

const installId = await getOrSetInstallId();

This ID persists across app sessions and is included in the device context.

Automatic Behaviors

  • app_open event: Tracked on init() with clipboard attribution (iOS).
  • deep_link_opened event: Tracked automatically for all incoming deep links.
  • Background flush: Events are flushed when the app goes to background/inactive.
  • Foreground flush: Events are flushed when the app becomes active.
  • Network reconnect flush: Events are flushed when the device reconnects (requires @react-native-community/netinfo).
  • Periodic flush: Events are flushed on a timer (configurable).
  • Remote config: Server configuration is fetched during init.
  • SKAN auto-config: SKAN preset/rules from remote config are applied automatically (iOS).
  • Device context: Platform, OS version, device model, locale, screen size, timezone, IDFV (iOS), and install ID are collected automatically.
  • Event persistence: Events are persisted via AsyncStorage (if available) and rehydrated on restart.

TypeScript Types

All types are exported from the package:

import type {
  ATTStatus,
  ClipboardAttribution,
  ConsentState,
  DeepLinkData,
  DeviceContext,
  Environment,
  ErrorListener,
  EventProperties,
  LayersRNConfig,
  SKANConversionRule,
  SKANMetrics,
  SKANPresetConfig,
  UserProperties
} from '@layers/react-native';

Keywords

react-native

FAQs

Package last updated on 03 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts