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

@insightech/react-native

v1.2.0

Published

Insightech analytics SDK for React Native

Downloads

431

Readme

@insightech/react-native

Insightech analytics SDK for React Native. Captures user interactions, screen views, and component tree snapshots for session replay, heatmaps, click maps, scroll depth, and form analytics on the Insightech dashboard.

The SDK sends data in the exact same format as the Insightech web JavaScript SDK, so no backend changes are needed.

Table of Contents


Requirements

  • React >= 17
  • React Native >= 0.68
  • @react-native-async-storage/async-storage >= 1.17
  • Optional: @react-navigation/native for automatic screen tracking

Compatible with: Expo managed workflow, Expo bare workflow, React Native CLI, Expo Go, and the New Architecture (Fabric/Bridgeless). No native modules required.

Tested with: React Native 0.68 through 0.81, React 17 through 19, both Paper and Fabric renderers. React Native 0.76–0.81 are verified on every push by the CI matrix (TypeScript build + full unit-test suite, against each version's bundled types and its matching React 18/19). React Native 0.81 (React 19, New Architecture) is additionally verified end-to-end on both the iOS simulator and an Android emulator via the example/ app — pageview, tap, scroll, text input, navigation, and FlatList all capture correctly on each. RN 0.77–0.80 are covered by the CI matrix at the build + unit-test level; on-device verification focuses on the newest minor, where fiber-tree and New-Architecture changes are most likely to surface.

New Architecture: The SDK accesses React internals defensively (see #15) and runs on both the legacy (Paper) and New Architecture (Fabric/Bridgeless) renderers. The CI matrix exercises the default architecture shipped with each RN version.


Installation

npm install @insightech/react-native @react-native-async-storage/async-storage

If using @react-navigation/native (recommended for automatic screen tracking):

npm install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context

Quick Start

Integration requires just two steps: add the Babel plugin and wrap your app with InsightechProvider. No component swapping needed.

Step 1: Add the Babel Plugin

// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'], // or 'module:metro-react-native-babel-preset'
    plugins: ['@insightech/babel-plugin-react-native'],
  };
};

The plugin automatically instruments interactive components at build time. Your app code stays 100% standard React Native.

Step 2: Wrap Your App

import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
import { InsightechProvider } from '@insightech/react-native';

export default function App() {
  const navigationRef = useNavigationContainerRef();

  return (
    <InsightechProvider
      config={{
        account: 'YOUR_PROFILE_ID:YOUR_SERVER_ID',
        appName: 'MyApp',
      }}
      navigationRef={navigationRef}
    >
      <NavigationContainer ref={navigationRef}>
        {/* Your app navigator */}
      </NavigationContainer>
    </InsightechProvider>
  );
}

Where to find your account string: Log in to the Insightech dashboard. Your profile ID and server ID are in the tracking code snippet, formatted as profileId:serverId.

That's it. The SDK starts tracking immediately.


What Gets Tracked Automatically

Once set up, the following are captured without any additional code:

| What | How | Requires | |------|-----|----------| | Screen views | React Navigation listener | navigationRef prop | | Tap / click events | Babel plugin instruments Pressable, TouchableOpacity, TouchableHighlight | Babel plugin | | Scroll events | Babel plugin instruments ScrollView, FlatList, SectionList | Babel plugin | | Text input & changes | Babel plugin instruments TextInput | Babel plugin | | Field focus / blur | Tracked via TextInput wrapper | Babel plugin | | App background / foreground | AppState listener | Nothing (built-in) | | Viewport resize | Dimensions listener | Nothing (built-in) | | Component tree snapshots | React fiber tree serialization | Nothing (built-in) | | DOM mutations | Tree diff after interactions | Nothing (built-in) | | Rage taps | Rapid repeated taps on same element | Nothing (built-in) | | JS crashes | Global error handler | Nothing (built-in) | | API errors | Fetch/XHR interception | Server config |

Excluding Components from Auto-Tracking

If you don't want certain components to be tracked, exclude them in the Babel plugin config. Two options are available and can be combined:

  • exclude — skip specific component types everywhere.
  • excludeFiles — skip all instrumentation for files matching glob patterns. Use this as a file-level escape hatch for a screen or directory that interacts badly with instrumentation (e.g. a screen with complex native modules), instead of disabling the plugin entirely.
plugins: [
  ['@insightech/babel-plugin-react-native', {
    // Skip these component types in every file
    exclude: ['ScrollView', 'FlatList'],
    // Skip these files/directories entirely (glob patterns)
    excludeFiles: ['**/lesson/**', '**/VideoPlayer.tsx'],
  }],
],

