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

@kortyx/usage-telemetry

v0.6.0

Published

Bounded, privacy-preserving product usage telemetry for Kortyx.

Readme

Kortyx usage telemetry

Maintainer usage telemetry measures adoption and reliability of the SDK, CLI and OSS Studio. It is separate from customer observability in @kortyx/telemetry and @kortyx/otel. The default destination is Kortyx's EU PostHog Production project, using its public capture key. Consumers need no personal API token.

Controls

Set these in the SDK process or Studio deployment environment. CLI-generated Compose forwards the same controls to API, Studio and updater containers; restart the containers after changing them.

| Variable | Effect | | --- | --- | | KORTYX_USAGE_TELEMETRY_DISABLED=1 | Stops collection, identity creation and queued delivery; true is also accepted | | KORTYX_USAGE_TELEMETRY_DEBUG=1 | Prints approved records locally, without creating identities or sending requests | | KORTYX_USAGE_TELEMETRY_POSTHOG_KEY | Overrides the public phc_ capture key, for example for maintainer staging | | KORTYX_USAGE_TELEMETRY_POSTHOG_HOST | Overrides the ingestion host; defaults to https://eu.i.posthog.com | | KORTYX_USAGE_TELEMETRY_ENDPOINT | Replaces PostHog with a collector accepting { identity, records } | | KORTYX_USAGE_TELEMETRY_ENVIRONMENT=staging | Labels maintainer staging; pair it with that project's capture key | | KORTYX_USAGE_TELEMETRY_TRAFFIC_SOURCE | Explicit internal, synthetic or external cohort; otherwise unknown. CI does not imply synthetic traffic | | KORTYX_USAGE_TELEMETRY_ID | Optional random UUID for deliberate identity sharing between Node processes |

Tests (NODE_ENV=test) disable the default Node integration. Consumer NODE_ENV and CI supply a coarse runtime mode; they do not select the maintainer project. Browser bootstrap receives only public configuration from Studio's server environment, so no NEXT_PUBLIC_ variables are needed. Debug output contains approved dimensions and aggregate counts, never application payloads.

Node delivery lazily stores a random installation UUID in ~/.config/kortyx/usage-id (new directory mode 0700, file 0600). Read-only installations use a process UUID instead. Removing the file resets the identity after restarting the process. Browsers lazily store a separate random UUID in local storage at kortyx.usage.id, falling back to an in-memory UUID if storage is unavailable. Clear this key and reload to reset it. Browser/server identities are independent; they do not establish a cross-product funnel. These are pseudonymous identifiers, not people or authenticated accounts.

Approved data and bounded delivery

The shared catalog allows fixed operation names, outcome enums, Kortyx release versions, provider families, storage/transport kinds, coarse HTTP status, known error codes and booleans. Arbitrary property keys are dropped; unrecognized enum values and error codes become other. The error projection reads only own data properties and does not invoke application getters.

Sample chapters use the bounded studio.sample chapter/step catalog, including optional error-diagnostics and evaluation-progress. Optional starts/completions have their own chapter denominator and do not increase the six-chapter full-tour denominator. Completion is a displayed-guide outcome, not proof of learning.

Studio page explanations use studio.help with finite help_page, help_step, help_context (real/sample), and help_action values. Starts count explanation attempts; step events count displayed steps, including Back. Completion, skip, exit, error, and example request/accept/cancel distinguish local help from a confirmed sample transfer. Compare completions against starts within the same page/context cohort, accounting for best-effort delivery and abandoned tabs. Record identifiers, URLs, selectors, setting values, and page content are excluded. Page-help facts are allowed in sample views while ordinary execution metrics remain suppressed; they do not measure SDK activation or customer execution outcomes.

Prompts, inputs/outputs, messages, schemas, workflow/node/tool names, URLs, paths, custom application error codes, customer IDs, credentials, raw errors and stacks are excluded. Capture requests omit browser cookies and referrers, disable PostHog person profiles and geolocation enrichment, and send $ip: null. Network infrastructure still receives a request's source IP; the payload is not proof of legal anonymity. There is no autocapture, session replay or global exception handler.

Records aggregate matching operations, outcomes and approved dimensions over a 60-second flush window. A scope finishes once. Successes and failures use the same counting policy. usage.operation records reliability and duration; usage.feature records deliberate adoption or explicit feature configuration. Background reads/refreshes have separate origins and must not be used as click counts.

Each component client buffers at most 64 distinct groups and sends at most 120 groups per hour. A group can represent many attempts through count. Duration buckets are noncumulative: ≤10ms, (10,100], (100,1,000], (1,000,10,000], (10,000,60,000], >60,000ms. Query duration_total_ms / count for means or combine bucket counts for approximate distributions. Restrict latency queries to usage.operation.

