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

@crimson-education/browser-logger

v5.0.11

Published

An abstract logger and reporting utility for browser environments

Readme

Crimson Education Browser Logger

A structured logger and analytics reporting utility for browser environments.

This library contains a number of reporters that is will send analytics to.

These must be enabled by calling Logger.init(), as seen below.

Note: This library has been upgraded to support Node.js 22. Some features have been removed or modified during the upgrade process. See the Upgrade Notes section for details.

!!IMPORTANT NOTICE: for the legacy lib of Datadog V4.X and others, please see the main branch, this is the one upgraded.

Install

npm i @crimson-education/browser-logger

or

yarn add @crimson-education/browser-logger

For new frontend applications, including Replit-hosted applications, follow the frontend integration guide. It defines the recommended split between Datadog Logs, PostHog product analytics, and allowlisted session replay.

Usage

Initialize

import * as Logger from '@crimson-education/browser-logger';
import { config } from '../configuration';

Logger.init({
  service: 'test-project',
  application: 'crimson-app',
  environment: config.environment,
  version: config.version,
  defaultMetadata: {
    domain: window.location.hostname,
  },

  reporters: {
    log: true,

    gtm: true,

    datadog: {
      applicationId: config.datadogApplicationId,
      clientToken: config.datadogClientToken,
      site: config.datadogSite,
      proxyUrl: config.datadogTunnelProxyUrl,
      version: config.datadogVersion,

      sampleRate: config.environment === 'production' ? 50 : 0,
      replaySampleRate: config.environment === 'production' ? 50 : 0,

      forwardConsoleLogs: true,
      logTransport: {
        level: Logger.LogLevel.Info,
      },
      trackUserInteractions: true,
      allowedTrackingOrigins: ['https://my.api.domain'],
    },

    posthog: {
      apiKey: config.posthogApiKey,
      apiHost: config.posthogApiHost,
      capturePageview: 'history_change',
      replaySampleRate: 0,
    },
  },
});

Logger.setUser({
  id: '123',
  email: '[email protected]',
  name: 'Billy Brown',
});

// Once the user is authenticated.
Logger.recordSession();

Logger.trackEvent({
  name: 'App Loaded',
  metadata: {
    type: 'SPA',
  },
});

export const logger = Logger.createLogger();

// Attributed logging.
logger.info('WOW!', {
  id: 1,
});

Structured Logging

Structured logging in this library is loosely based on Winston, and follows roughly the same interface as @crimson-education/node-logger.

Call Logger.createLogger() to create a logger instance, it is recommended to re-use this as a global logger everywhere, and then call .child() to reuse metadata.

Global metadata about the service will be added for transport usage after calling Logger.init().

You can add more Global Metadata at any time by calling addMetadata().

export const logger = Logger.createLogger();

const log = logger.child({
  from: 'childLog',
});

log.info('My Log', { jobCount: jobs.length });

const timer = log.startTimer();

const result = await job(jobs);

timer.done({ message: 'Job Completed', metadata: { id: result.id } });

Reporting

Opting out of events

You can opt out of sending events to reporters on a global, or per call basis using the endpoints config.

E.g. On calls

Logger.trackEvent({
  message: 'my-event',
  toReporters: ['log', 'datadog'],
  excludeReporters: ['datadog'],
});

E.g. Globally

Logger.init({
  reporters: {
    log: true,
    datadog: {
      ...
      endpoints: {
        trackEvent: false,
      }
    }
  }
});

These will only send to the log reporter, it is recommended to use toReporters or excludeReporters separately as they overlap.

Filtering out metadata

You can filter what metadata gets sent to each reporter in the reporter config. This accepts a string for exact match metadata keys, or a RegExp. You can use . to traverse metadata.

Logger.init({
  reporters: {
    log: {
      ignoreMetadataPatterns: ['internalError', 'user.email', /error\.stack.*/g],
    },
  },
});

Filtering out Breadcrumb categories

You can filter what breadcrumbs get sent to reports in the reporter config.

Logger.init({
  reporters: {
    log: {
      ignoreBreadcrumbCategories: [
        'fetch'
      ]
    }
  }
});

// Not sent to the log reporter.
Logger.addBreadcrumb({
  ...
  category: 'fetch',
});

Configure Reporters

Proxies

Some reporters support taking a proxyUrl parameter in their config. When provided, the reporter will send events to the proxyUrl instead of the default destination. This can be useful to get around ad blockers users might have installed. Typically, proxyUrl should point to our internal proxy service--a shared service that forwards requests it receives to a third-party system.

Our internal proxy service is defined in our crimson-infrastructure repository.

Log

By default, the log reporter is enabled. This adds all reporter functions to logs. Set reporters.log to false to disable reporter logging.

import { config } from '../configuration';
import * as Logger from '@crimson-education/browser-logger';

Logger.init({
  reporters: {
    log: {
      trackEventLevel: Logger.LogInfo.Debug,
      endpoints: {
        recordSession: false,
        recordSessionStop: false,
      },
    },
  },
});

Check out the DatadogReporterConfig for all of the configuration you can apply to Datadog reporting.

Datadog

To configure Datadog, this requires at least applicationId, clientToken and site (As we use an EU instance).

import { config } from '../configuration';
import * as Logger from '@crimson-education/browser-logger';

Logger.init({
  reporters: {
    datadog: {
      applicationId: config.datadogApplicationId,
      clientToken: config.datadogClientToken,
      site: config.datadogSite,
      proxyUrl: config.datadogTunnelProxyUrl,
      version: config.datadogVersion,

      sampleRate: config.environment === 'production' ? 50 : 0,
      replaySampleRate: config.environment === 'production' ? 50 : 0,

      forwardConsoleLogs: true,
      logTransport: {
        level: Logger.LogLevel.Info,
      },
      trackUserInteractions: true,
      allowedTrackingOrigins: ['https://my.api.domain'],
    },
  },
});

Check out the DatadogReporterConfig for all of the configuration you can apply to Datadog reporting.

This automatically adds a Datadog Log Transport that transmits Log data to Datadog, this can be customized in DatadogReporterConfig with logTransport, or disabled by setting logTransport to false.

If you need to keep browser logs while disabling RUM, or vice versa, use the independent Datadog switches:

Logger.init({
  reporters: {
    datadog: {
      applicationId: config.datadogApplicationId,
      clientToken: config.datadogClientToken,
      site: config.datadogSite,
      logsEnabled: true,
      rumEnabled: false,
      logTransport: {
        level: Logger.LogLevel.Info,
      },
    },
  },
});

logsEnabled only affects Datadog Browser Logs and the Datadog log transport. rumEnabled only affects Datadog Browser RUM, browser actions, view tracking, error reporting, and replay controls.

PostHog

To configure PostHog, this requires at least apiKey and apiHost.

import { config } from '../configuration';
import * as Logger from '@crimson-education/browser-logger';

Logger.init({
  reporters: {
    posthog: {
      apiKey: config.posthogApiKey,
      apiHost: config.posthogApiHost,
      capturePageview: 'history_change',
      replaySampleRate: 0,
      trackViewsManually: false,
    }
  }
});

replaySampleRate is provided as a compatibility alias for existing Datadog-style config. Values less than or equal to 0 disable session recording at startup, while Logger.recordSession() can still enable replay later for allowlisted users.

For an authenticated SPA whose initial Page View must carry the final user identity, set captureInitialPageviewOnIdentify: true. The reporter drops automatic Page Views until the first valid Logger.setUser(...), then emits the current page once with that identity. Keep normal capturePageview: 'history_change' enabled so subsequent navigation remains automatic. Do not enable this for public or anonymous flows where pre-login views are intentionally retained.

When multiple repos write into the same PostHog project, prefer setting application at Logger.init(...). This ensures a stable product-level dimension is present on all events independently of each app's service name.

Person Profile processing defaults to never. Authenticated user fields are still registered on events, but PostHog does not create billable Person Profiles. Applications that require PostHog cohorts, lifecycle analysis, or person-property targeting must explicitly set personProfiles: 'identified_only' and account for identified-event pricing.

