This page covers the low-level headless Editor approach. For production AI agent workflows, use the Document Engine AI tools instead — they provide structured tool definitions, provider-ready schemas, and built-in dispatch.
SuperDoc can run headless in Node.js for server-side document processing, AI agent workflows, and batch automation.
Quick example
import { Editor } from 'superdoc/super-editor';
import OpenAI from 'openai';
const openai = new OpenAI();
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Write a service agreement in HTML.' }],
});
const editor = await Editor.open(templateDocx);
editor.commands.insertContent(completion.choices[0].message.content, {
contentType: 'html',
});
const docx = await editor.exportDocx();
Content formats
editor.commands.insertContent(value, { contentType: 'html' }); // Recommended for LLMs
editor.commands.insertContent(value, { contentType: 'markdown' });
editor.commands.insertContent(value, { contentType: 'text' });
editor.commands.insertContent(value, { contentType: 'schema' }); // ProseMirror JSON
See Import/Export for format details, limitations, and guidance on choosing a format.
AI redlining with track changes
Use suggesting mode so AI edits appear as tracked changes that users can accept or reject:
const contract = await readFile('./contract.docx');
const editor = await Editor.open(contract, {
documentMode: 'suggesting',
});
// AI suggestions are tracked — users review them in Word
editor.commands.insertContent(aiRevisions, { contentType: 'html' });
const redlined = await editor.exportDocx();
Programmatic block access
For multi-step workflows — extract block references, send them to an LLM, then apply edits — use the Document API. It returns stable block addresses that work across separate editor sessions:
// Find all paragraphs and their text
const result = editor.doc.find({
select: { type: 'node', nodeType: 'paragraph' },
includeNodes: true,
});
// Each item has an address with a best-effort stable nodeId
const blocks = result.items.map((item) => ({
id: item.address.nodeId, // usually stable across loads for unchanged DOCX content
type: item.address.nodeType,
text: item.node?.text,
}));
// Send blocks to LLM, get back edits, apply them
Block addresses from doc.find() prefer DOCX-native IDs (paraId) for imported blocks. This is the best available cross-session anchor, but no ID is guaranteed to survive all Word round-trips. Don’t read node.attrs.sdBlockId directly — it’s regenerated on every load.
LLM quick reference
Point your AI assistant at these URLs for SuperDoc context:
https://docs.superdoc.dev/llms.txt // Quick reference
https://docs.superdoc.dev/llms-full.txt // Complete documentation
Next steps