Home

BugTape docs

SDK Reference

Every browser init option and method.

The BugTape JavaScript/TypeScript SDK records browser activity and lets users submit bug reports with full context.

Installation

The public npm package is not published. Use the hosted browser module after applying your app's consent policy:

<script type="module">
  import { init } from 'https://app.bugtape.ai/bugtape.mjs';
  init({ apiKey: 'bt_live_your_key_here' });
</script>

Supported runtimes

RuntimeSupportedNotes
Browser (modern)YesChrome, Firefox, Safari, Edge — ES2020+
Node.jsNoSDK uses browser APIs (DOM, fetch, rrweb)
Next.js (browser)YesUse the hosted module example; no SSR initialization
Next.js (server)NoUse the HTTP API for server-side ingestion
React NativeNoBrowser-only

Browser module exports

import { init, identify } from 'https://app.bugtape.ai/bugtape.mjs';

This import belongs in a browser module. For Next.js use the hosted module example; do not ask a bundler to install the unavailable npm package.

Initialization

const instance = init({ apiKey: 'bt_live_your_key_here' });

BugTapeConfig

PropertyTypeRequiredDefaultDescription
apiKeystringYesProject API key (bt_live_* or bt_test_*)
endpointstringNohttps://app.bugtape.ai/v1/ingestIngest endpoint URL
registeredIdentity{ applicationId: string; buildId?: string; installationId?: string }NoomittedManagement-enrolled UUIDs. applicationId is required inside this object; optional build and installation must belong to that application and the capture key's project. Copy the populated snippet from Setup.
releasestringNoinferredDeploy/release id on every occurrence. Prefer init({ release }). If omitted: BUGTAPE_RELEASE, then common CI SHA envs (GITHUB_SHA, VERCEL_GIT_COMMIT_SHA, …).
summarizebooleanNotrueSet to false to disable the AI summary entirely
recordingWindownumberNo10Buffer duration in minutes
maxEventsnumberNo50000Maximum events in ring buffer
positionstringNo'bottom-right'Widget position: bottom-right, bottom-left, top-right, top-left
themestringNo'auto'Widget theme: dark, light, auto
disableDomRecordingbooleanNofalseDisable DOM mutation recording
disableNetworkRecordingbooleanNofalseDisable network request recording
disableConsoleRecordingbooleanNofalseDisable console output recording
rageClickSensitivitystringNo'medium'Rage click detection: very-sensitive, medium, low
contextobjectNoOccurrence metadata: reporterEmail, reporterId, sessionId, userId, release, environment, platform, metadata. Prefer top-level release.
context.platformstringNo'web'Capture platform: web, ios, android, react-native, flutter, server, other. Sent on every ingest; the server infers it from the user agent when a client omits it. On the v1 web/server path, platform is not part of the fingerprint. Native v2 hashes a canonical JSON blob that includes platform.
piiPartial<PiiConfig>No{ enabled: true }PII scrubbing configuration
onSubmit(report: BugReport) => void | Promise<void>NoCustom submit handler (replaces default)
onSuccess(response: IngestResponse) => voidNoCalled after successful submission
onError(error: Error) => voidNoCalled on submission failure

Do not pass encryptionKey: the SDK rejects it because storage/read/decryption is not supported end to end. Do not put an AI provider key in browser code. onSubmit replaces default delivery; an empty handler discards the submission path. Use onSuccess for acknowledgement callbacks.

Registered application, build and installation

Use Setup's enrolled snippet to associate a real capture with its installation. The SDK takes the IDs inside registeredIdentity; they are not top-level SDK options:

init({
  apiKey: captureKey,
  registeredIdentity: { applicationId, installationId, buildId },
});

The variables above are your enrolled IDs from Setup or authorized deployment configuration. Omit buildId until a build has been registered. Basic capture can omit the entire object, but it cannot confirm a particular installation. A build or installation ID requires its application's ID. Do not invent IDs or label a repaired build with a failed build's ID.

The SDK copies and validates this object on first initialization. Misplaced top-level applicationId, buildId or installationId causes an early error before recording or transport starts. Repeated init calls return the existing instance without applying new configuration. The HTTP ingest payload flattens the validated values to those three top-level fields; that wire format is different from the SDK configuration.

An ingest acknowledgement proves report acceptance in the stated project. Setup's installation receipt separately confirms a real capture from that enrolled installation. Neither receipt attests a binary, physical device or verified repair. Agent work grants and trusted runner verification have separate authority; see Agents.

BugTapeInstance

MethodReturnsDescription
open()voidOpen the bug report widget programmatically
getEvents()BugTapeEvent[]Get all buffered events within the recording window
destroy()voidTear down the SDK, remove event listeners, remove widget
bufferRingBufferDirect access to the ring buffer (advanced use)

Auto-captured events

Once initialized, the SDK automatically captures these event types:

DOM events (dom)

Recorded via rrweb. Captures full visual replay data including:

  • Full DOM snapshots
  • Incremental DOM mutations
  • Mouse movement and clicks
  • Scroll events (throttled to 150ms)
  • Input changes (last value only)
  • Focus/blur events

All text inputs are masked by default for privacy.

Network events

Event typeData captured
networkResource timing: URL, duration, transfer size, initiator type
network:fetchFetch requests: URL, method, status code, duration
network:fetch:errorFailed fetch: URL, method, error message, duration
network:xhrXHR requests: URL, method, status code, duration

Console events

Event typeData
console:log{ level: "log", args: string[] }
console:warn{ level: "warn", args: string[] }
console:error{ level: "error", args: string[] }
console:info{ level: "info", args: string[] }
console:debug{ level: "debug", args: string[] }