Glob support: ** (any path segments), * (any characters within one segment), and ? (a single character). Globs are matched against the file's absolute path, so prefix directory patterns with **/. Clear the Metro cache after changing plugin options (--reset-cache / --clear).

Note: TouchableOpacity and TouchableHighlight are wrapped by faithful tracked equivalents that preserve their native press feedback (opacity fade / underlay highlight) — instrumentation is transparent and does not change how your buttons look or behave.


Custom Event Tracking

Use the useInsightech hook to track custom business events:

import { useInsightech } from '@insightech/react-native';

function ProductDetailScreen({ product }) {
  const { trackCustomEvent } = useInsightech();

  const handleAddToCart = () => {
    addToCart(product);

    trackCustomEvent({
      event: 'add_to_cart',
      product_id: product.id,
      product_name: product.name,
      price: product.price,
      currency: 'USD',
    });
  };

  return (
    <Pressable testID="add-to-cart-btn" onPress={handleAddToCart}>
      <Text>Add to Cart</Text>
    </Pressable>
  );
}

Custom events appear as type 99 (DATA_LAYER) in the session timeline and can be used for conversion tracking, funnel analysis, and segmentation.


Error Tracking

Automatic JS Crash Tracking

The SDK automatically captures unhandled JavaScript exceptions via React Native's ErrorUtils. These are sent as js_error events and appear in the session timeline. The handler chains with existing error handlers (Sentry, Crashlytics, etc.) so it won't interfere with your crash reporting setup.

Manual Error Tracking

Track error messages shown to users — validation errors, API failures, or any error state:

const { trackError } = useInsightech();

// Form validation error
trackError({
  message: 'Please fill in all required fields',
  type: 'validation',
  context: { screen: 'Checkout', empty_fields: ['email', 'phone'] },
});

// API error
trackError({
  message: 'Payment failed: card declined',
  type: 'api',
  context: { endpoint: '/api/payment', status: 402 },
});

Each trackError call sends a custom event with event: "error", error_message, error_type (defaults to "validation"), and any additional context fields.


Form Tracking

Track form submissions with field-level detail:

const { trackFormSubmit, flush } = useInsightech();

const handleCheckout = async () => {
  trackFormSubmit({
    nodeIndex: 0,
    cssPath: '#checkout-form',
    name: 'checkout',
    method: 'POST',
    fields: [
      { nodeIndex: 1, cssPath: '#email', name: 'email', value: email },
      { nodeIndex: 2, cssPath: '#name', name: 'name', value: name },
      // Mask sensitive fields before tracking
      { nodeIndex: 3, cssPath: '#card', name: 'card', value: '****' },
      { nodeIndex: 4, cssPath: '#cvv', name: 'cvv', value: '***' },
    ],
  });

  // Force send events before navigating away
  await flush();

  navigation.navigate('OrderConfirmation', { orderId });
};

Important: Always call flush() before navigating away from a screen with tracked form data to ensure events are sent before the component unmounts.


Element Identification with testID

Add testID to your components for stable, readable element identification in analytics:

<Pressable testID="add-to-cart" onPress={handleAdd}>
  <Text>Add to Cart</Text>
</Pressable>

<TextInput testID="email-input" placeholder="Email" onChangeText={setEmail} />

<ScrollView testID="product-list">
  {/* ... */}
</ScrollView>

Why this matters:

  • testID maps to the HTML id attribute in the synthetic DOM, producing CSS selectors like #add-to-cart
  • Without testID, elements are identified by position (e.g., div:nth-child(2)), which breaks when the layout changes
  • testID is also used for content masking rules (see Privacy section)
  • testID is already standard practice for testing — use the same IDs for both

Privacy & Data Masking

All personal data is masked on-device before transmission. Raw values never leave the device.

Automatic Input Masking

All TextInput values are masked by default:

| User types | Sent as | Rule | |------------|---------|------| | John Doe | **** *** | Letters/symbols → * | | 4242424242424242 | 0000000000000000 | Digits → 0 | | [email protected] | ****@*******.** | Email pattern detected, structure preserved | | 123 Main St | 000 **** ** | Mixed: digits → 0, letters → * |

Automatic Email Detection

Email addresses are detected and masked in all text content (not just inputs). Any text matching an email pattern is masked before the component tree is sent.

Content Masking with testID

Mask specific on-screen text using testID combined with the server's contentBlockList:

