Skip to content

Privacy & Security

All processing happens client-side. The SDK makes no network requests unless you configure output sinks — in which case data goes only where you send it.

  • Key press timestamps — when keys are pressed and released
  • Dwell times — how long each key is held
  • Flight times — intervals between keystrokes
  • Mouse activity timing — time since last mouse movement (not position)
  • Focus events — when the window gains/loses focus
  • Composition events — when IME composition sequences complete (duration and character count, not the composed text)
  • Key codes — which keys were pressed (e.g., KeyA, Backspace)
  • Key names — character or key name (e.g., a, Enter)
  • Cursor position — position in text where events occurred
  • Selection ranges — start/end positions of selections

These fields capture actual text content:

  • Clipboard content — pasted text
  • Selected text — text that was selected
  • Before/after text states — text content around edits
  • IP addresses — no network requests by default
  • User identifiers — no tracking or fingerprinting
  • Browsing history — no access to other tabs or pages
  • System information — no device fingerprinting
  • Persistent state — no localStorage or cookies. IndexedDB is used only when persist: true is explicitly enabled (see Session Persistence)

By default, data exists only in memory for the duration of a session. Calling start() clears previous data. When the tracker is dereferenced, all data is garbage collected.

When persist: true is enabled, session data is also stored in IndexedDB so it can be restored after page reloads. Call clearPersistedData() to remove persisted data explicitly.

License keys contain embedded cryptographic signatures and are validated entirely client-side. No network requests are made during validation. Evaluation mode (no license key) works fully offline on localhost.

When exporting data server-side, these are the fields that may contain user-authored text:

Event typeSensitive fields
Keystroke eventskey, code
Clipboard eventscontent, beforeText, afterText
Selection eventsselectedText
Undo/redo eventsbeforeText, afterText
Session exportsession.rawText

The getData().quality score and all timing fields (timestamp, dwellTime, flightTime) contain no user content and are always safe to store.

The SDK has no npm dependencies — the published package contains only first-party code. There is no transitive dependency tree and no supply chain attack surface.

The capture layer works under strict CSP with no relaxation:

  • No unsafe-eval — the SDK never uses eval() or new Function()
  • No unsafe-inline — no inline styles or scripts are injected
  • No workers, blob URLs, or document.write

If you call getAnalysis() or getSessionReport(), the SDK lazy-loads a WebAssembly module. You must add wasm-unsafe-eval to your script-src directive:

Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval';

Capture-only usage (getData()) does not require this directive.

If using the webhook sink, add your endpoint to connect-src.

When using getAnalysis(), all analysis runs entirely client-side in the browser via WebAssembly. No data is transmitted to Anthropic, WriteTrack, or any third party. The WASM module computes SHA-256 hashes of text content for integrity verification — the hashes are included in the analysis output but the original text is not stored or transmitted by the analysis module.