Data Schema
WriteTrack captures multiple types of events during typing sessions. This page documents the complete data schema.
Schema Version: v2.1.0
Event Types
Section titled “Event Types”Keystroke Events
Section titled “Keystroke Events”The primary event type, capturing individual key presses and releases.
interface KeystrokeEvent { key: string; // Character or key name code: string; // Physical key code type: 'keydown' | 'keyup'; timestamp: number; // High-precision timestamp (ms) dwellTime?: number; // Key hold duration (keyup only) flightTime?: number; // Time since last key (keydown only) isCorrection?: boolean; // True for Backspace, Delete, ArrowLeft, ArrowRight windowFocused: boolean; // Window focus state timeSinceLastMouse: number; // ms since last mouse activity isTrusted?: boolean; // true if user-generated, false if scripted inputSource?: InputSource; // Input source classification, set by editor integrations or beforeinput fallback}Dwell and Flight Time
Section titled “Dwell and Flight Time”Dwell time: How long a key is held down (keydown to keyup).
- Only present on
keyupevents - Typical human range: 50-200ms
Flight time: Time between releasing the previous key and pressing this one.
- Only present on
keydownevents - Typical human range: 50-500ms
Clipboard Events
Section titled “Clipboard Events”Captures copy, paste, and cut operations.
interface ClipboardEvent { type: 'copy' | 'paste' | 'cut'; timestamp: number; position: number; // Cursor position length: number; // Length of content shortcut: string; // e.g., 'Ctrl+V', 'Cmd+V' content?: string; // Actual content (paste only) beforeText?: string; // Text state before operation afterText?: string; // Text state after operation replacedText?: string; // Text that was replaced replacedRange?: { start: number; end: number; }; isTrusted?: boolean; // true if user-generated, false if scripted inputSource?: InputSource; // Input source classification, set by editor integrations or beforeinput fallback}Example Paste Event
Section titled “Example Paste Event”{ type: 'paste', timestamp: 1234567890.12, position: 42, length: 150, shortcut: 'Cmd+V', content: 'The pasted text content...', beforeText: 'Some existing text', afterText: 'Some existing textThe pasted text content...', replacedText: '', // Nothing was selected/replaced replacedRange: undefined}Selection Events
Section titled “Selection Events”Captures text selection actions.
interface SelectionEvent { type: 'select'; timestamp: number; startPosition: number; endPosition: number; selectedLength: number; selectedText?: string; // The selected text content (omitted when privacy-sensitive) method: 'mouse' | 'keyboard' | 'programmatic'; isTrusted?: boolean; // true if user-generated, false if scripted}Undo/Redo Events
Section titled “Undo/Redo Events”Captures undo and redo operations.
interface UndoRedoEvent { type: 'undo' | 'redo'; timestamp: number; shortcut: string; // e.g., 'Ctrl+Z', 'Meta+Z' beforeText: string; afterText: string;}Programmatic Insertion Events
Section titled “Programmatic Insertion Events”Detects text inserted without corresponding keystrokes, such as browser autocomplete, autofill, predictive text, AI extension injection, voice dictation, or programmatic value assignment.
interface ProgrammaticInsertionEvent { type: 'programmatic-insertion'; timestamp: number; insertedText: string; // Text that was inserted insertedLength: number; // Character count position: number; // Cursor position where text was inserted isTrusted: boolean; // Whether the triggering input event was user-generated inputType?: string; // InputEvent.inputType if available inputSource?: InputSource; // Input source classification, set by editor integrations or beforeinput fallback}WriteTrack monitors text length changes against keystroke count. When text grows faster than keystrokes can explain, a programmatic insertion event is emitted.
Composition Events
Section titled “Composition Events”Captures completed IME composition sequences (CJK input methods, dead keys, accent input). Intermediate keystrokes during composition are suppressed — only the final result is recorded.
interface CompositionEvent { timestamp: number; // When the composition started duration: number; // Duration of the composition sequence (ms) insertedLength: number; // Characters inserted (0 if composition was abandoned) isTrusted: boolean; // Whether the compositionend event was user-generated}Output Format
Section titled “Output Format”Raw Data Access
Section titled “Raw Data Access”Access captured events directly:
const keystrokes = tracker.getRawEvents();const clipboard = tracker.getClipboardEvents();const selections = tracker.getSelectionEvents();const undoRedo = tracker.getUndoRedoEvents();const insertions = tracker.getProgrammaticInsertionEvents();const compositions = tracker.getCompositionEvents();Session Data Export
Section titled “Session Data Export”getData() returns the complete session as a WriteTrackDataSchema object:
const data = tracker.getData();// {// version: "2.1.0",// metadata: { tool, targetElement, timestamp, duration },// session: { events, clipboardEvents, selectionEvents, ... },// quality: { overallScore, sequenceValid, qualityLevel, ... },// }Special Events
Section titled “Special Events”Focus Events
Section titled “Focus Events”Window focus changes are recorded as keystroke events:
{ key: 'FOCUS', // or 'BLUR' code: 'FOCUS', // or 'BLUR' type: 'keydown', timestamp: 1234567890.12, windowFocused: true, // or false timeSinceLastMouse: 0}Visibility Changes
Section titled “Visibility Changes”Document visibility changes (tab switching):
{ key: 'VISIBILITY_CHANGE', code: 'VISIBILITY_CHANGE', type: 'keydown', timestamp: 1234567890.12, windowFocused: false, timeSinceLastMouse: 1234.5, dwellTime: 5000 // Duration of visibility}Timing Precision
Section titled “Timing Precision”WriteTrack uses performance.now() for high-precision timestamps:
- Resolution: Sub-millisecond (typically 5μs)
- Monotonic: Always increasing, not affected by system clock changes
- Relative: Starts at 0 when the page loads
// Convert to absolute time if neededconst absoluteTime = Date.now() - performance.now() + event.timestamp;