# tautau browser reporting

Embed a private bug reporter in a service you manage in tautau. Create a service under **Services**, add the exact origins for each environment, then copy its installation snippet.

```html
<script defer src="https://tautau.xyz/sdk/tautau.js"
  data-tautau-key="tt_pub_YOUR_ENVIRONMENT_KEY"></script>
```

The environment key is publishable. It only permits submissions from the configured origins; it cannot read reports, run fixes or access your repository. Rotate it under the service's Environments tab. Use separate environments for production and localhost.

For module-based apps:

```js
import { createTautau } from 'https://tautau.xyz/sdk/tautau.mjs';
const reporter = createTautau({
  ingestKey: 'tt_pub_YOUR_ENVIRONMENT_KEY',
  release: { version: '2026.09.27', commit: 'FULL_40_CHARACTER_COMMIT_SHA' },
  capture: {
    mode: 'reports-only',
    blockSelectors: ['.customer-address', '[data-private]'],
  },
  launcher: false,
  onSubmitted: ({ reportId }) => console.log('Report saved', reportId),
});
document.querySelector('#report-bug').onclick = () => reporter.openReport();
// On application teardown:
// reporter.destroy();
```

`browser-sdk/` also builds an npm-compatible package with TypeScript declarations. The package name is `@tautau/browser`; this change does not publish it to the npm registry. Use the hosted script/module or build and pack this directory for your own bundler.

## Evidence and privacy

By default collection begins when the reporter opens. To collect the lead-up to a problem, explicitly choose `capture.mode: 'breadcrumbs'` and enable breadcrumbs in the service policy. The buffer retains at most 150 events. It records clicks, navigation, error stacks, redacted console messages at log/info/debug/warn/error levels, and request URL/method/status/timing. Console objects are omitted without reading their properties; original arguments still reach the app's console. It does not read request bodies, headers, cookies, storage or form values. URLs lose credentials, query strings and fragments; common secrets and email addresses are redacted from diagnostic text. Review the diagnostics before sending.

Screenshots and recordings use the browser's screen-sharing permission. When Chromium confirms capture of the current tab, input regions, contenteditable fields, embedded frames and configured private regions are painted over before storage. Arbitrary text and closed shadow trees cannot be classified reliably: mark sensitive host elements `data-tautau-private`. Other selected surfaces and uploaded files require the reporter's own review and redaction. The reporter says when automatic masking could not verify the selected tab. Invalid privacy selectors discard capture rather than bypass masking.

A single pill offers Screenshot, Draw, Hide details and Record steps. Screenshots support freehand Draw, Arrow, Box, Hide details and Text labels. Drag to draw a freehand stroke or shape; repeat to combine multiple marks on the same image. Click with Draw to add a dot. Choose a colour and Thin, Medium or Bold stroke width before each mark; existing marks keep their original style. Type or dictate a label, then click the screenshot to place it. Undo removes the most recent mark. Hide details always paints an opaque dark mask, independent of the chosen colour. **Dictate report** adds recognised speech to the description. Voice typing uses the browser's speech service when available and stops when the reporter closes, starts capture or submits. Browser support and speech-service availability vary; typed input remains available. Recording is opt-in, limited to 60 seconds and 50 MB, and can include the microphone. A report can contain ten attachments, up to 100 MB in total. Each attachment must be reviewed before submission. Screenshot annotations are flattened into the uploaded pixels.

**Include page asset inventory** is off by default. When enabled, the diagnostics preview lists up to 100 image, script, stylesheet and media URLs outside private regions. The server sanitises and stores that inventory with the occurrence; the report's Assets tab, JSON manifest and evidence ZIP include it. Inventory collection does not fetch asset files. Attach images or clips separately when their original bytes are needed. Private selectors apply to both snapshots and inventories, and invalid selectors discard their contents.

## Chrome extension

The same reporter can open from the tautau Chrome extension without changing the app's HTML. In extension settings, add the exact app origin and its environment's publishable key. Use **Report a bug in this app** on that origin. The locally bundled SDK runs in the selected page and submits through the same origin-scoped API as the embed. The app's CSP must allow the reporting and upload connections described below. Capture begins after the reporter opens; this path does not retrieve earlier logs. Use the embedded breadcrumbs mode when you need the lead-up to a problem. The extension's separate **Send tautau feedback** action reports problems with tautau itself.

Text is saved before large evidence uploads. A failed upload keeps the same report and attachment identities; retrying does not create another report. Drafts, including pending blobs, stay in this origin's IndexedDB for up to 24 hours. Editing waits for draft restoration. Once the report is accepted, its text and captured inventory stay fixed while pending evidence can be retried or removed. Set `persistDrafts: false` to disable draft storage. Successful submission deletes the local draft. Removing a pending attachment refunds its reserved storage. Close preserves a draft; `destroy` stops capture and restores wrapped browser functions.

Only one reporter instance is active per document. The widget uses an isolated shadow root. Hosts with a CSP can pass a style `nonce`, allow `https://tautau.xyz` in `script-src`/`connect-src`, allow the signed GCS upload origin in `connect-src`, and permit `blob:` in `img-src`/`media-src`.

## Clippy

When initialising the existing clippy embed, pass `ingestKey` to its configuration. Its report action lazy-loads this SDK with `launcher: false`, retaining the same service, privacy policy and evidence flow.

## Register a deployment

A manager can rotate a **deployment key** in the service's Repository tab. Keep this key in CI secrets, never in browser code. POST `/api/capture/releases` with `Authorization: Bearer tt_deploy_…` and JSON:

```json
{
  "environmentId": "env-…",
  "version": "2026.09.27",
  "commit": "FULL_40_CHARACTER_COMMIT_SHA",
  "url": "https://your-app.example",
  "sourceMaps": [
    { "url": "https://your-app.example/assets/app.js", "content": { "version": 3, "sources": ["src/app.ts"], "names": [], "mappings": "AAAA" } }
  ]
}
```

Only a registered environment/version/commit makes a report's release verified. A release accepts at most 20 source maps totalling 2 MB; the service retains at most 50 release records and expires source-map contents with its retention policy. Chat can resolve bundle frames and inspect the linked repository at this commit.

## Development

From the repository root: `node browser-sdk/scripts/build.mjs`, `task test:bugs`, `task e2e:bugs`. The latter uses a fresh database, real Go/Next servers, a local checkout fixture and local provider responses. See `docs/BUG_REPORTING.md` for management and operations.
