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

@arguslog/sdk-react-native

v1.0.3

Published

Arguslog React Native SDK — ErrorBoundary, hooks, RN-aware integrations

Downloads

143

Readme

@arguslog/sdk-react-native

npm version license

React Native SDK for Arguslog. Wraps @arguslog/sdk-browser with a RN-native global error handler (via ErrorUtils), an <ArguslogErrorBoundary>, a useArguslog() hook, and an opt-in AppState breadcrumb integration.

Ships ESM only. Compatible with React Native 0.73+ on Hermes or JSC, and React 18 / 19.

Install

pnpm add @arguslog/sdk-react-native
# peer deps — already in any RN app
pnpm add react react-native

Quick start

import { init, ArguslogErrorBoundary } from '@arguslog/sdk-react-native';
import { AppRegistry } from 'react-native';

init({
  dsn: 'arguslog://<publicKey>@<host>/api/<projectId>',
  environment: __DEV__ ? 'dev' : 'production',
  release: '1.4.0',
  integrations: ['globalHandlers'],
});

function App() {
  return (
    <ArguslogErrorBoundary fallback={<CrashScreen />}>
      <RootStack />
    </ArguslogErrorBoundary>
  );
}

AppRegistry.registerComponent('MyApp', () => App);

What globalHandlers does on RN

  • Wires ErrorUtils.setGlobalHandler and chains the previous handler so RN's redbox / LogBox still fires in dev. Fatal flag is forwarded as level: 'fatal'.
  • If globalThis.addEventListener is available (Hermes ≥ 0.74), also picks up unhandledrejection events. On older runtimes you can wire promise/setimmediate/rejection-tracking yourself and forward into captureException.

AppState breadcrumbs (opt-in)

AppState isn't statically imported by this package — that keeps the module loadable in test environments that don't resolve react-native. Pass it in explicitly:

import { AppState } from 'react-native';
import { installAppStateBreadcrumbs } from '@arguslog/sdk-react-native';

const teardown = installAppStateBreadcrumbs(AppState);
// later, on app shutdown:
teardown();

Each foreground/background transition becomes a breadcrumb under the app.lifecycle category, which is then attached to subsequent captured exceptions.

Day 1 breadcrumbs setup

A pragmatic bootstrap that wires the four breadcrumb sources most apps want from the moment they ship: app lifecycle, navigation, fetch, and console.warn / console.error. Drop this in a single arguslog.ts file and call bootstrapArguslog() once from your entry point.

// src/arguslog.ts
import {
  addBreadcrumb,
  captureException,
  init,
  installAppStateBreadcrumbs,
} from '@arguslog/sdk-react-native';
import { AppState, Platform } from 'react-native';
import type { NavigationContainerRef } from '@react-navigation/native';

export function bootstrapArguslog(): void {
  init({
    dsn: 'arguslog://<publicKey>@<host>/api/<projectId>',
    environment: __DEV__ ? 'dev' : 'production',
    release: `[email protected]+${Platform.OS}`,
    integrations: ['globalHandlers'],
    maxBreadcrumbs: 100,
  });

  installAppStateBreadcrumbs(AppState);
  installFetchBreadcrumbs();
  installConsoleBreadcrumbs();
}

// 1) Network — wraps global fetch and records method, URL, status, duration.
function installFetchBreadcrumbs(): void {
  const original = globalThis.fetch;
  globalThis.fetch = async (input, init) => {
    const started = Date.now();
    const method = (init?.method ?? 'GET').toUpperCase();
    const url = typeof input === 'string' ? input : (input as Request).url;
    try {
      const res = await original(input as RequestInfo, init);
      addBreadcrumb({
        category: 'http',
        message: `${method} ${url}`,
        level: res.ok ? 'info' : 'warning',
        data: { status: res.status, duration_ms: Date.now() - started },
      });
      return res;
    } catch (err) {
      addBreadcrumb({
        category: 'http',
        message: `${method} ${url}`,
        level: 'error',
        data: { error: String(err), duration_ms: Date.now() - started },
      });
      throw err;
    }
  };
}

// 2) Console — surfaces dev warnings/errors as breadcrumbs without changing call sites.
function installConsoleBreadcrumbs(): void {
  for (const level of ['warn', 'error'] as const) {
    const original = console[level].bind(console);
    console[level] = (...args: unknown[]) => {
      addBreadcrumb({
        category: 'console',
        message: args.map(String).join(' ').slice(0, 200),
        level: level === 'error' ? 'error' : 'warning',
      });
      original(...args);
    };
  }
}

// 3) Navigation — record screen transitions. Pass the NavigationContainer ref in.
//    Call `attachNavigationBreadcrumbs(navigationRef)` from <NavigationContainer ref=...>.
export function attachNavigationBreadcrumbs(
  navigationRef: NavigationContainerRef<Record<string, object | undefined>>,
): void {
  let previous: string | undefined;
  navigationRef.addListener('state', () => {
    const current = navigationRef.getCurrentRoute()?.name;
    if (current && current !== previous) {
      addBreadcrumb({
        category: 'navigation',
        message: previous ? `${previous} → ${current}` : current,
        level: 'info',
        data: { from: previous, to: current },
      });
      previous = current;
    }
  });
}

