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

crumbtrail-capacitor

v0.39.0

Published

Capacitor and Ionic SDK for Crumbtrail: adds device, app lifecycle, connectivity and deep link context to the web capture already running in the WebView. See https://crumbtrail.ai

Readme

crumbtrail-capacitor

Capacitor and Ionic SDK for Crumbtrail session capture.

A Capacitor app is a real web app running in a native WebView, so crumbtrail-core already captures console, errors, network, user interactions and DOM replay with no help from this package. What this package adds is the half of a phone bug that a WebView cannot see: which device and OS build, which app version, whether the app was backgrounded mid request, what the radio was doing, which deep link opened the screen, and which way the phone was being held.

Install

Fastest path: the setup wizard

From your app's root:

npx crumbtrail

The wizard detects a Capacitor app by the presence of a @capacitor/core dependency, installs crumbtrail-core and crumbtrail-capacitor with your project's package manager, and prepends a createCapacitorCrumbtrailAsync(...) block to your web entry: the module your root index.html loads for a Vite based app (Ionic React, Ionic Vue, vanilla), or src/main.ts for Ionic Angular.

By hand

npm install crumbtrail-core crumbtrail-capacitor

Setup

import { createCapacitorCrumbtrailAsync } from "crumbtrail-capacitor";

createCapacitorCrumbtrailAsync({
  config: {
    httpEndpoint: "https://api.crumbtrail.ai",
    httpAuthToken: import.meta.env.VITE_CRUMBTRAIL_KEY,
    remoteConfig: true, // take the kill switch and capture settings from the project
    service: "app",
  },
}).catch(() => {});

Put this at the top of your web entry, before your app bootstraps.

Ionic Angular has no browser safe environment variable mechanism. Add the key to src/environments/environment.ts and read it from there instead:

import { environment } from "./environments/environment";

createCapacitorCrumbtrailAsync({
  config: {
    httpEndpoint: "https://api.crumbtrail.ai",
    httpAuthToken: environment.crumbtrailKey,
    remoteConfig: true,
    service: "app",
  },
}).catch(() => {});

Why the async form

createCapacitorCrumbtrailAsync reads any session id persisted by a previous launch before it initialises. Without that step every cold start opens a new session, so a bug a user hits once a day arrives as a series of unrelated single event sessions rather than one recurring signature.

A synchronous createCapacitorCrumbtrail is exported for cases where you cannot await anything at startup. It gives up cross launch session continuity.

Native context comes from optional plugins

Every plugin below is optional. The SDK detects what is installed, reports it, and collects what it can. Installing none of them leaves you with web capture only, which is the phone shaped blind spot this package exists to close.

| Plugin | What it adds | | --- | --- | | @capacitor/app | Foreground and background transitions, cold start launch URL, deep links, Android hardware back presses, OS restored plugin results | | @capacitor/device | Model, manufacturer, OS version, WebView version, memory and disk, battery level | | @capacitor/network | Connectivity at start and every change, including blips that produce no failed request | | @capacitor/preferences | Session continuity across cold starts | | @capacitor/screen-orientation | Portrait and landscape at the moment of the bug |

npm install @capacitor/app @capacitor/device @capacitor/network @capacitor/preferences
npx cap sync

npx cap sync is required. Without it the native projects do not pick the plugins up, and the SDK reports them absent.

Passing plugins explicitly

The SDK resolves plugins at runtime, which works in a development build. Bundlers cannot see through that indirection, so a production build can drop the modules and leave the lookup empty even though the plugins are installed and working. If your app already imports them, pass them in:

import { App } from "@capacitor/app";
import { Device } from "@capacitor/device";
import { Network } from "@capacitor/network";
import { Preferences } from "@capacitor/preferences";

createCapacitorCrumbtrailAsync({
  plugins: { App, Device, Network, Preferences },
  config: { /* … */ },
}).catch(() => {});

What gets captured

Native context is emitted as ordinary Crumbtrail events alongside everything the web collectors produce, so it lands in the same session timeline.

| Event | When | | --- | --- | | env | Once at startup: runtime, device, app version, battery, locale. Again on each rotation. | | app-lifecycle | Initial state, every foreground and background transition, native pause and resume, OS restored plugin results | | net-status | Connectivity at startup and on every change | | navigation | The cold start launch URL and every deep link opened while running | | nav-intent | Android hardware or gesture back presses | | capacitor.capabilities | Once at startup: which plugins were found |

Events are tagged with the concrete platform, ios or android, rather than a flat webview, so a session can be filtered to one OS. That matters because WKWebView and the Android System WebView disagree about storage eviction, back navigation and media autoplay, and a large share of hybrid bugs are on exactly one of them.

The Android back button listener observes the press and does nothing else. It never calls preventDefault or exits the app.

Defaults

The web collectors are left exactly as crumbtrail-core ships them, with two exceptions: video and audio capture default to off. They are the most expensive collectors to run and the most expensive to upload, and a phone is constrained on battery and cellular data in a way a desktop tab is not. Turn them back on through config if you want them.

Configuration

createCapacitorCrumbtrailAsync({
  // Core capture config, passed straight through to Crumbtrail.init.
  config: { /* … */ },
  // Plugin instances, if you would rather not rely on runtime resolution.
  plugins: { App, Device },
  // Disable native collectors wholesale, or one at a time.
  collectors: { orientation: false },
  // Skip the startup capabilities report.
  reportCapabilities: false,
  // Override the reported platform tag.
  platform: "ios",
});

Collector names: environment, appLifecycle, network, deepLinks, backButton, orientation.

Teardown

const { logger } = await createCapacitorCrumbtrailAsync({ /* … */ });
await logger.stop(); // also removes every native plugin listener

License

MIT