Skip to content

TinyMCE Integration

WriteTrack includes a native TinyMCE plugin, compatible with TinyMCE v6+ (including Moodle 4.4+).

Install WriteTrack alongside TinyMCE:

Terminal window
npm i writetrack tinymce

Import writetrack/tinymce to register the plugin, then add 'writetrack' to your plugins list:

import 'writetrack/tinymce';
tinymce.init({
selector: '#editor',
plugins: ['writetrack'],
writetrack_license: 'your-license-key',
});

The plugin works in both inline and iframe (default) editor modes. No extra configuration needed — iframe document context is detected automatically.

Pass options as TinyMCE editor options, prefixed with writetrack_:

tinymce.init({
selector: '#editor',
plugins: ['writetrack'],
writetrack_license: 'your-license-key',
writetrack_userId: 'user-123',
writetrack_contentId: 'document-456',
writetrack_metadata: { formName: 'signup' },
writetrack_autoStart: true,
});
OptionTypeDefaultDescription
writetrack_licensestringundefinedWriteTrack license key
writetrack_userIdstringundefinedUser identifier included in metadata
writetrack_contentIdstringundefinedContent identifier included in metadata
writetrack_metadataRecord<string, unknown>undefinedAdditional metadata
writetrack_autoStartbooleantrueStart tracking when editor initializes
writetrack_wasmUrlstringundefinedURL to WASM binary for analysis
writetrack_persistbooleanfalseEnable IndexedDB session persistence (requires writetrack_contentId)
writetrack_onTick(data: { activeTime: number; totalTime: number; tracker: WriteTrack }) => voidundefinedCallback fired every ~1s with active session time and tracker instance
writetrack_onReady(tracker: WriteTrack) => voidundefinedCallback fired when tracker is ready

The most common integration for an existing app: pull the session data out of the tracker when the form submits, and send it with the same request that carries the content. The tracker lives at editor.plugins.writetrack.tracker after init:

<form id="exam-form" method="post" action="/submit.php">
<textarea id="essay" name="essay_html"></textarea>
<input type="hidden" name="wt_trace" id="wt-trace" />
<button type="submit">Submit</button>
</form>
<script type="module">
import 'writetrack/tinymce';
tinymce.init({ selector: '#essay', plugins: ['writetrack'] });
document.getElementById('exam-form').addEventListener('submit', (e) => {
e.preventDefault();
const tracker = tinymce.get('essay').plugins.writetrack.tracker;
tracker.stop();
document.getElementById('wt-trace').value = JSON.stringify(
tracker.getData()
);
tinymce.triggerSave(); // sync editor content back to the textarea
e.target.submit();
});
</script>

Your backend stores wt_trace as JSON like any other column. To send the trace separately from the form instead, register a webhook sink via writetrack_onReady:

import { webhook } from 'writetrack/pipes';
tinymce.init({
selector: '#essay',
plugins: ['writetrack'],
writetrack_onReady: (tracker) => {
tracker.pipe(webhook({ url: '/api/writetrack' }));
},
});

The plugin API is available at editor.plugins.writetrack after the editor’s init event:

tinymce.init({
selector: '#editor',
plugins: ['writetrack'],
writetrack_license: 'your-license-key',
setup: (editor) => {
editor.on('init', () => {
const wt = editor.plugins.writetrack;
const data = wt.tracker?.getData();
const isTracking = wt.isTracking;
});
},
});

Or use the writetrack_onReady callback:

tinymce.init({
selector: '#editor',
plugins: ['writetrack'],
writetrack_license: 'your-license-key',
writetrack_onReady: (tracker) => {
console.log('WriteTrack ready', tracker.getData());
},
});
PropertyTypeDescription
trackerWriteTrack | nullThe WriteTrack instance (null until init)
isTrackingbooleanWhether capture is active
destroy()() => voidStop tracking and clean up
getMetadata()() => { name: string; url: string }Plugin metadata (for TinyMCE Help plugin)

The plugin automatically cleans up when TinyMCE’s remove event fires. You can also call destroy() manually:

editor.plugins.writetrack.destroy();
import type { WriteTrackTinyMCEPlugin } from 'writetrack/tinymce';