telemetry

Define and collect telemetry events and traces from Sanity CLI, Studio, and other TypeScript apps.

Library
npm
v1.1.0
1stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
36/100Needs Attention
Development Activity48
Maintenance32
Community12
Maturity52
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
58/100Fair
Architecture68
Code Quality62
Innovation48
Learning Curve55

@sanity/telemetry is a small TypeScript library for instrumenting applications with typed, versioned telemetry events and multi-step traces. Rather than hard-wiring an app to a specific analytics vendor, it exposes a store you configure with your own consent-resolution and event-delivery strategies, then hands application code a logger with log() and trace() methods to call.

It originated as the shared telemetry layer for the Sanity CLI and Sanity Studio, where the same event needs to be logged consistently from many entry points without each one knowing about consent state, session identity, or batching. The library builds on RxJS internally to buffer events, throttle flush intervals, and retry failed submissions, while keeping the public API deliberately small: defineEvent, defineTrace, createBatchedStore, and a React provider/hook pair for component-level usage.

What You Get

  • defineEvent() and defineTrace() helpers for declaring versioned, typed telemetry schemas ahead of time
  • A createBatchedStore() factory that buffers events, throttles flushes on a configurable interval, and retries failed submissions
  • Pluggable resolveConsent and sendEvents strategies so the library stays agnostic about the analytics backend and consent UI
  • Trace contexts via newContext() that propagate caller information through shared helper functions without those functions needing telemetry awareness
  • A React integration (@sanity/telemetry/react) with TelemetryProvider and useTelemetry() for component-level logging
  • Browser lifecycle handling (registerLifecycleEvents, endWithBeacon) to flush pending events before a tab closes or navigates away

Common Use Cases

  • Logging feature usage and session events from the Sanity CLI and Sanity Studio
  • Tracking multi-step user flows (e.g. search, onboarding) as traces with start/log/complete/error states
  • Wrapping a shared helper function (like a login routine) so telemetry context flows through it without coupling the helper to any specific caller
  • Collecting client-side usage data in a browser app with consent gating and beacon-based flush on unload

Under The Hood

Architecture The core is createStore(), a small event-bus built on an RxJS Subject that turns log()/trace() calls into typed TelemetryEvent objects on an observable stream. createBatchedStore() wraps that store with buffering, throttled flush timing, and retry-on-failure logic composed from RxJS operators (throttle, concatMap, mergeMap, catchError), while index.ts and the react/ subdirectory re-export the same store contract for plain TypeScript and React consumers respectively. Data flows one way — call site to Subject to in-memory buffer to periodic submit() to the consumer-supplied sendEvents() — with no dependency-injection framework; composition is purely functional closures. Because both the CLI and the React provider build on the same TelemetryStore shape, changing that core contract would ripple through every consumer at once.

Tech Stack Written in TypeScript targeting ES2020 with bundler module resolution, the package’s only runtime dependencies are RxJS (event stream plumbing) and typeid-js (trace ID generation); React is an optional peer dependency used solely by the react/ entry point. It’s built with @sanity/pkg-utils into dual CJS/ESM bundles with generated type declarations, tested with Vitest, linted with ESLint/Prettier, managed as a pnpm workspace package, and released via release-please GitHub Actions automation with Renovate keeping dependencies current.

Code Quality Tests live under src/__test__ using Vitest, exercising createBatchedStore and createDeferredStore end-to-end with mocked sendEvents/resolveConsent callbacks and real timers, favoring integration-style toMatchObject assertions over isolated per-function unit tests. Strict TypeScript settings (strict, strictNullChecks, noImplicitAny) are enabled project-wide, and naming is consistent across factory functions (createXStore, defineX). No dedicated CI test workflow is visible in .github/workflows (only a release-please workflow), and inline documentation comments are sparse and inconsistently applied across exported functions.

API Design The public surface is deliberately small: defineEvent()/defineTrace() declare typed, versioned schemas ahead of time, and a single logger object exposes log()/trace() for actually recording data. Nothing is batteries-included — integrators must supply their own resolveConsent() and sendEvents() implementations before any event reaches a backend, which adds upfront work but keeps the library vendor-neutral. The React integration (useTelemetry()) mirrors the vanilla logger shape closely, minimizing relearning across environments, and the examples/ directory ships runnable CLI and React sample apps alongside a single README rather than generated API docs.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search