# Tracebird — SDK & API documentation (for LLMs)
> Tracebird is a tester-feedback SDK for web and Flutter (iOS/Android). Testers
> click a floating widget, optionally annotate a screenshot, write one
> sentence and send. Every report automatically ships with console logs,
> network calls, JS errors, navigation breadcrumbs, environment info, a
> gzipped rrweb DOM snapshot, and — during a test session — a full session
> recording (DOM mutations, scroll, mouse trail). Reports land in a
> dashboard inbox; issues are created on GitHub/Linear/Jira from there.
## Install
Script tag (any stack — the file is an ES module):
Or via npm:
npm install @tracebird/web
import { init } from "@tracebird/web";
init({ projectKey: "pk_live_..." });
Call init() as early as possible: buffers only capture what happens after
installation. Call it once, not per route.
## init(options)
| option | type | default | notes |
|-------------|--------|--------------------------|-------|
| projectKey | string | required | public key from project Settings |
| endpoint | string | https://api.tracebird.dev| ingest base URL (self-hosting) |
| environment | string | — | free-form label (staging, production…) |
| release | string | — | app version, used for regression tracking |
| tester | string | — | optional name/email; testers never need accounts |
The project key is public by design. Abuse is contained server-side:
per-project Origin allowlist (403 for unknown key OR bad origin —
indistinguishable on purpose), rate limiting per identified caller
with a per-IP backstop for anonymous traffic, 8 MB body cap.
IMPORTANT: every domain testers use (including localhost:PORT and preview
deploys) must be added to the project's allowed origins, or reports fail 403.
## JavaScript API
- init(options): void — installs capture, mounts the widget, resumes an
in-flight session after a page load. Idempotent.
- startSession(): Promise — starts a test session (loads the
recorder chunk on demand, shows a pulsing REC badge with a live timer).
- endSession(): void — stops and discards. Rarely needed: sending a report
ends the session automatically and attaches the recording.
Available as ESM exports or on window.Tracebird when loaded via script tag.
Lazy loading: core ~11 KB gz on load; rrweb recorder ~82 KB gz fetched on
session start; screenshot/annotation editor ~8 KB gz on "Capture &
annotate"; DOM snapshot module ~24 KB gz at send time. Chunks resolve
relative to tracebird.js — when self-hosting, serve the whole dist/ folder.
## What a report contains (caps enforced server-side)
Always: console ring buffer (100 entries, 500 chars each) · network (50
requests: method, url, status, ms — NEVER bodies, auth headers scrubbed) ·
JS errors (20) · navigation breadcrumbs (30 routes) · environment
(viewport, browser, language, timezone, UA, connection) · gzipped rrweb DOM
snapshot (≤ 800 KB, inputs masked, skipped if over cap).
On demand: annotated screenshot (JPEG ≤ 3 MB, blur regions pixelated
client-side BEFORE upload) · vector annotations (≤ 200 shapes: brush with
point list, arrow, rect, blur) · session recording (gzipped rrweb event
stream ≤ 3 MB, merged across page loads) · click journey (≤ 200 timestamped
clicked elements).
Never captured: request/response bodies, input values (masked at source),
passwords (always masked, no opt-out), cookies, storage, auth headers,
anything under a tester's blur.
## Test sessions
Start from the widget panel ("Start test session") or startSession().
While active: pulsing REC badge with timer on every page; rrweb records DOM
mutations/scroll/mouse (mousemove sampled 40 ms); clicks are logged as a
readable journey. Sessions persist across full page loads via
sessionStorage (segments gzipped per page, merged at send). Sending a
report ends the session and ships the recording; a failed send keeps it
running. Limits: 20 000 events/page, 3 MB gz recording, 200 clicks.
## Flutter SDK (iOS & Android)
flutter pub add tracebird_flutter
await Tracebird.init(
projectKey: 'pk_live_...',
trigger: TracebirdTrigger.shake, // shake | floatingButton | manual
capture: TracebirdCapture(logs: true, network: true, breadcrumbs: true),
privacy: TracebirdPrivacy(maskWidgets: true, scrubHeaders: ['authorization']),
);
runApp(TracebirdWrapper(child: MyApp()));
- Add the app's bundle IDs (com.acme.app) to the project allowlist — the
mobile equivalent of web origins.
- Wrap sensitive UI in TracebirdMask(child: ...) — blanked at capture time
on the device.
- Manual trigger: Tracebird.report(type: FeedbackType.bug).
- Platform views (WebView/Maps/camera): measured, iOS needs a native capture
fallback (UIGraphicsImageRenderer + drawHierarchy) because RepaintBoundary
leaves a hole; Android needs none because platform views are composited
into the Flutter scene. Automatic, no configuration. FLAG_SECURE content
is still uncapturable on Android — the report goes without a screenshot.
- No runtime dependencies: device info, cache dir, shake detection, capture
and JPEG encoding go through the plugin's own platform channel.
- Offline: reports persist locally and replay on reconnect with an
idempotency key (no duplicates).
- Context: debugPrint logs, Dio interceptor for network, NavigatorObserver
breadcrumbs, device model/OS/app version, Tracebird.addMetadata().
- Web and Flutter reports share one inbox (filter by platform).
## Ingest HTTP API
POST {endpoint}/v1/ingest/feedback
Headers: Content-Type: application/json; Origin must match the allowlist.
{
"projectKey": "pk_live_...", // required, 8-64 chars
"type": "bug" | "idea" | "question",// default "bug"
"comment": "...", // required, 1-4000 chars
"tester": "...", // ≤ 120 chars
"release": "...", "environment": "...", // ≤ 50 chars each
"route": "/checkout", // ≤ 500 chars
"context": { ... } // validated field-by-field; unknown keys stripped
}
Responses: 202 {"id": ""} · 400 validation (first bad field named) ·
403 unknown key or origin not allowlisted · 413 body > 8 MB · 429 rate
limited. Server-to-server callers must still send a matching Origin header
(add e.g. ci.acme.dev to the project).
## AI triage & dedup (automatic, server-side)
Every ingested report is analyzed by Claude: generated title, severity
(low/medium/high/critical) + reason, repro steps inferred from the
navigation trail, expected/actual, and a suspected cause quoting the
decisive log line or failed request. Reports describing the same
underlying defect are grouped (duplicate_of). Results appear in the
dashboard and via the MCP server; analysis is asynchronous (a report
may briefly show "analyzing").
## MCP server
MCP over Streamable HTTP at https://api.tracebird.dev/mcp, auth via
"Authorization: Bearer ". Tools: list_projects,
list_reports(project, status?, limit?), get_report(id) — full context
incl. logs/network/errors/comments, update_report(id, status?,
assignee?), add_comment(id, body, author?). Claude Code:
"claude mcp add --transport http tracebird --header ...".
## Privacy summary
Masking by default (inputs, passwords), no network bodies ever, blur
destroys pixels client-side, recording is always visibly indicated (REC
badge), unlimited reports with AI triage metered per month (50 free,
2,000 indie, 10,000 studio) — reports are never refused, only the analysis
pauses, captures in a private bucket served through short-lived
signed links, project deletion cascades immediately.
Docs: https://tracebird.dev/docs