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

@siteplane/analytics

v0.1.23

Published

The public Siteplane Analytics SDK for explicitly instrumented React and Next.js websites, whether they are operated directly or managed for a client.

Readme

@siteplane/analytics

The public Siteplane Analytics SDK for explicitly instrumented React and Next.js websites, whether they are operated directly or managed for a client.

The stable import surfaces are:

  • @siteplane/analytics for the browser SDK.
  • @siteplane/analytics/server for server-side events.
  • @siteplane/analytics/react for React integrations.

The current SDK candidate starts disabled and reads site approval from GET /api/analytics/config on the explicitly configured collector origin. Site approval and the visitor's stored choice are separate gates. A server clock up to ten seconds ahead is accepted without extending the 60-second lease or the response's shorter lifetime. Expiry, revocation and visitor consent still close the measurement gate.

This package is under active pre-release development. Production use is gated by Siteplane Plan 19 and its published release evidence.

Supported environments

  • Node.js 20 and 22 for @siteplane/analytics/server.
  • Next.js 15 and 16.
  • React 19 for @siteplane/analytics/react.
  • Current Chromium, Firefox and WebKit for the browser SDK.

The root export is browser-safe and framework-independent. The server export does not read browser globals. Analytics starts disabled until fresh server approval and the visitor's decision permit tracking.

Canonical setup

Use the public Siteplane CLI from an existing initialized project:

npx -y siteplane@latest analytics init --agent-client codex
npx -y siteplane@latest analytics check
npx -y siteplane@latest analytics sync
npx -y siteplane@latest analytics test --page-url https://example.com

Provider imports use normalized UTF-8 JSON. The default command is a dry-run; apply additionally requires --apply --confirm-hash <hash> --yes and a live, owner-approved analytics:import grant on the existing Project Connection.

Browser tracking contract

Configure the public key and collector endpoint:

const analytics = initSiteplaneAnalytics({
  siteKey: process.env.NEXT_PUBLIC_SITEPLANE_ANALYTICS_SITE_KEY!,
  endpoint: "https://siteplane.io/api/analytics/collect"
});

The initializer has no siteMode option. The SDK keeps approval only in memory for up to 60 seconds, refreshes every 30 seconds in visible tabs and checks again on page return. A failed or expired response clears queued events and active identifiers without changing the visitor's saved choice. Approval captures the current page; actions taken while disabled are discarded.

endpoint is required. The browser SDK does not infer a collector from the customer website origin. It sends normal scheduled and explicit flushes with fetch, evaluates the HTTP status and uses sendBeacon only as a best-effort pagehide delivery path.

The SDK adds installationGeneration and measurementMode to live browser events. The collector requires those fields and verifies the current approval again at the database write. They are permission metadata, not visitor identity. The SDK exposes no setter for the installation generation.

Each request contains at most 50 events and its actual UTF-8 JSON body is strictly smaller than 64 KiB. Event IDs are created once before the first send and stay stable across chunking and retries. Network failures, 429 and 5xx receive at most three attempts with exponential backoff and jitter; Retry-After is honored. Events that remain transiently unsent return to the in-memory queue unless approval expires, consent changes, opt-out or disposal clears it. Permanent 4xx responses are not retried and can be observed through the typed onDiagnostic callback.

session_only uses a session ID in sessionStorage and no persistent visitor ID. full_analytics stays at consent_required until the visitor makes an explicit compatible choice:

analytics.setConsent("full_analytics");
analytics.setConsent("session_only");
analytics.optOut();

For a website with an existing CMP, pass consentAdapter to the initializer. Its getConsent() returns unknown until that CMP has resolved the visitor's choice, disabled for rejection, or session_only / full_analytics for an actual grant. subscribe(onChange) must notify on every choice change and return an unsubscribe function. The SDK reads the current choice after subscribing and on each callback; read or subscription failures block measurement. Dispose the SDK when its owning client component unmounts.

CMP grants are capped by the server-approved site mode and any more restrictive Siteplane choice. They do not overwrite Siteplane consent records; an existing Siteplane opt-out still requires a new explicit Siteplane choice. Do not copy a CMP snapshot into setConsent. Unknown/denied CMP state clears queued events and IDs without inventing a Siteplane denial tombstone. When access becomes allowed, only the current pageview and new actions are captured. Server pause and preview suppression remain independent gates.

