Vanilla JavaScript
WriteTrack works with any HTML page — no framework required. Attach it to a <textarea>, <input>, or contenteditable element and start capturing.
Installation
Section titled “Installation”npm i writetrackpnpm add writetrackyarn add writetrackbun add writetrackLicense
Section titled “License”On localhost, WriteTrack runs with full analysis enabled — no license key required. For production, register a free trial:
npx writetrack initThe CLI prompts for your email and domain, then saves the key to .env. Pass it when initializing:
const tracker = new WriteTrack({ target: textarea, license: 'your-license-key',});See Licensing for full details.
Basic Usage
Section titled “Basic Usage”Attach WriteTrack to any text input and call getData() on submit:
import { WriteTrack } from 'writetrack';
const textarea = document.querySelector<HTMLTextAreaElement>('#response-field')!;const tracker = new WriteTrack({ target: textarea });tracker.start();
document.getElementById('response-form')!.addEventListener('submit', (e) => { e.preventDefault(); const data = tracker.getData(); console.log('Session quality:', data.quality.qualityLevel); tracker.stop();});With Analysis
Section titled “With Analysis”Run the WASM analysis engine to assess typing authenticity:
import { WriteTrack, formatIndicator } from 'writetrack';
const tracker = new WriteTrack({ target: textarea });tracker.start();
// ... user types ...
tracker.stop();const analysis = await tracker.getAnalysis();
if (analysis) { console.log(formatIndicator(analysis.contentOrigin.indicator)); // → "All text was typed directly"
console.log(formatIndicator(analysis.timingAuthenticity.indicator)); // → "Timing variability is within normal range"}Or bundle raw data and analysis into a single payload with getSessionReport():
const report = await tracker.getSessionReport();// report.data — captured events (same as getData())// report.analysis — authenticity analysis (same as getAnalysis())
await fetch('/api/submit', { method: 'POST', body: JSON.stringify(report),});With Output Sinks
Section titled “With Output Sinks”Use .pipe() to route session data to your backend automatically when getData() is called:
import { WriteTrack, webhook } from 'writetrack';
const tracker = new WriteTrack({ target: document.querySelector('#response-field')!,});
tracker.pipe(webhook({ url: '/api/writetrack' }));tracker.start();WriteTrack also ships sinks for Datadog, Segment, and OpenTelemetry. See Output Sinks for details.
Contenteditable Elements
Section titled “Contenteditable Elements”WriteTrack works with contenteditable elements the same way:
const editor = document.querySelector<HTMLDivElement>('#editor')!;const tracker = new WriteTrack({ target: editor });tracker.start();Multiple Fields
Section titled “Multiple Fields”Track different fields independently:
const titleTracker = new WriteTrack({ target: document.querySelector('#title')!, contentId: 'title',});
const bodyTracker = new WriteTrack({ target: document.querySelector('#body')!, contentId: 'body',});
titleTracker.start();bodyTracker.start();Context Fields
Section titled “Context Fields”Tag sessions with identifiers that flow through to getData() output and all sinks:
const tracker = new WriteTrack({ target: textarea, userId: 'u_abc123', contentId: 'post_draft_42', metadata: { formName: 'signup', variant: 'B' },});| Field | Type | Description |
|---|---|---|
userId | string | Who is typing. Appears in metadata.userId. |
contentId | string | What they’re typing into. Appears in metadata.contentId. |
metadata | Record<string, unknown> | Arbitrary key-value pairs. Appears as metadata.custom. |
Next Steps
Section titled “Next Steps”- Analysis — Deep dive on the six analysis categories
- Session Persistence — Save and resume sessions across page reloads
- Scorecard — Render a full visual analysis report
- Output Sinks — Route data to webhooks, Datadog, Segment, or OpenTelemetry
- API Reference — Complete method and type reference