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

@zanbug/react-native

v2.0.1

Published

Zanbug SDK for React Native and Expo — crash reporting with real screenshots, an offline queue and app start-up / screen-load performance.

Readme

@zanbug/react-native

Crash reporting and performance monitoring for React Native and Expo, reporting to your own Zanbug server. Your errors, screenshots and user data stay on infrastructure you control.

npm install @zanbug/react-native

Quick start

import { initZanbug } from '@zanbug/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

initZanbug({
  apiKey: 'bb_your_project_key',
  host: 'https://zanbug.com',
  release: '1.4.0',
  environment: __DEV__ ? 'development' : 'production',

  // Passed in by YOUR app, never imported by the SDK — see "Why you pass these in".
  storage: AsyncStorage,
});

That is the whole setup. From here, an unhandled JS error, a rejected promise or a failed HTTP call arrives in your Zanbug panel with the stack trace, the device, the screen and the breadcrumbs that led there.

What it captures

| | | |---|---| | Unhandled errors | Hooks ErrorUtils.setGlobalHandler and chains the previous handler, so the dev red box and any reporter you already had keep working. | | Unhandled promise rejections | Through Hermes' enablePromiseRejectionTracker (RN 0.70+ default engine). | | HTTP failures | fetch and XMLHttpRequest are wrapped. 5xx and transport errors become their own HttpError event; 4xx stays a breadcrumb, because a 401 is usually the app working correctly. Method, URL, status and duration only — never headers or bodies, which on a phone is where the auth token and the card number live. | | Screenshots | A real PNG of the screen at error time, with <ZanbugMask> regions painted over before the shutter. | | Device and app | OS, OS version, model, screen size, app version and build. | | Performance | APP_START, SCREEN_LOAD and JANK, measured in short windows rather than a permanent frame loop — a loop that schedules work every frame is a battery cost you would feel. | | Breadcrumbs | Navigation, HTTP calls, console output and anything you add with addBreadcrumb(). |

Every error gets a screenshot (1.4.0)

Once screenshot is configured, the adapter hands the capture function to the core, so every captured error carries a picture of the current screen — a plain Zanbug.capture(e) from a try/catch, a failed HTTP request reported by the network integration, and (best effort) a fatal. Before 1.4.0 only captureWithScreenshot() and the global handler attached one.

The event is written to the offline queue first and the screenshot is attached afterwards, bounded to 2 s, so a slow or failing capture never costs the error itself. captureMessage() events get no screenshot.

Offline queue — why it matters on mobile

A phone loses signal in a lift and a fatal error kills the process before a request can finish. The queue is therefore written to disk before sending and cleared only once the server has accepted it, so a crash with no connection is still reported the next time the app opens.

initZanbug({ apiKey: 'bb_…', host: 'https://zanbug.com', storage: AsyncStorage });

Without storage the SDK still works, but a report that cannot be sent right now is lost with the process. A 4xx response counts as delivered on purpose — otherwise a wrong API key would replay the same rejected payload on every launch, forever.

Masking a screenshot

Wrapping a subtree marks it for masking. The children are not unmounted, so state is kept and the layout does not jump; an overlay is painted over them for the capture only.

import { ZanbugMask } from '@zanbug/react-native/mask';

<ZanbugMask>
  <Text>{cardNumber}</Text>
</ZanbugMask>

The older advice — collapsable={false} and renderToHardwareTextureAndroid — does not work. react-native-view-shot cannot skip a view, so the card number was captured in full while the payload claimed masked: true. ZanbugMask reports masked only when an overlay was really drawn.

To enable screenshots, pass the capture function from your app:

import { captureScreen } from 'react-native-view-shot';

initZanbug({
  /* … */
  screenshot: { capture: () => captureScreen({ format: 'png', result: 'base64' }) },
});

Why you pass storage and screenshot in

Metro resolves require at build time. If this package imported @react-native-async-storage/… or react-native-view-shot itself, every app that does not install them would fail to build — not at runtime, where a try/catch could help, but at bundling, where nothing can. So the SDK depends on neither and takes them as arguments.

Identifying the user

import { setUser, setContext, addBreadcrumb } from '@zanbug/react-native';

setUser({ id: 42, email: '[email protected]' });
setContext({ cart_items: 3 });
addBreadcrumb({ category: 'checkout', message: 'Pressed pay' });

Options

| Option | Default | What it does | |---|---|---| | apiKey | — | Project key from the Zanbug panel. Without it the SDK is a silent no-op. | | host | — | Your Zanbug server. | | release / environment | — | Shown on every event; release is what tells you which build introduced a bug. | | storage | — | AsyncStorage-compatible object; enables the offline queue. | | screenshot | — | { capture } — enables PNG capture. | | captureHttp | true | Wrap fetch / XHR. | | httpIgnoreUrls | [] | Substrings or RegExps that must never be reported. | | maxBreadcrumbs | 30 | Ring buffer size. | | beforeSend | — | Last chance to edit or drop an event; return null to discard. |

Compatibility

Verified by building real apps, not by inspection:

| | | |---|---| | React Native 0.71.19 (Metro 0.73, React 18.2) | bundles, /mask subpath included | | React Native 0.76.5 (Metro 0.81, React 19) | release APK, full behaviour on a device | | Expo 57 / RN 0.86 | expo export — 590 modules, 1.5 MB Hermes bundle |

The SDK never throws. A network failure, a malformed response or a missing permission ends as a dropped report, never as a crash in your app.

Privacy

Query-string secrets are redacted before a URL is stored, request and response bodies are never collected, and screenshots are masked in the app before the image exists. Everything is sent to your server — there is no third party in the path.


Part of the Zanbug SDK family: @zanbug/js (core), @zanbug/node, @zanbug/express, @zanbug/nestjs, @zanbug/next, @zanbug/react, @zanbug/vue.

MIT © Zanbug