Delivery is best effort, single-flight, with a two-second transport timeout, no retries and unreferenced Node timers. SDK operations never await analytics delivery or change results because collection fails. The CLI flushes registered component clients after command parsing/execution, waiting at most two seconds even for a custom transport. Setup stages and command invocations are separate measurements. Browser visibility changes request a flush. Offline, disabled, terminated or short-lived processes can lose records; call the helper's flush() explicitly at an application-controlled shutdown boundary when appropriate. No disk event queue or crash detection is implied. stats() exposes local pending/dropped/delivered group counts. Budgets are per component and process, not an organization-wide spending guarantee; PostHog's $0 billing limits remain the financial control.

Reusable boundaries

import { createUsageTelemetry, publicCatalog } from '@kortyx/usage-telemetry';

const usage = createUsageTelemetry({
  context: { product: 'sdk', component: 'agent', version: '1.0.0' },
  catalog: publicCatalog,
  identity: () => installationUuid,
  transport: myTransport,
});

const scope = usage.start('sdk.execute');
try {
  const result = await execute();
  scope.end();
  return result;
} catch (error) {
  scope.fail(error);
  throw error;
}

The root export is browser safe. Bundlers use a browser fallback for the Node entry so portable exports from libraries such as prompts keep working without filesystem imports. That fallback collects nothing automatically; browser usage requires the embedding application's explicit bootstrap or component override, as Studio provides. @kortyx/usage-telemetry/node owns filesystem identity, environment controls, EU defaults and a component registry. configureUsageTelemetry(component, client) replaces a component client, including after SDK modules have been imported. Component facades resolve the registry at each boundary. Other distributions extend a catalog with their own bounded products/operations/properties and provide a transport; the public catalog contains only public product facts.

Studio uses the @studio/usage server adapter and @studio/usage-contracts contract, following its existing edition alias pattern. An adapter owns its server client and serializable browser configuration, including an optional extended catalog. Browser configuration chooses one product. configureStudioUsage(config, extensionClient) also accepts a custom browser client. API embedders can pass usage to createApiApp. Never put a personal PostHog token in a browser config or transport.

Workflow reducer adoption

Successful sdk.registry operations carry the boolean data_reducers: whether at least one registered workflow has a callback. Compare sum(count) with the flag enabled against all successful registry operations in the same release cohort to measure configured adoption. This counts registry resolutions, not workflow runs or unique workflows. Registries without a list method cannot establish adoption and omit the property. Repeated agent initialization and best-effort aggregation/delivery affect reach estimates as described above.

Existing execution outcomes allowlist WORKFLOW_REDUCER_FAILED as a known error code for reliability measurement. Reducer field names, callbacks, schemas, values and raw error messages are never usage properties. Existing opt-out, bounded aggregation and failure-independent delivery apply unchanged.

First slice and follow-up opportunities

SDK boundaries include initialization, registry resolution, direct execution/resume, chat admission, terminal graph execution, response completion, model and tool execution, structured output, explicit response completion, prompt resolution, eval outcomes, MCP connection/discovery/close, checkpoint operations and observability export attempts. Early response completion and later graph failure are separate outcomes. An eval quality failure is distinct from an execution error.

Studio boundaries include CLI setup, API requests/ingest, server reads and parse failures, first-use guidance and observed data, navigation, tab/trace inspection, render failures/retries, prompt actions, eval launch/read/cancel and live refresh/reconnect. Prompt and eval browser actions measure request acceptance. The built-in eval worker separately measures persisted terminal results; its attempt and legacy run units are described below. SDK eval configuration rejection is included with phase configuration.

The opportunity inventory covers remaining node/parallel/child execution, prompt cache/refresh, persistence internals, exporter queue loss, deeper filters/saved views, deeper worker phases, reviews and upgrade phases. Reserved catalog operations are not evidence that these boundaries already emit. Feature-flag evaluation and exposure are a future addition.

Use sum(properties.count), rather than raw PostHog event count, to measure attempts. For a comparable component/operation cohort, failure rate is sum(count where outcome = failed) / sum(count for completed operation outcomes). Decide explicitly whether cancellations, denial and suspension belong in the denominator. Compare installation reach, repeated use and failure rate by release; do not rank features solely by workload volume. PostHog funnels over aggregates give coarse observed ordering (flush windows can obscure exact ordering), not exact user-session sequences or time since npm installation.

Measurement quality (version 2)

The envelope remains schema_version: 1; additive approved properties carry measurement_version: "2". Historical events without it retain their old coverage. Compare matching measurement versions, release, component, operation, origin, action, analytics environment and runtime mode. Never add up all SDK operations as workflow executions.

| Unit (measurement_kind) | Counting boundary | | --- | --- | | invocation | One CLI command parse/action outcome or SDK eval run() call, including rejected configuration | | execution | SDK terminal graph execution; persisted legacy worker suite run | | attempt | Each model/export send attempt; each claimed eval worker case/repetition attempt | | chunk, output, update | Structured text deltas, final output, other updates; workload volume, not feature adoption | | stage | A Studio setup phase, separate from CLI command completion | | poll | Background Studio reads, including diagnostic prefetch; not deliberate inspection | | request, call | Studio request or other SDK API call outcome | | feature, observation | Deliberate/configured use versus server/background observation |