{/* Order ID — visible (not in block list) */}
<Text testID="order-id">{orderId}</Text>

{/* Personal details — masked via contentBlockList */}
<Text testID="personal-details">{userName}</Text>
<Text testID="personal-details">{userEmail}</Text>
<Text testID="personal-details">{userAddress}</Text>

In the replay:

  • Order ID: ORD-12345 (readable)
  • Name: **** *** (masked)
  • Email: ****@*******.** (masked)
  • Address: *** **** ** (masked)

Server-Controlled Masking Rules

The server returns two lists on the SDK's first request — no app update needed to change masking rules:

  • fieldAllowList — Input fields to leave unmasked (e.g., ["#search-input", "#quantity"])
  • contentBlockList — Elements to fully mask (e.g., ["#personal-details", "#payment-info"])

Configuration Reference

All configuration options for InsightechProvider:

<InsightechProvider
  config={{
    // ── Required ──
    account: 'profileId:serverId',  // From your Insightech dashboard
    appName: 'MyApp',               // Used in screen URLs

    // ── Optional ──
    protocol: 'https:',             // Server protocol (default: 'https:')
    trackingLevel: 'full',          // 'full' or 'lite' (default: 'full')
    sampleRate: 1.0,                // Fraction of visitors with session replay, 0.0–1.0 (default: 1.0)
    devMode: false,                 // true = new visitor ID on each app start,
                                    //        enables console logging (default: false)

    // ── Network ──
    maxConcurrentRequests: 1,       // Max parallel HTTP requests (default: 1)
    sendRequestSize: 200,           // KB threshold to trigger send (default: 200)
    requestTimeout: 10000,          // Request timeout in ms (default: 10000)
    maxRetries: 3,                  // Max retries per failed batch (default: 3)
    retryBaseDelay: 1000,           // Base delay for exponential backoff in ms (default: 1000)

    // ── Event Throttling ──
    scrollInterval: 150,            // Scroll event throttle in ms (default: 150)
    resizeInterval: 150,            // Resize event throttle in ms (default: 150)
    mutationBatchInterval: 200,     // Mutation batch window in ms (default: 200)

    // ── Storage ──
    visitorIdStorageKey: 'insightech_vid', // AsyncStorage key for visitor ID
    maxQueueSize: 1000,             // Max queued events before dropping oldest (default: 1000)
    maxTestIdEntries: 5000,         // Max testID lookup entries before LRU eviction (default: 5000)
    maxSnapshotBytes: 500000,       // Drop a DOM snapshot above this approx. size (default: 500000)
    deferTracking: true,            // Defer snapshot/gzip work off the critical path (default: true)
  }}
  navigationRef={navigationRef}     // Optional: React Navigation ref for auto screen tracking
/>

Session Sampling

sampleRate controls session-replay coverage, not whether events flow. Analytics events (taps, scrolls, inputs, custom events, errors) are always sent for every visitor; the rate only decides which visitors also capture replay data (DOM snapshots and mutations):

| sampleRate | Visitors with full tracking (replay) | Visitors with lite tracking (events only) | |---|---|---| | 1.0 (default) | 100% | 0% | | 0.5 | 50% | 50% | | 0.0 | 0% | 100% |

The decision is deterministic per visitor — a visitor keeps the same mode across app launches, and the same calculation is used by other Insightech SDKs, so a visitor lands in the same bucket on every platform.

Precedence when multiple settings apply:

  1. Explicit trackingLevel — if you set trackingLevel: 'full' or 'lite', sampling is bypassed entirely.
  2. Server override (sr) — Insightech can adjust the rate server-side without an app release.
  3. sampleRate — the local default, 1.0 if omitted.
<InsightechProvider
  config={{
    account: 'YOUR_PROFILE_ID:YOUR_SERVER_ID',
    appName: 'MyApp',
    sampleRate: 0.25,  // replay for 25% of visitors; analytics for all
  }}
/>

Out-of-range values are clamped to [0, 1] (a warning is logged in devMode).

Snapshot Size Guard

On very deep or wide screens a single DOM snapshot can grow into megabytes — heavy to serialize, expensive to gzip, and a large one-shot hit to a user's bandwidth. maxSnapshotBytes (default 500000, an approximate serialized-size estimate) bounds this: when a snapshot would exceed the limit, the SDK drops that snapshot — it skips the DOM-tree (type 2) event for that screen rather than sending an oversized or partial payload. All other events (taps, scrolls, inputs, navigation, custom events) keep flowing; only the replay snapshot for that one oversized screen is omitted (a warning is logged in devMode).