Omit the adapter only after checking that the website has no existing CMP. An unrecognized CMP needs its actual callbacks connected before Analytics is ready; a constant grant or no-op adapter is not a verified integration. This adapter is part of the unreleased Batch 2 candidate; integrated product acceptance is pending.

Visitor and session IDs are generated internally as cryptographically random, fixed-format opaque values. The public SDK exposes no identity setter or identity injection option; the collector validates the format and persists only site-scoped HMAC pseudonyms, never the browser values themselves.

Positive choices and anonymous visitor IDs are versioned localStorage records with a maximum lifetime of 180 days. Reject/optOut() first stores a durable denial tombstone and then clears the in-memory queue, acquisition context, session ID and visitor ID. enable() never overrides that tombstone; the visitor must make a new explicit choice. If required browser storage is missing or blocked, the SDK fails closed without sending a request or creating an identifier.

The optional vanilla and React consent banners show equal Accept and Reject actions and accept a configurable privacyPolicyUrl. They are integration templates, not replacements for an existing CMP or legal review.

Public opt-out is local SDK behavior on the customer website origin. The Siteplane app cannot clear another origin's storage and exposes no anonymous retrospective visitor-delete endpoint. Owner/admin/compliance deletion is a separate protected workflow; anonymous opt-out does not remove preserved aggregates.

Browser URLs and referrers never retain query strings or fragments. Known route templates are preferred; otherwise e-mail, UUID, token/JWT and high-entropy path segments are replaced with :redacted. Only bounded non-sensitive UTM values and event-specific property allowlists survive both client and server sanitization. Raw form values, names, e-mail addresses, phone numbers, messages, auth fields and full destination URLs are discarded.

installDataAttributeTracking sends section views only after a valid section target is at least 50% visible for 500ms. Form starts are emitted once per form and route view, while native validation errors are captured and deduplicated per submit attempt. The SDK never prevents the website's own form handlers.

Every browser event receives the current normalized page path, known route template, sanitized referrer and the acquisition UTMs captured when the SDK was initialized. Next.js App Router sites should call the explicit adapter from a client component whenever usePathname() changes:

const navigation = createNextAppRouterNavigationAdapter({
  setPageContext: analytics.setPageContext,
  trackPageView: () => analytics.track("page_view")
});

navigation.trackNavigation({
  pathname,
  routeTemplate: pathname,
  search: window.location.search
});

Pass analytics.getRouteViewId to installDataAttributeTracking, call attributes.refresh() after an App Router transition, and dispose both the attribute tracker and Analytics instance on unmount. Generic React apps may use the History API fallback instead.

Siteplane editor URLs carry siteplaneSessionId, siteplaneAdminOrigin and siteplanePreview=1. The SDK suppresses measurement before generating IDs or sending events in that context and validates later bridge messages against both the parent window and expected admin origin. The separately authorized RuntimeBridge readiness probe remains a test path; it does not enable regular preview tracking.

Server tracking contract

Import the server-only entry point and pass an absolute HTTP(S) collector endpoint explicitly:

import { trackServer } from "@siteplane/analytics/server";

const result = await trackServer(
  {
    event: "lead_created",
    siteKey: process.env.SITEPLANE_ANALYTICS_SITE_KEY,
    secretKey: process.env.SITEPLANE_ANALYTICS_SECRET_KEY,
    targetId: "contact_form",
    targetType: "conversion",
    idempotencyKey: "lead:123",
    properties: {
      conversion_id: "contact_form"
    }
  },
  {
    endpoint: "https://siteplane.io/api/analytics/collect",
    timeoutMs: 5000
  }
);

The default timeout is five seconds. Network failures, 429 and 5xx use the same bounded three-attempt retry contract and honor Retry-After. The event ID and serialized request remain stable across attempts. Use a stable idempotencyKey for any retryable mutation; revenue events require it. Auth, permanent collector, unavailable collector and network failures return typed error codes instead of silently succeeding.

Owner activation checks

Version 0.1.22 handles Siteplane's short-lived owner test link during the normal SDK initialization. The temporary test tab sends one authorized runtime receipt and stays entirely outside visitor tracking, storage and consent writes. The editor iframe supplies its own separate suppression receipt. Ordinary website visits never enter this test path. Do not add custom probe code or copy test links into source or logs.