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

@nexly/react-native

v1.0.0

Published

React Native bindings for Nexly: fetch transport, AsyncStorage IDs, AppState engagement on top of @nexly/core

Readme

@nexly/react-native

React Native SDK for Nexly. Implements NexlyBase with:

  • fetch({ keepalive: true }) transport,
  • visitor/session IDs persisted via @react-native-async-storage/async-storage,
  • device metadata via Platform, Dimensions, PixelRatio,
  • engagement tracking driven by AppState (active seconds, heartbeat, session_ping).

Install

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

react and react-native must already be installed in your app.

Usage

import { NexlyProvider, useNexlyClient } from '@nexly/react-native'

export default function App() {
  return (
    <NexlyProvider appId="your-app-id" ingestKey="your-ingest-key" autoEngagement initialScreen="Home">
      <Root />
    </NexlyProvider>
  )
}

function Root() {
  const client = useNexlyClient()

  return (
    <Button
      title="Upgrade"
      onPress={() => client?.customEvent('upgrade_clicked', { plan: 'pro' })}
    />
  )
}

Screen views and paths

React Native has no URL, so Nexly uses a manual screen name as the path:

  • client.setScreen('Settings') — updates the screen used as path on future events.
  • client.screenview('Settings') — records that the user viewed a new screen.

On the ingest wire, a screen view is stored as a pageview event with context.path set to the screen name. That keeps mobile screens in the same Pages dashboard, filters, and session metrics as web routes, while the React Native API still uses screenview() because that is the vocabulary app developers expect.

Call screenview() only when the user actually views a different screen or route. Do not use it for button taps, form input, tab content changes inside the same screen, or other interactions. Send those with client.customEvent(...) or client.event(...) instead; they still carry the current screen as path.

Hook it up to your router of choice. Example with @react-navigation/native:

<NavigationContainer
  onStateChange={(state) => {
    const route = state?.routes[state.index ?? 0]
    if (route) client?.screenview(route.name)
  }}
>
  ...
</NavigationContainer>

If you pass initialScreen, you do not need to send an extra screenview() for that same screen during the first render. Send the first manual screenview() from your navigator when it reports a route change.

Engagement

autoEngagement attaches an AppState listener that:

  • Increments active_seconds only while the app is foregrounded.
  • Sends a heartbeat every 60 s (lifecycle event for realtime dashboards).
  • Sends session_ping when the app goes to background, and session_end on provider unmount.

No scroll/click tracking (those are DOM-only); if you want tap analytics, send custom engagement events yourself.

startEngagement() is idempotent — calling it again stops the previous subscription first, so Fast Refresh or double-mounts cannot produce duplicate listeners.

Privacy mode (no device storage)

Pass privacyMode to the provider (or Nexly.init({ privacyMode: true })) and Nexly never reads or writes AsyncStorage for its visitor / session identifiers. Events go out without client-side IDs; the Nexly collector derives a daily-rotating visit fingerprint server-side instead. Cross-day returning-visitor metrics are not available in this mode.

Dashboard setup

Enable Mobile apps in your app's Ingest settings in the Nexly dashboard before sending native events. This allows React Native traffic from the package's synthetic origin and makes React Native sources visible in Technology analytics.

Native clients report as:

  • rn-ios for iOS and other Apple native runtimes,
  • rn-android for Android,
  • rn-web when running through React Native Web.

In Technology analytics, native React Native traffic is labelled as React Native with the appropriate OS and mobile device type. React Native Web uses the browser's normal web metadata.