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

hazo_umetrics

v0.1.2

Published

Product analytics for hazo apps — GA4 hybrid + first-party stat store + feature flags

Downloads

281

Readme

hazo_umetrics

Product analytics for hazo apps — GA4 hybrid + first-party stat store + feature flags.

Gives every hazo Next.js app one consistent, auth-gated way to understand user behaviour:

  • GA4 hybrid — traffic, SEO, and conversion funnels read via the GA4 Data API; auto-provisioned via GA4 Admin API (M1).
  • Stat store — first-party numeric metrics over time, collector pattern, sparkline history.
  • Feature flags — deterministic weighted-variant bucketing, signed consent cookie, sticky assignment.
  • A/B experiments — same engine as flags + significance (deferred until traffic justifies it).

All surfaces mount inside hazo_admin via the existing kind:'metrics' section; every read/write is scope_id-gated.

Status

M0 Core shipped. M0 Interactive test-app is live (Admin Mount, Event Log, Metrics, Autotest). See design/master_plan.md.

Installation

npm install hazo_umetrics

Peer dependencies (install the ones you use):

npm install hazo_core hazo_connect hazo_auth hazo_secure hazo_audit hazo_api hazo_ui hazo_dataviz

The hazo_umetrics/ui panel renders its trend chart with hazo_dataviz (the chart primitives moved out of hazo_ui in the hazo_ui 4.0.0 migration), so install hazo_dataviz when you use MetricsPanel/StatTrend.

Required env vars for cookie signing (A/B assignment):

HAZO_UMETRICS_COOKIE_KEY_CURRENT=v1
HAZO_UMETRICS_COOKIE_KEY_v1=<base64-encoded 32-byte AES-256 key>

Entry points

| Import path | Contents | |---|---| | hazo_umetrics | Server: recordStat, getLatestStat, getStatSeries, resolveVariant, weightedBucket, GA4/experiment stubs | | hazo_umetrics/api | Route factories: createStatHandlers, createExperimentHandlers, createGa4ConnectHandlers, createQueryHandlers | | hazo_umetrics/client | Client: HazoMetricsProvider, useMetrics, getVariant, isEnabled, identify, recordStat | | hazo_umetrics/ui | UI: MetricsPanel, StatCards, StatTrend (uses hazo_dataviz LineChart — requires hazo_dataviz peer dep) |

Stat store

import { recordStat, getLatestStat, getStatSeries, registerStatCollector, runStatSnapshot } from 'hazo_umetrics';

// Append a reading (always inserts, never upserts)
await recordStat(adapter, { scope_id: 'my-app', metric_key: 'active_users', value: 42 });

// Latest value
const stat = await getLatestStat(adapter, { scope_id: 'my-app', metric_key: 'active_users' });

// Series (ascending by captured_at)
const series = await getStatSeries(adapter, { scope_id: 'my-app', metric_key: 'active_users', limit: 30 });

// Register a collector (runs in runStatSnapshot)
registerStatCollector({
  key: 'active_users',
  label: 'Active users',
  format: 'count',
  collect: async (scope_id) => countActiveUsers(scope_id),
});

// Run all collectors (call on a schedule via hazo_jobs in M1)
const results = await runStatSnapshot(adapter, { scope_id: 'my-app' });

Feature flags

import { resolveVariant, getVariant, isEnabled } from 'hazo_umetrics';

// Evaluate a flag with logged-in user (sticky assignment)
const { variant } = await resolveVariant(adapter, {
  experimentKey: 'new_dashboard',
  scope_id: 'my-app',
  subjectId: user.id,
  consent: true,
});

// Boolean flag shorthand
const enabled = await isEnabled(adapter, { experimentKey: 'new_feature', scope_id, subjectId });

API route factories

import { createStatHandlers, createExperimentHandlers } from 'hazo_umetrics/api';

const statHandlers = createStatHandlers({ getAdapter: () => myAdapter });
// → statHandlers.getStat, statHandlers.getStatSeries, statHandlers.recordStat

const expHandlers = createExperimentHandlers({ getAdapter: () => myAdapter });
// → expHandlers.listExperiments (metrics.view), expHandlers.startExperiment (metrics.manage)

DB setup

Run db_setup_sqlite.sql (SQLite) or db_setup_postgres.sql (PostgreSQL) once. Creates 7 tables, all prefixed hazo_umetrics_.

Config

Copy config/hazo_umetrics_config.ini.sample to hazo_umetrics_config.ini and fill in values. Sections: [env], [ga4], [stats], [ab_cookie], [retention].

Tailwind / shadcn setup for UI components

MetricsPanel renders inside HazoUiDialog and uses shadcn token classes (bg-background, text-muted-foreground, etc.). If those tokens aren't defined, the dialog panel will appear transparent. In your globals.css:

@import "tailwindcss";
/* shadcn tokens — required for bg-background, border, muted colors etc. */
@import "../node_modules/hazo_ui/dist/styles.css";

@source "../node_modules/hazo_umetrics/dist";
@source "../node_modules/hazo_ui/dist";
@source "../node_modules/hazo_dataviz/dist";  /* StatTrend's LineChart lives here */

/* Tailwind v4 — map tokens to utilities */
@theme inline {
  --color-background: hsl(var(--background));
  --color-foreground: hsl(var(--foreground));
  --color-muted-foreground: hsl(var(--muted-foreground));
  --color-border: hsl(var(--border));
  /* add remaining tokens as needed — see hazo_ui/dist/styles.css for the full list */
}

(Adjust @import and @source depth to match your project's distance from node_modules.)