runtime_mode uses Node CI / NODE_ENV, independently of the destination project. Node factories and Studio browser bootstrap carry the same safe context. traffic_source is explicit: unknown is not evidence of external customer use. Pseudonymous installation/browser/process reach is not a count of customers.

Failures always have an approved error_code and error_category. Unclassified explicit failures use UNCLASSIFIED_FAILURE; inspected unknown errors use other. The classifier reads at most eight objects, three links deep, following own data fields failure, cause, and error. Known network codes, HTTP classes, framework failure descriptors and optional bounded cause_code/cause_category/retryable help distinguish provider, transport, validation and configuration problems. Eval failures also project the first issue's approved eval_phase; multiple issues in one run are not a complete failure census. Messages, stacks, diagnostic IDs and exception serialization remain excluded. Cancellation, suspension, limits, eval quality failures and ungraded outcomes stay separate from technical failures. A known category is not proof of a product bug.

Exporter records add bucketed batch_size, retry_attempt, retried and recovered. Recovery means a successful send after a retry, not a correlated end-to-end delivery guarantee. Recursive split sends are separate attempts.

Each successful normal delivery may carry usage_dropped_observations and usage_failed_batches once, as deltas since the last delivered health snapshot. They include cardinality/budget losses and identity/transport failures; local stats().dropped still counts groups. Health never bypasses budgets, creates its own event, or persists on disk. Permanently offline, crashed, disabled or restarted processes cannot report their lost tail. These counters expose observed loss; they cannot reconstruct unbiased feature shares after selective group dropping. A failed or ambiguous delivery may have reached ingestion: these counters describe client-observed loss, not verified server loss.

Eval and diagnostic boundaries

Eval launch/settings requests record only booleans for explicit settings and case/run deadline overrides. The SDK sdk.eval boundary reports configuration rejections and safe execution failure codes. Neither timeout values nor judge, suite, case, input, criteria or output identities are usage dimensions.

The built-in worker emits studio.eval.execution only after store.finish persists a result. A claimed case/repetition uses attempt; a legacy suite run uses execution. Cancellation, technical failure, quality failure, ungraded and success are separate. Lease loss, process shutdown and a failed persistence write do not imply completion. Retries/reclaims may execute again; no global deduplication or evaluation-level completion funnel is promised.

A custom EvalJobStore keeps instrumentation ownership by default. Embedders may supply EvalWorkerOptions.usage to opt in, or false to disable worker emission. Choose one owner: either the existing store wrapper or this injected helper. Use the same replacement catalog in its helper. Existing custom store adapters do not acquire a second public emitter when upgraded. The dispatcher also accepts usage / false; the worker forwards the chosen client or disables dispatch collection for a custom store. Retry observations use origin=server and are separate from terminal results. Standalone dispatcher defaults use component eval_dispatch, correcting the formerly invalid component spelling.

Studio emits a studio.diagnostic feature on deliberate error-detail inspection, and separately records background diagnostic reads and their failures. Shared table controls emit bounded studio.table.layout interaction actions, including resize initiation, without column names, sizes or saved layout content. Neither path sends the displayed error content. Customer-authenticated diagnostic storage continues to serve original errors independently.

Proposal: replace direct capture with a Kortyx collector

Keep direct EU capture for this slice. A later collector can accept the existing versioned record envelope, validate the catalog again, cap body/group/count sizes, rate-limit installations and total daily ingestion, deduplicate event_id, strip network metadata, and route approved releases to the intended PostHog project. Keep retention and operational logs bounded and avoid logging request bodies. Forward asynchronously with its own retry/deduplication policy.

This moves abuse controls and global budgets to an owned boundary: a public PostHog capture key can be copied and spoofed, so client caps alone cannot protect ingestion or establish authenticity. Replace the transport or set KORTYX_USAGE_TELEMETRY_ENDPOINT; product instrumentation does not change. Endpoint deployment, global limits and project routing belong to that follow-up. Existing released SDK versions continue direct capture until upgraded, so migration must account for them.

Studio contextual help

studio.help counts feature interactions using help_action: open | documentation and help_placement: card | button. Count closed-to-open card transitions once; count documentation navigation intent separately. Compare summed card-footer navigation counts with summed card-open counts to assess help use. Standalone button clicks are a separate population, and these aggregates do not establish unique users, successful page loads, or completed reading. Existing opt-out, budgets, aggregation and best-effort delivery apply. No help labels, descriptions, URLs, customer identifiers or execution content are collected. This measures maintainer product usage separately from customer execution observability.

Topology publication measurement

cli.command counts each topology.push invocation once, including dry runs. The allowlisted topology_strict boolean records whether optional strict discovery was selected. A blocked publication reports KTX_TOPOLOGY_INCOMPLETE, validation category and retryable: false; the CLI's existing terminal outcome and opt-out, bounded delivery and exporter-failure behavior apply. Compare sum(count) for strict invocations with all topology-push invocations to measure adoption, and blocked strict invocations with all strict invocations to measure rejection rate. Do not interpret a successful invocation as complete discovery when strict mode is off or intentional dynamic calls are exempt. Paths, expressions, import traces, credentials and diagnostic messages are never usage properties.