Skip to content

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 IndexedDB
await tracker.ready;
// start() will auto-resume the prior session if one exists
tracker.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.

  • Storage key: Sessions are stored by contentId:fieldId, where fieldId is derived from data-writetrack-field, id, or name on the target element.
  • Page unload: On beforeunload, the current session is synchronously saved to localStorage as a fallback (IndexedDB transactions don’t survive page unload). On the next load, this is promoted back to IndexedDB.
  • ready promise: Resolves when IndexedDB has loaded any prior session. Always await tracker.ready before calling start() when persistence is enabled.
  • stop(): Saves the session to IndexedDB. After calling stop(), ready resolves again once the save completes.
  • Cleanup: Call clearPersistedData() to remove the stored session for this field (e.g., after successful form submission).

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());

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) });
});

For multi-document applications, use the static methods to list and delete persisted sessions without creating a WriteTrack instance:

// List all persisted sessions
const 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 session
await WriteTrack.deletePersistedSession('doc_1', 'body');