Set maxSnapshotBytes: Infinity to disable the guard and always send the full snapshot. Raise it if replays of complex screens are missing; lower it to cap payload size more aggressively.

Deferred Capture

With deferTracking: true (the default), the SDK keeps heavy work off the interaction path:

  • DOM snapshots wait for ongoing gestures/animations (InteractionManager) and serialize in chunks, yielding to the event loop every ~500 components,
  • gzip compression of large payloads yields a frame before running,
  • snapshots and mutation diffs run through an ordered queue, so replay events are never reordered.

Set deferTracking: false to restore fully synchronous capture — useful in tests or when you need a snapshot to complete before the next line of code runs.

Custom gzip (optional)

Large request payloads (>10KB) are gzipped before sending. By default the SDK uses the bundled pure-JS pako — no setup, works in Expo Go. If you want compression to run on a native thread, pass your own gzip function (e.g. backed by a native module) and the SDK will use it instead:

config={{
  // Receives the JSON body string, returns gzipped bytes (sync or async).
  gzip: (body) => myNativeGzip(body),
}}

The SDK falls back to pako, then to sending uncompressed, if gzip is omitted or throws — so this never breaks the request, and adds no native dependency unless you opt in.

Development Mode

Set devMode: true during development to:

  • Generate a new visitor ID on each app start (each reload is a new session)
  • Enable console.log output for debugging SDK behavior
  • See SDK initialization, event queuing, and transport logs in Metro
<InsightechProvider
  config={{
    account: 'YOUR_PROFILE_ID:YOUR_SERVER_ID',
    appName: 'MyApp',
    devMode: __DEV__,  // Auto-enable in development
  }}
  navigationRef={navigationRef}
/>

Advanced Usage

Manual Screen Tracking (Without React Navigation)

If you don't use React Navigation, track screens manually:

const { trackScreen } = useInsightech();

// Call when a screen mounts or becomes visible
useEffect(() => {
  trackScreen('ProductDetail', { productId: product.id });
}, []);

Force Sending Events

The SDK batches events and sends them automatically. To force-send immediately (e.g., before the app navigates to an external URL or before a critical action):

const { flush } = useInsightech();

const handleExternalLink = async () => {
  await flush();
  Linking.openURL(url);
};

Accessing the SDK Instance Directly

For advanced use cases, access the raw SDK instance:

const { sdk } = useInsightech();

// Track a tap manually
sdk.trackTap({
  nodeIndex: 0,
  cssPath: '#custom-element',
  tag: 'button',
  text: 'Custom Button',
  elementX: 100,
  elementY: 200,
  screenX: 100,
  screenY: 300,
  scrollTop: 0,
  scrollLeft: 0,
  pageTop: 0,
  pageLeft: 0,
  name: '',
  href: '',
});

Offline Support

Events are persisted to AsyncStorage when the app goes to background. If the app is killed before events can be sent, they are restored and sent on the next app launch. This ensures no data loss during:

  • OS killing the app in the background
  • App crashes
  • Brief network outages (events are retried with exponential backoff)

Using Tracked Components Directly

If you prefer not to use the Babel plugin, import tracked components directly:

import {
  TrackedPressable,
  TrackedTouchableOpacity,
  TrackedTouchableHighlight,
  TrackedScrollView,
  TrackedFlatList,
  TrackedSectionList,
  TrackedTextInput,
} from '@insightech/react-native';

// Use them as drop-in replacements
<TrackedPressable testID="my-button" onPress={handlePress}>
  <Text>Press Me</Text>
</TrackedPressable>

<TrackedFlatList
  testID="product-list"
  data={products}
  renderItem={renderProduct}
/>

How It Works

Architecture Overview

Your App
  │
  ├── InsightechProvider (wraps app, captures fiber tree)
  │     │
  │     ├── Babel plugin rewrites imports at build time
  │     │     Pressable → TrackedPressable
  │     │     TouchableOpacity → TrackedTouchableOpacity
  │     │     TouchableHighlight → TrackedTouchableHighlight
  │     │     ScrollView → TrackedScrollView
  │     │     FlatList → TrackedFlatList
  │     │     SectionList → TrackedSectionList
  │     │     TextInput → TrackedTextInput
  │     │
  │     ├── Tracked wrappers intercept events (taps, scrolls, inputs)
  │     │
  │     ├── Component tree serialized to synthetic DOM
  │     │     View → <div>, Text → <span>, Pressable → <button>, etc.
  │     │
  │     └── Privacy masking applied on-device
  │
  └── Events batched → compressed → sent to Insightech backend
        ↓
      Insightech Dashboard (replay, heatmaps, funnels, analytics)

