Skip to content

SMOODEV-2706: Add installWebVitals RUM one-liner to browser SDK#74

Closed
brentrager wants to merge 1 commit into
mainfrom
SMOODEV-web-vitals
Closed

SMOODEV-2706: Add installWebVitals RUM one-liner to browser SDK#74
brentrager wants to merge 1 commit into
mainfrom
SMOODEV-web-vitals

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

Customers embedding the @smooai/observability browser SDK have no turnkey way to report Core Web Vitals. They'd have to wire web-vitals callbacks to a MetricsClient themselves and get the metric names/attrs right by hand.

Solution

Add installWebVitals(metrics, opts?) to @smooai/observability/browser — a one-liner that records Core Web Vitals against the existing browser MetricsClient:

import { getMetricsClient } from '@smooai/observability/metrics';
import { installWebVitals } from '@smooai/observability/browser';

installWebVitals(getMetricsClient('my-web-app'));

Pinned metric contract (matches the apps/web RUM dogfood exactly):

  • web.vitals.lcp / .fcp / .inp / .ttfb — histogram, unit ms (via MetricsClient.timing)
  • web.vitals.cls — histogram, unitless raw CLS (via MetricsClient.histogram)
  • attributes on every point: route (location.pathname, overridable via opts.route for SPA routers), rating (good|needs-improvement|poor), navigation_type (metric.navigationType)

Details:

  • Browser-guarded — no-op during SSR (typeof window === 'undefined').
  • Idempotent — repeat calls are a no-op (won't double-register PerformanceObservers).
  • Lazyweb-vitals is dynamically imported only when installWebVitals is called, so it stays out of the critical path and off the node/SSR bundle.
  • No dependency on any product internals.
  • web-vitals@^5.3.0 added as a dependency (tiny, no transitive deps).
  • No metrics catalog exists in this SDK to register against (searched all langs) — nothing to add there.

Verification

  • pnpm --filter @smooai/observability test — 62 pass (3 new, driving recordWebVital with a fake MetricsClient + synthetic metrics; asserts exact name / recording kind / attrs for each vital).
  • pnpm --filter @smooai/observability typecheck — clean.
  • pnpm --filter @smooai/observability build — clean; confirmed installWebVitals/recordWebVital exported from dist/browser.mjs + browser.d.mts, and import("web-vitals") stays a lazy runtime import (not bundled).

Release

⚠️ Hold for release until the logs signal ships — changeset included (minor), but do NOT publish this ahead of the logs signal. Release the two together.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S2bM94GAnVjYSSv1x7HKRB

Package Core Web Vitals collection into @smooai/observability/browser so
customers get LCP/CLS/INP/FCP/TTFB with a single call. Records against the
existing browser MetricsClient using the metric contract dogfooded in
apps/web:
- web.vitals.{lcp,fcp,inp,ttfb} — histogram, unit ms
- web.vitals.cls — histogram, unitless raw CLS
- attrs: route, rating, navigation_type

Browser-guarded, idempotent, lazy-loads web-vitals only on opt-in. No
product internals. Held for release until the logs signal ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S2bM94GAnVjYSSv1x7HKRB
@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d4b8474

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/observability Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager

Copy link
Copy Markdown
Contributor Author

Standing down — premise was false: the browser SDK has no metrics transport (getMetricsClient is a Node-only OTel no-op in the browser), so installWebVitals would silently send nothing. Real prerequisite is a browser metrics transport (extend the error transport's IngestPayload with type:'metric'), deferred to the customer-release phase (pearl th-e67905) after dogfooding the path inside the monorepo. Branch left on remote for reference; not deleting since it'll inform th-e67905.

@brentrager brentrager closed this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant