Session Persistence
By default, session data lives only in memory and is lost on page reload. Enable persistence to automatically save and restore sessions via IndexedDB.
Pass persist: true with a contentId to the constructor:
const tracker = new WriteTrack({ target: textarea, contentId: 'post_draft_42', // Required with persist persist: true,});
// Wait for any prior session data to load from IndexedDBawait tracker.ready;
// start() will auto-resume the prior session if one existstracker.start();When a session is resumed, all previously captured events are restored and new events are appended. The sessionId stays the same across resumes, and a segment counter in the metadata tracks how many times the session was resumed.
How It Works
Section titled “How It Works”- Where sessions live: in the browser’s IndexedDB, under the
writetrackdatabase and itssessionsobject store, scoped to the page’s origin. Nothing leaves the device. - Storage key: Sessions are stored by
contentId:fieldId, wherefieldIdis derived fromdata-writetrack-field,id, ornameon the target element. - Page unload: On
beforeunload, the current session is synchronously saved tolocalStorageas a fallback (IndexedDB transactions don’t survive page unload). On the next load, this is promoted back to IndexedDB. readypromise: Resolves when IndexedDB has loaded any prior session. Alwaysawait tracker.readybefore callingstart()when persistence is enabled.stop(): Saves the session to IndexedDB. After callingstop(),readyresolves again once the save completes.- Cleanup: Call
clearPersistedData()to remove the stored session for this field (e.g., after successful form submission).
Multi-Field Forms
Section titled “Multi-Field Forms”Each field gets its own persisted session, keyed by contentId:fieldId. Give each tracked element a distinct id or data-writetrack-field attribute:
const trackers = ['#title', '#body', '#summary'].map((sel) => { const el = document.querySelector<HTMLTextAreaElement>(sel)!; const t = new WriteTrack({ target: el, contentId: 'post_42', persist: true }); return t;});
await Promise.all(trackers.map((t) => t.ready));trackers.forEach((t) => t.start());Cleanup After Submission
Section titled “Cleanup After Submission”After the user submits the form, clear persisted data so the next visit starts fresh:
form.addEventListener('submit', async (e) => { e.preventDefault(); const data = tracker.getData(); tracker.stop(); await tracker.ready; // wait for final save await tracker.clearPersistedData(); // remove from IndexedDB
await fetch('/api/submit', { method: 'POST', body: JSON.stringify(data) });});Managing Persisted Sessions
Section titled “Managing Persisted Sessions”For multi-document applications, use the static methods to list and delete persisted sessions without creating a WriteTrack instance:
// List all persisted sessionsconst sessions = await WriteTrack.listPersistedSessions();// [{ contentId: 'doc_1', fieldId: 'default', keystrokeCount: 42, ... }]
// Delete all sessions for a document (e.g., when user deletes it)await WriteTrack.deletePersistedSession('doc_1');
// Delete a specific field's sessionawait WriteTrack.deletePersistedSession('doc_1', 'body');Related
Section titled “Related”persistoption — Constructor option referencereadypromise — Await persistence loadingclearPersistedData()— Remove stored sessionslistPersistedSessions()— List all stored sessionsdeletePersistedSession()— Delete sessions by contentId- Privacy & Security — How persistence affects data storage
Awaiting persistence
Section titled “Awaiting persistence”Automatic saves are not awaitable. An IndexedDB write becomes durable when its
transaction commits. Call flush() before an operation that depends on the
completed write:
tracker.stop();await tracker.flush(); // IndexedDB transaction committedwindow.location.href = '/submitted';flush() is a no-op when persistence is disabled and rejects when the write
fails.
Persistence errors
Section titled “Persistence errors”The persist:error event reports load, save, flush, and unload-snapshot
failures. The unload snapshot uses localStorage and is subject to the
browser’s per-origin storage quota.
tracker.on('persist:error', (error, stage) => { // stage: 'load' | 'save' | 'flush' | 'unload-snapshot' console.warn(`WriteTrack could not persist (${stage})`, error); if (stage === 'unload-snapshot') { // The localStorage unload snapshot was not written. }});An 'unload-snapshot' error means that the localStorage copy was not written.
The IndexedDB session remains available unless its own save reports an error.