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

Source
npmnpm
Version
1.1.0
Version published
Weekly downloads
64
-69.52%
Maintainers
4
Weekly downloads
 
Created
Source

@layers/react-native

React Native SDK for Layers Analytics with ATT, SKAN, deep link support, and offline queueing.

Install

npm install @layers/react-native
# or
pnpm add @layers/react-native

Peer Dependencies

PackageRequiredWhat degrades without it
reactYes--
react-nativeYes--
@react-native-async-storage/async-storageOptionalEvents are only persisted in memory; lost on app kill
@react-native-community/netinfoOptionalSDK assumes always-online; no offline queueing
npm install @react-native-async-storage/async-storage @react-native-community/netinfo

Quick Start

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

const layers = new LayersReactNative({
  apiKey: 'your-api-key',
  appId: 'your-app-id',
  environment: 'production',
  enableDebug: __DEV__
});

await layers.init();

// Track events
await layers.track('app_open', { source: 'push_notification' });

// Track screens
await layers.screen('home');

// Identify a user
layers.setAppUserId('user-123');

Configuration

All fields for LayersRNConfig:

FieldTypeDefaultDescription
apiKeystringrequiredAPI key from the Layers dashboard
appIdstringrequiredApplication identifier
environment'development' | 'staging' | 'production'requiredDeployment environment
appUserIdstringundefinedPre-set user ID at init time
enableDebugbooleanfalseVerbose console logging
baseUrlstringhttps://in.layers.comOverride the ingest endpoint
flushIntervalMsnumber30000Periodic flush interval (ms)
flushThresholdnumber20Queue depth that triggers auto-flush
maxQueueSizenumber10000Max events in queue before dropping

User Identity

The SDK uses set-user-once semantics. Once setAppUserId() is called, subsequent calls are ignored until clearAppUserId() is called:

layers.setAppUserId('user-123'); // sets the user ID
layers.setAppUserId('user-456'); // ignored (already set)
layers.clearAppUserId(); // clears it
layers.setAppUserId('user-456'); // now sets to user-456

ATT (App Tracking Transparency)

iOS 14.5+ requires asking for tracking permission before accessing IDFA.

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

// Check if ATT is available on this device
const available = await isATTAvailable();

// Request permission (shows the system dialog)
const status = await requestTrackingAuthorization();
// Returns: 'authorized' | 'denied' | 'restricted' | 'not_determined'

// Check current status without prompting
const currentStatus = await getATTStatus();

// Get IDFA (only returns a value when status is 'authorized')
const idfa = await getAdvertisingId();

// Get IDFV (always available, does not require ATT)
const idfv = await getVendorId();

// Wire ATT status into consent
if (status === 'authorized') {
  await layers.setConsent({ analytics: true, advertising: true });
} else {
  await layers.setConsent({ analytics: true, advertising: false });
}

ATT functions require the native LayersATT module. On Android or when the native module is not linked, they return safe defaults ('not_determined', null, false).

SKAN (SKAdNetwork)

Manage iOS SKAdNetwork conversion values with a rule-based engine:

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

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

await skan.initialize();

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

// Or define custom rules
skan.setCustomRules([
  { eventName: 'app_open', conversionValue: 1, priority: 1 },
  { eventName: 'trial_start', conversionValue: 20, priority: 5 },
  { eventName: 'subscription_start', conversionValue: 50, priority: 10 }
]);

// Call processEvent for each analytics event to evaluate rules
await skan.processEvent('trial_start', { plan: 'premium' });

// Check current state
console.log(skan.getCurrentValue()); // 20
console.log(skan.getMetrics());

SKAN requires the native LayersSKAN module. On Android or without the module, isSupported() returns false and all native operations are no-ops.

React Native Linking API

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

const unsubscribe = setupDeepLinkListener((data) => {
  console.log(data.url); // 'myapp://product/123?ref=email'
  console.log(data.scheme); // 'myapp'
  console.log(data.host); // 'product'
  console.log(data.path); // '/123'
  console.log(data.queryParams); // { ref: 'email' }

  // Track the deep link as an event
  layers.track('deep_link', {
    url: data.url,
    source: data.queryParams.ref
  });
});

// Clean up
unsubscribe();

Expo Router

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 fires a screen() call on every route change with the pathname and search params as properties.

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

// Check current state
const consent = layers.getConsentState();

When analytics is false, track() and screen() calls are silently dropped.

Error Handling

Register error listeners to catch errors that would otherwise be silently dropped:

layers.on('error', (err) => {
  console.error('Layers SDK error:', err.message);
});

// Remove a listener
layers.off('error', myListener);

When enableDebug is true and no error listeners are registered, errors are logged to console.warn.

Debug Mode

Enable enableDebug: true (or __DEV__) for detailed logging:

[Layers] track("app_open", 1 properties)
[Layers] screen("home", 0 properties)
[Layers] setAppUserId("user-123")

Testing

Mock the SDK in tests by replacing the instance with a simple spy object:

const mockLayers = {
  init: jest.fn().mockResolvedValue(undefined),
  track: jest.fn().mockResolvedValue(undefined),
  screen: jest.fn().mockResolvedValue(undefined),
  setAppUserId: jest.fn(),
  clearAppUserId: jest.fn(),
  getAppUserId: jest.fn(),
  setConsent: jest.fn().mockResolvedValue(undefined),
  getConsentState: jest.fn().mockReturnValue({}),
  setUserProperties: jest.fn().mockResolvedValue(undefined),
  setDeviceInfo: jest.fn(),
  flush: jest.fn().mockResolvedValue(undefined),
  shutdown: jest.fn(),
  getSessionId: jest.fn().mockReturnValue('mock-session-id'),
  on: jest.fn().mockReturnThis(),
  off: jest.fn().mockReturnThis()
};

License

MIT

Keywords

react-native

FAQs

Package last updated on 08 Mar 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