Synthetic DOM Tree

React Native has no HTML DOM. The SDK constructs a synthetic DOM by walking the React fiber tree and mapping components to HTML equivalents:

| React Native Component | HTML Element | |------------------------|-------------| | View, SafeAreaView, KeyboardAvoidingView | <div> | | Text | <span> | | Image, ImageBackground | <img> | | TextInput | <input> | | ScrollView | <div> (with overflow styles) | | FlatList, SectionList | <ul> | | Pressable, TouchableOpacity, TouchableHighlight | <button> | | Switch | <input type="checkbox"> | | Modal | <div> |

Screen URLs

Screens are represented as URLs for backend compatibility:

https://app.insightech.com/rn/{appName}/{screenName}?param=value

For example, navigating to a ProductDetail screen with { productId: '42' } generates:

https://app.insightech.com/rn/MyApp/ProductDetail?productId=42

Event Batching & Delivery

Events are queued and sent based on type:

  • Immediate: Pageview, DOM tree, navigation, form submit, app background
  • Force send: Clicks, rage taps (flushes entire queue)
  • Batched: Scroll, resize, input, mutations (merged into arrays)
  • Size-based: Queue flushed when payload exceeds 200KB

Failed requests are retried with exponential backoff (1s, 2s, 4s) up to 3 times. Events are persisted to AsyncStorage on app background and restored on next launch.

Fiber Access & Compatibility

The SDK accesses React's internal fiber properties to serialize the component tree. These are undocumented internals that may change across versions. The following properties are tried in order:

  1. __internalInstanceHandle (Fabric / New Architecture)
  2. _internalFiberInstanceHandleDEV (Paper / development builds)
  3. _reactInternals (React 18+)
  4. _reactInternalInstance (React 17 / legacy)

If fiber access fails, the SDK degrades gracefully — events are still tracked but session replay won't have DOM data. Test replay after major React/RN version upgrades.


Troubleshooting

No data appearing in the dashboard

  1. Check devMode logs: Set devMode: true and look for [Insightech:Transport] logs in Metro. You should see Response: 200 for successful sends.
  2. Verify account string: Ensure account is formatted as profileId:serverId (e.g., '080360e96:us-0-api').
  3. Check date filter: The dashboard defaults to "Yesterday". Switch to "Today" to see current sessions.

Session replay shows empty/broken layout

  1. Check fiber access: In devMode, look for [Insightech:Provider] Root fiber captured. If you see "No fiber found", the SDK can't access the component tree.
  2. Verify RN version: Ensure you're on a supported React Native version (0.68+).
  3. Add testIDs: Elements without testID use positional selectors which are less stable.

Events not being tracked for specific components

  1. Check Babel plugin: Verify @insightech/babel-plugin-react-native is in your babel.config.js. Clear the Metro cache after changes: npx expo start --clear or npx react-native start --reset-cache.
  2. Check exclusions: Make sure the component isn't in the exclude list, and that its file isn't matched by an excludeFiles glob.
  3. Custom components: The Babel plugin only instruments direct imports from react-native. If you wrap Pressable in a custom component, add tracking manually using useInsightech.
  4. Check provider placement: Tracked components only record when they render inside <InsightechProvider> — see below.

<InsightechProvider> placement (no data on some screens)

The Babel plugin instruments components app-wide, and every tracked component looks up the SDK from the nearest <InsightechProvider>. If a tracked component renders outside the provider's subtree, tracking is silently disabled for that component only — the app keeps running (the SDK fails open and never throws).

In development (__DEV__) you'll see this warning once:

[Insightech] A tracked component rendered outside <InsightechProvider>;
tracking is disabled for it. Move <InsightechProvider> so it wraps your
entire app (above your navigator/router).

Fix: mount <InsightechProvider> at the very top of your app — above your navigator/router (e.g. wrapping the root layout in app/_layout.tsx for Expo Router, or your NavigationContainer) — so every screen and component is a descendant. A correctly-placed provider never triggers this warning.

High memory usage or battery drain

Adjust throttling and batching settings:

config={{
  scrollInterval: 300,        // Less frequent scroll events
  mutationBatchInterval: 500, // Longer mutation batch window
  sendRequestSize: 500,       // Larger batches, fewer requests
  maxQueueSize: 500,          // Smaller max queue
}}

