| name | autotel-web |
| description | Use this skill when adding distributed tracing to a browser application — covers lean mode (traceparent header injection, ~1.6KB), full mode (real OTel spans, Web Vitals, error capture), privacy controls, and SSR-safe setup.
|
autotel-web
Ultra-lightweight browser SDK for distributed tracing. Two modes:
- Lean (
autotel-web) — ~1.6KB gzipped. No OTel dependencies. Injects W3C traceparent headers on fetch/XHR so the backend can continue the trace. No real browser spans.
- Full (
autotel-web/full) — Real OTel spans, Web Vitals, error capture, network timing, OTLP export. Larger bundle (~40–50KB gzipped).
Setup
Lean mode — traceparent injection only
import { init } from 'autotel-web';
init({ service: 'my-frontend-app' });
fetch('/api/users');
Full mode — real browser spans + export
import { initFull } from 'autotel-web/full';
initFull({
service: 'my-app',
endpoint: 'https://collector.example.com/v1/traces',
sampleRate: 0.1,
captureNavigation: true,
captureFetch: true,
captureXHR: true,
captureErrors: true,
captureWebVitals: true,
captureLongTasks: false,
});
React / Next.js (client-only init)
import { useEffect } from 'react';
import { init } from 'autotel-web';
function App() {
useEffect(() => {
init({ service: 'my-spa' });
}, []);
return <div>...</div>;
}
Configuration / Core Patterns
AutotelWebConfig (lean mode)
init({
service: 'my-app',
debug: false,
instrumentFetch: true,
instrumentXHR: true,
privacy: {
allowedOrigins: ['api.myapp.com'],
blockedOrigins: ['analytics.google.com'],
respectDoNotTrack: true,
respectGPC: true,
},
});
Privacy decision order: DNT check → GPC check → blockedOrigins → allowedOrigins → allow all.
Functional API (lean mode)
import { init, trace, getActiveContext, getTraceparent, extractContext } from 'autotel-web';
init({ service: 'my-app' });
const fetchUser = trace(async (id: string) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
});
const fetchUser = trace((ctx) => async (id: string) => {
console.log('Trace ID:', ctx.traceId);
const res = await fetch(`/api/users/${id}`);
return res.json();
});
init({ service: 'my-app', instrumentFetch: false });
fetch('/api/data', {
headers: { traceparent: getTraceparent() },
});
const ctx = extractContext(request.headers.get('traceparent') ?? '');
Low-level traceparent utilities
import { createTraceparent, generateTraceId, generateSpanId, parseTraceparent } from 'autotel-web';
const header = createTraceparent();
const parsed = parseTraceparent(header);
Full mode extras
import { initFull, span, setAttribute, addEvent } from 'autotel-web/full';
initFull({ service: 'my-app', endpoint: '...' });
const result = span('my-operation', (s) => {
s.setAttribute('key', 'value');
return doWork();
});
setAttribute('user.id', '123');
addEvent('button.clicked', { 'button.name': 'submit' });
Full mode — advanced options
initFull({
service: 'my-app',
endpoint: '...',
userInteraction: {
enabled: true,
selectors: ['button', 'a', '[data-track]'],
},
attributeRedactor: 'default',
errorTracking: {
},
webVitals: {
reportAllChanges: false,
},
});
Backend (autotel) — automatic trace continuation
No code changes needed on the backend. Autotel's HTTP middleware reads the traceparent header and creates child spans automatically:
import { init, trace } from 'autotel';
init({ service: 'my-api', endpoint: 'http://localhost:4318' });
app.get('/api/users', async (req, res) => {
const users = await trace(async () => db.users.findAll())();
res.json(users);
});
Common Mistakes
HIGH — Calling init() in SSR/server code
Wrong:
import { init } from 'autotel-web';
init({ service: 'my-app' });
Correct:
useEffect(() => {
init({ service: 'my-app' });
}, []);
Explanation: init() checks typeof window === 'undefined' and no-ops on the server, but calling it at module level in SSR frameworks can still cause issues. Always initialize inside useEffect or a client component.
HIGH — Importing from autotel-web/full for lean use case
Wrong:
import { initFull } from 'autotel-web/full';
initFull({ service: 'my-app' });
Correct:
import { init } from 'autotel-web';
init({ service: 'my-app' });
Explanation: Full mode bundles the OpenTelemetry browser SDK. Use it only when you need real browser spans, Web Vitals, or OTLP export from the client.
HIGH — Using protocol:// in allowedOrigins / blockedOrigins
Wrong:
init({
service: 'my-app',
privacy: {
allowedOrigins: ['https://api.myapp.com'],
},
});
Correct:
init({
service: 'my-app',
privacy: {
allowedOrigins: ['api.myapp.com'],
},
});
Explanation: Origin matching is substring-based. Including https:// is unnecessary and triggers a console warning. Use domain names only.
MEDIUM — Expecting trace() to create real browser spans
Wrong:
const result = await trace(async () => heavyWork())();
Correct: Use full mode (autotel-web/full) if you need real browser spans. In lean mode, only the backend creates spans; trace() is provided for API consistency and access to trace IDs via the factory pattern.
MEDIUM — Calling init() multiple times
Wrong:
init({ service: 'my-app' });
init({ service: 'my-app' });
Correct: Call init() once at app startup. Subsequent calls are no-ops (with a warning logged if debug: true). The module-level isInitialized flag prevents double-patching.
Version
Targets autotel-web v1.11.0. Lean mode has no @opentelemetry/* runtime dependencies. Full mode (autotel-web/full) depends on @opentelemetry/sdk-trace-web, @opentelemetry/exporter-trace-otlp-http, and related packages (all bundled in the package, no separate install needed). Node.js 22+ for testing; browser targets all modern browsers.