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

@inoxth/react-native-edot-navigation

v0.2.2

Published

EDOT navigation integration — unified screen-tracking for react-navigation, expo-router, and Wix react-native-navigation

Readme

@inoxth/react-native-edot-navigation

Unified navigation tracking plugin for the React Native EDOT SDK. On every navigation it emits a screen-load-latency span (from screen-appear until the JS thread is idle, i.e. the screen is interactive) and enriches network/error spans created during that screen's lifetime with screen.name + screen.id.

A single package covers all three popular React Native navigators:

Pick the section that matches your navigator — each is self-contained.

Install

yarn add @inoxth/react-native-edot-navigation

You also need the core SDK initialized first:

yarn add @inoxth/react-native-edot-sdk

See the SDK README for native setup and EdotReactNative.initialize(...). The navigator libraries themselves are declared as optional peer dependencies — only install the one you actually use.

React Navigation

yarn add @react-navigation/native

Initialize the SDK with useEdot at the app root, then wrap your NavigationContainer with <EdotNavigationProvider> sharing the same ref. Wait for ready before mounting NavigationContainer — the navigator emits its initial screen span synchronously on mount, and on iOS the OTel TracerProvider only points at the agent's exporter once the agent has started. Mounting before the SDK is ready silently drops the first screen span.

import { ActivityIndicator, Text } from 'react-native';
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
import { useEdot } from '@inoxth/react-native-edot-sdk';
import { EdotNavigationProvider } from '@inoxth/react-native-edot-navigation';

export function App() {
  const navigationRef = useNavigationContainerRef();
  const { ready, error } = useEdot({
    serverUrl: 'https://your-apm-server:8200',
    serviceName: 'my-app',
    serviceVersion: '1.0.0',
    deploymentEnvironment: 'production',
    secretToken: process.env.EDOT_SECRET_TOKEN,
  });

  if (error) return <Text>Telemetry unavailable: {error.message}</Text>;
  if (!ready) return <ActivityIndicator />;

  return (
    <NavigationContainer ref={navigationRef}>
      <EdotNavigationProvider navigationRef={navigationRef}>
        {/* your screens */}
      </EdotNavigationProvider>
    </NavigationContainer>
  );
}

Working example: example/react-navigation/.

Expo Router

Expo Router is built on top of React Navigation and exposes the same useNavigationContainerRef hook. Initialize the SDK from your root layout with useEdot and gate the navigator on ready — the same first-screen-span ordering rule from the React Navigation section applies here:

import { ActivityIndicator, Text } from 'react-native';
import { Slot, useNavigationContainerRef } from 'expo-router';
import { useEdot } from '@inoxth/react-native-edot-sdk';
import { EdotNavigationProvider } from '@inoxth/react-native-edot-navigation';

export default function RootLayout() {
  const navigationRef = useNavigationContainerRef();
  const { ready, error } = useEdot({
    serverUrl: 'https://your-apm-server:8200',
    serviceName: 'my-app',
    serviceVersion: '1.0.0',
    deploymentEnvironment: 'production',
    secretToken: process.env.EDOT_SECRET_TOKEN,
  });

  if (error) return <Text>Telemetry unavailable: {error.message}</Text>;
  if (!ready) return <ActivityIndicator />;

  return (
    <EdotNavigationProvider
      navigationRef={navigationRef}
      screenNameMapper={(name) => name.replace(/\/\d+/g, '/:id')}
    >
      <Slot />
    </EdotNavigationProvider>
  );
}

Working example: example/expo-router/.

Wix react-native-navigation

Wix cannot use the useEdot hook. Init has to run inside Navigation.events().registerAppLaunchedListener — that's a callback executed by the native navigator before any React component mounts, so there is no React tree yet. Use the imperative EdotReactNative.initialize(config) here.

Wix has no continuously-mounted React root, so registration is imperative and the order matters. Do this in your index.js:

  1. Register every screen component at module top level (synchronous, before the navigator boots).
  2. Inside registerAppLaunchedListener, initialize the SDK first.
  3. Then call registerEdotNavigationListener so subsequent navigations are tracked.
  4. Then call Navigation.setRoot(...) to mount the UI.