// Optional: catch errors that escape async boundaries you forgot to wrap.
export function reportAsync<T>(fn: () => Promise<T>): Promise<T> {
  return fn().catch((err) => {
    captureException(err);
    throw err;
  });
}

Wire it into your root:

// index.tsx
import { AppRegistry } from 'react-native';
import { NavigationContainer, createNavigationContainerRef } from '@react-navigation/native';
import { bootstrapArguslog, attachNavigationBreadcrumbs } from './arguslog';

bootstrapArguslog();
const navigationRef = createNavigationContainerRef();

function Root() {
  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() => attachNavigationBreadcrumbs(navigationRef)}
    >
      <RootStack />
    </NavigationContainer>
  );
}

AppRegistry.registerComponent('MyApp', () => Root);

After this, every captured exception arrives with the trail of: app foregrounded → screen transitions → HTTP requests → warnings — even on the very first crash you ship.

Common use cases

Identifying the signed-in user

Set on login, clear on logout. The identity is attached to every subsequent event.

import { setUser } from '@arguslog/sdk-react-native';

function onLogin(account: { id: string; email: string }): void {
  setUser({ id: account.id, email: account.email });
}

function onLogout(): void {
  setUser(undefined);
}

Capturing handled errors

For errors you've already caught — surface them anyway, with feature-scoped tags.

import { captureException, captureMessage } from '@arguslog/sdk-react-native';

async function checkout(cart: Cart): Promise<void> {
  try {
    await api.placeOrder(cart);
  } catch (err) {
    captureException(err, {
      level: 'error',
      tags: { feature: 'checkout', step: 'place-order' },
    });
    throw err; // still bubble to the UI layer
  }
}

// Non-error signals — useful for "shouldn't happen" branches.
if (!cart.items.length) {
  captureMessage('Empty cart reached checkout', 'warning');
}

Wrapping a React event handler

The hook returns a stable surface, safe to call from event handlers.

import { useArguslog } from '@arguslog/sdk-react-native';

function BuyButton({ sku }: { sku: string }) {
  const arguslog = useArguslog();
  return (
    <Pressable
      onPress={() => {
        arguslog.addBreadcrumb({
          category: 'ui.click',
          message: 'Buy pressed',
          level: 'info',
          data: { sku },
        });
        buy(sku).catch((err) => arguslog.captureException(err, { tags: { sku } }));
      }}
    >
      <Text>Buy</Text>
    </Pressable>
  );
}

Tagging events globally

Pin a value to every event going forward — useful for A/B variant, build channel, etc.

import { setTag, setContext } from '@arguslog/sdk-react-native';

setTag('build.channel', __DEV__ ? 'debug' : 'release');
setTag('ab.checkout', 'variant-b');

setContext('device', {
  os: Platform.OS,
  version: Platform.Version,
  isHermes: Boolean((globalThis as { HermesInternal?: unknown }).HermesInternal),
});

Filtering / scrubbing before send

Drop or mutate events at the last mile via beforeSend. Returning null drops the event.

init({
  dsn: '…',
  beforeSend: (event) => {
    // Drop events from a known-noisy third-party SDK.
    if (event.exception?.values[0]?.value?.includes('NoiseLib')) return null;
    // Strip auth headers from request context if some other code attached them.
    if (event.contexts?.request) {
      delete (event.contexts.request as { headers?: unknown }).headers;
    }
    return event;
  },
});

Sampling in production

Keep dev fidelity at 100%, sample heavy traffic in prod.

init({
  dsn: '…',
  sampleRate: __DEV__ ? 1.0 : 0.2,
});

Flush before going to background

When the OS may suspend the JS runtime mid-request, await the queue first.

import { AppState } from 'react-native';
import { flush } from '@arguslog/sdk-react-native';

AppState.addEventListener('change', async (state) => {
  if (state === 'background') {
    await flush();
  }
});

Recording manual breadcrumbs

For custom signals that aren't covered by the auto-instrumentation above.

import { addBreadcrumb } from '@arguslog/sdk-react-native';

addBreadcrumb({
  category: 'auth',
  message: 'Token refreshed',
  level: 'info',
  data: { exp: token.exp },
});

API

The full browser SDK surface (captureException, captureMessage, setUser, setTag, setContext, addBreadcrumb, flush, getClient) is re-exported. See @arguslog/sdk-browser for option details.

init(options): ArguslogClient

Same options as the browser SDK, but integrations is narrowed to RN-supported values ('globalHandlers'). Calling init again tears down previously installed handlers, so hot-reload during dev doesn't accumulate listeners.

<ArguslogErrorBoundary fallback={...} onError={...}>

React error boundary. Captures any child render-time error with tags: { boundary: 'react-native' }, then renders fallback (a node or render-prop). The render-prop receives { error, reset } so you can offer a "Try again" button.

useArguslog()

Memoized object exposing captureException, captureMessage, addBreadcrumb, setUser, setTag, setContext, and isInitialized(). Stable across re-renders.

License

MIT — see LICENSE.