@tindalabs/blindspot
v0.1.2
Published
Blindspot — privacy-first auto-instrumentation for browsers. Captures Web Vitals, custom spans, and user events with built-in PII filtering.
Maintainers
Readme
@tindalabs/blindspot
Observability without surveillance — an OpenTelemetry-native frontend SDK.
Blindspot emits structured OTel spans from every user interaction — route navigations, clicks, form submissions, fetch calls, errors, and Web Vitals. Outgoing requests carry a W3C traceparent, so frontend spans correlate with your backend traces. No DOM snapshots. No PII. No session replay — signals, not recordings.
npm install @tindalabs/blindspotQuick start
import { init } from '@tindalabs/blindspot'
init({
endpoint: 'https://otel-collector.example.com/v1/traces',
serviceName: 'storefront',
privacy: { maskInputs: true }, // restrictive by default
sampling: { rate: 1.0 }, // lower in production, e.g. 0.2
})That's it — auto-instrumentation starts immediately. Point endpoint at any OTLP/HTTP collector (Grafana Tempo, Honeycomb, etc.).
What gets instrumented
| Instrumentation | Span | Key attributes |
|---|---|---|
| routing | navigation {from} → {to} | ux.route.from/to/trigger |
| clicks | click {tag}[{label}] | ux.element.label, ux.rage_click, ux.dead_click |
| forms | form.submit {name} | ux.form.name/valid/attempts |
| fetch | {METHOD} {path} | http.*, ux.api.user_wait_ms, injected traceparent |
| vitals | events on route span | lcp, cls, inp |
| errors | error.unhandled | error.type/message (sanitized) |
Each is toggleable via instrument: { ... } (all on by default).
Privacy by construction
maskInputs(defaulttrue) — input content is never captured.blockSelectors/data-blindspot-block— exclude elements entirely.piiPatterns— strip patterns (card numbers, etc.) from all attribute values.consentRequired+grantConsent()/revokeConsent()— buffer spans until consent (GDPR).
<div data-blindspot-block><input type="password" /></div>
<button data-blindspot-label="submit-order">Place Order — $49.99</button>Manual instrumentation
import { getTracer, recordEvent } from '@tindalabs/blindspot'
const span = getTracer().startSpan('checkout.address-validation')
span.setAttribute('ux.form.fields_count', 5)
span.end()
recordEvent('promo.applied', { code_type: 'percentage' }) // event on the active spanFramework adapters
-react · -next · -vue · -svelte
Docs
API reference · Architecture & privacy model
The Tindalabs stack
| Package | What it does | |---|---| | @tindalabs/blindspot | Privacy-first OTel frontend observability | | @tindalabs/shield | Tamper detection & content protection | | @tindalabs/scent | Probabilistic identity continuity |
License
MIT