import { Navigation } from 'react-native-navigation';
import { EdotReactNative } from '@inoxth/react-native-edot-sdk';
import { registerEdotNavigationListener } from '@inoxth/react-native-edot-navigation';
import { HomeScreen } from './src/screens/HomeScreen';
import { DemosScreen } from './src/screens/DemosScreen';
import { SettingsScreen } from './src/screens/SettingsScreen';

// 1. Register screens at module top level
Navigation.registerComponent('HomeScreen', () => HomeScreen);
Navigation.registerComponent('DemosScreen', () => DemosScreen);
Navigation.registerComponent('SettingsScreen', () => SettingsScreen);

const SCREEN_NAME_MAP: Record<string, string> = {
  HomeScreen: 'Home',
  DemosScreen: 'Demos',
  SettingsScreen: 'Settings',
};

Navigation.events().registerAppLaunchedListener(async () => {
  // 2. Initialize the SDK first
  await EdotReactNative.initialize({
    serverUrl: 'https://your-apm-server:8200',
    serviceName: 'my-app',
    serviceVersion: '1.0.0',
    deploymentEnvironment: 'production',
    secretToken: process.env.EDOT_SECRET_TOKEN,
  });

  // 3. Hook the navigation listener
  registerEdotNavigationListener(Navigation, {
    screenNameMapper: (name) => SCREEN_NAME_MAP[name] ?? name,
  });

  // 4. Mount the UI
  Navigation.setRoot({
    root: {
      bottomTabs: {
        children: [
          { stack: { children: [{ component: { name: 'HomeScreen' } }] } },
          { stack: { children: [{ component: { name: 'DemosScreen' } }] } },
          { stack: { children: [{ component: { name: 'SettingsScreen' } }] } },
        ],
      },
    },
  });
});

registerEdotNavigationListener returns a cleanup function — call it in tests or when tearing down the navigator.

Working example: example/wix-navigation/.

Screen name mapping

Both surfaces accept a screenNameMapper to normalize raw route names into stable span names. Common uses:

// Strip dynamic ids out of expo-router pathnames
screenNameMapper: (name) => name.replace(/\/\d+/g, '/:id');

// Use a friendly display name based on params
screenNameMapper: (name, params) =>
  name === 'Profile' && typeof params?.tab === 'string' ? `Profile.${params.tab}` : name;

What gets emitted

For every navigation, a screen-load-latency span is created with:

  • name = <post-mapper screen name> - view appearing (matches EDOT iOS/Android view-appearing span naming)
  • kind = INTERNAL
  • attribute screen.name (the bare post-mapper screen name)
  • attribute last.screen.name (only when a previous screen exists and differs)

The span starts when the screen appears and ends automatically when InteractionManager.runAfterInteractions fires — i.e. when navigation/transition animations have finished and the JS thread is idle. Typical span durations are 100–500ms, suitable for a Latency SLO.

Network and error spans created while the screen is active automatically include screen.name and screen.id as well — that correlation continues for the full time the screen is the active view, even after the load-latency span has already ended.

If the app is sent to background while the load span is still running (rare, only during the brief load window), the span is closed with status ERROR and attribute screen.load.aborted=true so SLOs see the abort honestly.

Custom load completion signal

For screens that need to wait for async data (e.g. an initial fetch) before they're truly "interactive", use useScreenLoaded(ready) to override the default runAfterInteractions end-trigger:

import { useScreenLoaded } from '@inoxth/react-native-edot-navigation';

function ProductScreen() {
  const { data } = useQuery('/product');
  useScreenLoaded(!!data); // ends the load span as soon as data arrives
  return /* ... */;
}

Whichever fires first — your useScreenLoaded flip or the automatic runAfterInteractions — wins; the span ends only once. Imperative callers can use markCurrentScreenLoaded() directly.

Requirements

  • React Native >= 0.72.0
  • React >= 18.0.0
  • One of:
    • @react-navigation/native >= 6.0.0
    • expo-router >= 3.0.0
    • react-native-navigation >= 7.0.0
  • @inoxth/react-native-edot-sdk initialized at app startup

License

MIT — see LICENSE.