scrollInterval vs scrollEventThrottle: scrollInterval (provider config) controls how often the SDK records a scroll snapshot. scrollEventThrottle is a standard per-component prop controlling how often the native layer delivers scroll events to JS. The tracked scroll wrappers default it to 16 (~60fps) only when you don't set it; any value you pass is respected. Scroll heatmaps are built from throttled position snapshots, so a higher scrollEventThrottle for performance has negligible visual impact.

Virtualized lists (FlatList / SectionList)

Virtualized lists only render the rows currently near the viewport — off-screen rows are unmounted. This has two implications for capture, both expected:

  • Replay reflects what was on screen. A DOM-tree snapshot contains the rows mounted at capture time; rows far off-screen aren't in it. As the user scrolls, mutation events capture the rows that come and go, so the replay follows the scroll rather than showing the entire list at once.
  • Row tracking stays correct and bounded. As rows recycle, each remounted row gets a fresh node index, and tap/scroll tracking resolves elements by testID to their current index — so interactions map to the right row. The internal testID → index registry is LRU-bounded (maxTestIdEntries, default 5000), so a long scrolling session won't leak memory; actively-visible elements are refreshed and never evicted.

Recommendations for large lists:

  • Give rows a stable testID (and a stable keyExtractor) so recycled rows map back consistently.
  • Tune windowSize / initialNumToRender on the list if you want more rows captured per snapshot (at the cost of render work).
  • Raise maxTestIdEntries only if you have more than ~5,000 distinct interactive testIDs alive at once (rare).

Events lost when app is killed

Events are automatically persisted to AsyncStorage when the app goes to background and restored on next launch. If you're still losing events, ensure @react-native-async-storage/async-storage is properly installed and linked.


API Reference

InsightechProvider

<InsightechProvider
  config={InsightechConfig}        // Required: SDK configuration
  navigationRef={NavigationRef}    // Optional: React Navigation container ref
>
  {children}
</InsightechProvider>

useInsightech()

const {
  trackScreen,       // (screenName: string, params?: Record<string, unknown>) => void
  trackCustomEvent,  // (data: Record<string, unknown>) => void
  trackFormSubmit,   // (info: FormInfo) => void
  trackError,        // (info: { message: string, type?: string, context?: Record }) => void
  flush,             // () => Promise<void>
  sdk,               // InsightechSDK instance (for advanced usage)
} = useInsightech();

Tracked Components

All tracked components are drop-in replacements that forward all props and refs:

| Component | Wraps | Tracks | |-----------|-------|--------| | TrackedPressable | Pressable | Tap events with position, element text, CSS path | | TrackedTouchableOpacity | TouchableOpacity | Tap events; preserves the native opacity fade | | TrackedTouchableHighlight | TouchableHighlight | Tap events; preserves the native underlay highlight | | TrackedScrollView | ScrollView | Scroll position, content size, throttled | | TrackedFlatList | FlatList | Scroll position, content size, throttled | | TrackedSectionList | SectionList | Scroll position, content size, throttled | | TrackedTextInput | TextInput | Input keystrokes (masked), focus, blur, change |

Event Types

| Type | Name | Trigger | |------|------|---------| | 1 | Pageview | Screen mount / navigation | | 2 | DOM Tree | Component tree snapshot | | 3 | App Ready | SDK initialization | | 4 | App Unload | App backgrounding | | 7 | Click | onPress on tracked pressables | | 8 | Input | onChangeText on tracked text inputs | | 9 | Input Change | onEndEditing / blur with final value | | 12 | Scroll | onScroll on tracked scroll views | | 13 | Tab Hidden | App goes to background | | 14 | Tab Visible | App returns to foreground | | 15 | Resize | Device orientation / dimensions change | | 16 | DOM Mutation | Component tree diff after interactions | | 17 | Field Focus | onFocus on tracked text inputs | | 18 | Field Blur | onBlur on tracked text inputs | | 19 | URL Change | Screen navigation | | 20 | Form Submit | trackFormSubmit() call | | 97 | API Error | HTTP errors on monitored endpoints | | 98 | Rage Tap | Rapid repeated taps on same element | | 99 | Custom / Error | trackCustomEvent() or trackError() |


Development

npm install          # Install dependencies
npm test             # Run tests (124 tests)
npm test -- --coverage  # Run with coverage report
npm run build        # Build CJS, ESM, and TypeScript definitions
cd example && npx expo start --ios  # Run example app

Version

SDK version: rn-1.1.0