Arguments are JSON-serialized with a 2,000-character limit per argument.

Error events

Event typeData
error{ message, filename, lineno, colno, stack }
error:unhandledrejection{ message, stack }

Rage click events (rage-click)

{ x: number, y: number, clicks: number, target: string, url: string, innerText: string }

Sensitivity presets:

PresetClicksWindowRadiusDebounce
very-sensitive2+1500ms50px1s
medium3+1000ms30px2s
low4+800ms20px3s

Event structure

All events share this shape:

interface BugTapeEvent {
  type: string;       // Event type identifier
  timestamp: number;  // Unix timestamp in milliseconds
  data: unknown;      // Event-specific payload
}

Ring buffer behavior

  • Events are stored in a time-windowed buffer (default: 10 minutes).
  • When the event count exceeds maxEvents, the oldest 20% of events are evicted.
  • PII scrubbing is applied at capture time (before events enter the buffer).
  • Calling getEvents() automatically prunes expired events.

Bug report structure

When a user submits via the widget, the SDK builds a BugReport:

interface BugReport {
  title: string;
  description: string;
  severity: 'critical' | 'high' | 'medium' | 'low';
  screenshot: ScreenshotResult | null;
  audio: AudioResult | null;
  audioTranscript: string | null;
  aiSummary: BugSummary | null;
  events: BugTapeEvent[];
  environment: {
    url: string;            // window.location.href
    userAgent: string;      // navigator.userAgent
    viewport: string;       // e.g., "1920x1080"
    timestamp: string;      // ISO 8601
    language: string;       // navigator.language
  };
}

Ingest payload

The SDK transforms the BugReport into the API payload:

{
  title: string;
  description: string;
  severity: string;
  url: string;
  userAgent: string;
  viewport: string;
  events: BugTapeEvent[];
  screenshot: ScreenshotResult | null;
  audio: AudioResult | null;
  aiSummary: BugSummary | null;
  platform: string;            // context.platform ?? 'web'
  // plus context fields: reporterEmail, reporterId, sessionId, userId, release, environment, metadata
}

Submitted via POST to the configured endpoint with headers:

  • Content-Type: application/json
  • X-BugTape-Key: <apiKey>

Legacy screenshot/audio payload fields are not proof of retrievable media storage. See the ingest contract for the current storage boundary.

Ingest response

interface IngestResponse {
  id: string;              // UUID — stable report ID
  fingerprint: string;     // 16-char hex dedup fingerprint
  deduplicated: boolean;   // true if matched an existing report
  regression: boolean;     // true if a resolved bug reoccurred
  is_regression: boolean;  // alias for regression
  schemaVersion?: 1;
  captureId?: string;      // stable capture acknowledgement when schema v1 is used
  occurrenceId?: string;   // required UUID in a schema v1 acknowledgement
  receivedAt?: string;
}

Submission behavior

  1. Default flow: SDK POSTs the report to the ingest endpoint.

Schema v1 submissions require a matching captureId and valid occurrenceId before the SDK invokes onSuccess or removes a queued report. Missing, mismatched, malformed or oversized receipts remain retryable. Response bodies are capped at64KiB, with the existing10-second deadline and stream cancellation. Self-hosted servers must support the v1 receipt before upgrading this SDK.

  1. Retry: Retryable transport/server failures get one retry after a 1-second delay. Permanent validation/auth failures are not queued.
  2. Offline fallback: Eligible failed captures can be stored in a bounded local retry queue when storage is available. Retry retains the original destination, credential scope and capture ID. onError reports whether the capture was saved; do not assume every failure was persisted.
  3. Custom submit: If onSubmit is provided, it replaces the default submission. You can call the API yourself or route reports elsewhere.

Encryption limitation

End-to-end report encryption is not supported. Setting encryptionKey causes submission to fail explicitly. The API does not provide a retrievable encrypted-artifact/decryption path. Do not use this option or claim private ciphertext storage.

PII scrubbing

Enabled by default. Scrubs the following patterns from all event data at capture time:

  • Email addresses
  • Credit card numbers (validated with Luhn algorithm)
  • US Social Security numbers
  • Phone numbers
  • JWTs
  • API keys / bearer tokens
  • IPv4 addresses

Configure with pii: { enabled: false } to disable.

Before a capture key on client-data UI: complete the privacy proof checklist and run the privacy fixture. Default regex scrub is not enough for named clients in table text — mark containers with data-bugtape-ignore / .bugtape-ignore / .rr-block, or set disableDomRecording: true / use server-only ingest.

AI summaries

The SDK fetches a short AI-generated summary when the bug report panel opens. The summary contains:

  • A suggested title
  • A severity assessment (critical / high / medium / low)
  • A 1–3 sentence description of what happened

The summary is included in the submitted report alongside the user-provided title and description.

AI Summary (server-side)

This is the default path. The SDK sends the last ~300 events to BugTape's /v1/ingest/ai-summary endpoint, which calls the workspace's configured AI provider (OpenAI, Anthropic, or Google) server-side and returns the summary.

No additional client configuration is required — it uses the same apiKey as ingest. If the workspace has no AI provider configured, the server responds with 503 and the SDK silently falls back to submitting without a summary; the bug report is still filed.

Set summarize: false to disable the AI summary request entirely.

Provider credentials

Omit the deprecated openaiKey option. Keep provider credentials on the server; do not place them in browser code or NEXT_PUBLIC_* variables. Use summarize: false if you do not want the summary request.

Error boundaries

All SDK recorders are wrapped in error boundaries. If a recorder fails (e.g., rrweb throws on an unusual DOM), the SDK logs a warning and continues. Test the integration against your own app; this does not guarantee that every host interaction is harmless.