In anonymous mode, the reporter continuously enforces anonymous event delivery. It clears identity state left by an earlier identified setup whenever that state is detected, drops person mutation events, removes person-property updates, and applies anonymous billing flags after consumer beforeSend hooks. A cleanup changes the PostHog distinct ID and session boundary, but stable user_id, user_email, user_name, and user_role event properties remain available for warehouse reporting. migratePersistedIdentifiedState: false disables the identity-state reset only; events are still sent without person processing while personProfiles is never.

Migration uses explicit identified-state markers, not inequality between device and distinct IDs: PostHog preserves the former and rotates the latter on an anonymous reset. Repeated normal events must not reset the session or restart replay. Explicit logout still resets identity; the existing replay opt-in policy and anonymous event-billing enforcement are unchanged.

Filtering technical analytics noise

Logger.trackEvent() still fans out to every enabled reporter. If a repo wants to keep technical log noise in the log reporter while excluding it from Datadog RUM or PostHog, configure ignoreTrackEventPatterns explicitly in that reporter.

Example:

Logger.init({
  reporters: {
    datadog: {
      applicationId: config.datadogApplicationId,
      clientToken: config.datadogClientToken,
      site: config.datadogSite,
      ignoreTrackEventPatterns: [
        'TIM_LOGIN_SUCCESS',
        /^TIM_MESSAGE_RECEIVED:/,
        /^feedback fetch (triggered|deduped inflight|skipped ttl|success)$/,
      ],
    },
    posthog: {
      apiKey: config.posthogApiKey,
      apiHost: config.posthogApiHost,
      ignoreTrackEventPatterns: [
        'TIM_LOGIN_SUCCESS',
        /^TIM_MESSAGE_RECEIVED:/,
      ],
    },
  },
});

Google Tag Manager

To configure GTM, you will need to have loaded the GTM script into your App. See: https://support.google.com/tagmanager/answer/6103696?hl=en

import { config } from '../configuration';
import * as Logger from '@crimson-education/browser-logger';

// No configuration
Logger.init({
  reporters: {
    gtm: true,
  },
});

// With configuration
Logger.init({
  reporters: {
    gtm: {
      ignoreBreadcrumbCategories: ['fetch'],
    },
  },
});

Check out the GTMReporterConfig for all of the configuration you can apply to Google Tag Manager reporting.

Functions

See the src/logger/index.ts file for all exported functions of the Logger. See the src/reporter/index.ts file for all exported functions of the Reporter.

Improve Session Tracking with Component names

You can improve the name of components in analytics tools like Datadog, instead of using the content of a component. This is valuable if the content is dynamic, e.g. a user's name:

<div data-analytics-name="MyUserName">Billy Brown</div>

This will result in the session saying something like, clicked on "MyUserName".

Upgrade Notes

Node.js 22 Upgrade Changes

This library has been upgraded to support Node.js 22. The following changes were made during the upgrade process:

Datadog Reporter Changes

  • trackInteractionstrackUserInteractions (renamed for clarity)
  • trackFrustrations → Removed (replaced with custom frustration detection implementation)
  • allowedTracingOriginsallowedTrackingOrigins (corrected spelling)

Removed Features

The following features were removed during the upgrade and have been replaced with custom implementations:

  1. Automatic Frustration Detection: Replaced with custom implementation that detects:

    • Rapid clicks (potential frustration)
    • Form validation errors
    • 404 and network errors
  2. Enhanced Auto-tracking: Replaced with custom implementation that tracks:

    • Page views and route changes
    • User interactions with analytics-enabled elements
    • Session state changes (active/inactive)

Configuration Updates Required

If you're upgrading from a previous version, update your configuration:

// Old configuration
datadog: {
  trackInteractions: true,
  trackFrustrations: true,
  allowedTracingOrigins: ['https://my.api.domain']
}

// New configuration
datadog: {
  trackUserInteractions: true,
  allowedTrackingOrigins: ['https://my.api.domain']
  // trackFrustrations is now handled automatically
}

For more details about the upgrade process and custom implementations, see the individual reporter configuration files.