Skip to content

About

Free, MIT-licensed block editor for Strapi 5: live collaboration across servers, version history, custom blocks, Media Library uploads and an optional AI assistant with your own provider.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

Magic Editor X

Block editor for Strapi 5: an Editor.js custom field with Media Library uploads, custom blocks, version history, live collaboration across several servers and an optional AI assistant that uses your own provider. Free and open source under the MIT license.

npm license: MIT

Live docs: https://schero94.github.io/Magic-Editor-X/

Contents

Features

Every feature is available in every installation. There is nothing to activate, no tiers and no usage limits, and the plugin makes no outgoing requests unless you use a feature that needs one (link previews, image by URL, AI assistant).

  • Custom field plugin::magic-editor-x.richtext (stored as JSON) for collection types, single types, components and dynamic zones, including localised fields and Draft & Publish.
  • Block tools (block name in brackets, the same names 1.x used):
    • text: paragraph (paragraph), heading H1 to H6 (header), list with nesting, ordered and unordered (list), checklist (checklist), quote (quote), warning (warning), alert in eight colours (alert), collapsible toggle (toggle), delimiter (delimiter), table (table);
    • code: plain code (code), code with syntax highlighting (codeFlask; Prism with JavaScript, TypeScript, JSX/TSX, JSON, HTML, CSS/SCSS, PHP, Python, Ruby, Go, Rust, Java, Kotlin, Swift, C, C++, C#, SQL, Bash, YAML, Markdown, GraphQL, Docker and diff);
    • media: image upload by file or URL into the Media Library (image), picking images from the Media Library (mediaLib, inserts image blocks), image by URL without upload (simpleImage), file attachments (attaches), embeds such as YouTube, Vimeo, CodePen, GitHub, Figma and others (embed);
    • other: link preview card (linkTool), person card (personality), call-to-action button (button), raw HTML (raw).
  • Inline tools: bold, italic, link with target and rel (hyperlink), marker, underline, strikethrough, inline code, tooltip, and the AI assistant when it is enabled.
  • Block tunes: alignment (alignmentTune), text variant call-out / citation / details (textVariant), indent (indentTune).
  • Editing: undo and redo, drag and drop of blocks, full screen mode, block and word count.
  • Custom blocks: define your own blocks in Settings: simple blocks with fields (text, textarea, URL, number, select, checkbox, image, colour) and an optional HTML template, or embedded-entry blocks that link an entry of another content type. Import and export as JSON.
  • Version history: save versions of a field, preview and restore them; automatic versions during live sessions.
  • Live collaboration: several admins edit the same field at the same time with character-level merging, presence avatars and read-only viewers. Works with several Node processes behind a load balancer without sticky sessions.
  • AI assistant: improve, fix grammar, shorten, expand, summarize, simplify, translate, change tone and continue writing, using Anthropic, OpenAI or any OpenAI-compatible server (for example a local model) with your own key.
  • Strapi-native admin: built with the Strapi Design System, light and dark mode, keyboard accessible, admin in English, German, French, Spanish and Portuguese.
  • Safe content: every value is normalised and sanitised on the server when it is saved, from the Content Manager, the Content API or code.

Screenshots

Editor in the Content Manager, light mode Editor in dark mode
Two admins editing the same field Version history dialog
AI assistant dialog Settings, configuration page
Settings, custom blocks list Custom block form

Editor on a 390 px wide screen

All screenshots use synthetic data.

Core concepts

Term Meaning
Field One Magic Editor X attribute of a content type or component. Its value is an Editor.js document.
Block One entry of the document's blocks array, for example a paragraph or an image. Each block has an id, a type (the block name) and data.
Custom block A block type defined in Settings > Magic Editor X > Custom blocks. Its name becomes the block type.
Version A stored copy (snapshot) of one field of one document in one locale, listed in the version history.
Room The live editing session of one field of one document in one locale. A room exists while people edit and for collaboration.roomTtlMinutes afterwards.
Viewer Someone in a room who can read the document but not update it. Viewers see changes live but cannot type.

Screens

Screen Where Who can open it
Editor field Content Manager, edit view Everyone who can read the field. Uploads, version history and the AI assistant need the permissions in Admin API and permissions.
Version history Clock button in the editor toolbar of a saved document access and Content Manager read on the document; saving and restoring need update.
AI assistant Inline toolbar (select text) access and ai.use, when an administrator turned the assistant on.
Configuration Settings > Magic Editor X > Configuration settings.read (view), settings.update (edit).
Custom blocks Settings > Magic Editor X > Custom blocks custom-blocks.manage.

Compatibility

Plugin Strapi Node Notes
2.x 5.38 or later (acceptance host: Strapi 5.61.1) 22 or 24 SQLite, PostgreSQL and MySQL/MariaDB through the Strapi database connection. Acceptance runs used SQLite and PostgreSQL 16.
1.x 5.x 22 No longer developed.

The admin uses the React, React Router, react-intl, styled-components and Design System versions of the Strapi admin (React 18, Design System 2.2.4).

Install

npm install magic-editor-x

Enable the plugin in config/plugins.ts (or config/plugins.js):

export default ({ env }) => ({
  'magic-editor-x': {
    enabled: true,
    config: {
      // optional, see Configuration
    },
  },
});

Then rebuild the admin and restart:

npm run build
npm run develop

Add the field in the Content-Type Builder: Add another field > Custom > Magic Editor X. In its settings you can set a placeholder and a minimum height (120 to 2000 px).

After the first start, Super Admins can use everything. Other roles need the plugin actions listed in Admin API and permissions (Settings > Administration Panel > Roles > Plugins > Magic Editor X).

Configuration

Reference

All keys are optional. Infrastructure options live in config/plugins; the AI provider is edited at runtime in Settings > Magic Editor X > Configuration.

Key Type Default Effect
debug boolean false Writes debug log lines (never content or personal data).
rawHtml 'sanitize' | 'allow' | 'disable' 'sanitize' Raw HTML block on save: sanitize removes scripts, event handlers, iframes and unsafe URLs; allow stores the HTML as typed; disable empties it.
sanitizeOnSave boolean true Normalise and sanitise Magic Editor X values on every Document Service write. Turning this off is not recommended.
encryptionKey string (32+ characters) unset Key for the stored AI provider key. Prefer the MAGIC_EDITOR_X_ENCRYPTION_KEY environment variable.
uploads.maxImageBytes integer 10485760 (10 MiB) Largest image accepted by file or URL (hard cap 500 MiB).
uploads.maxFileBytes integer 20971520 (20 MiB) Largest attachment.
linkPreview.enabled boolean true Link preview cards. When false, GET /magic-editor-x/link answers 404.
linkPreview.timeoutMs integer 8000 Time limit for fetching a page (1000 to 30000).
api.autoParseJSON boolean true Turn 1.x JSON strings into objects in Content API GET responses.
ai.allowPrivateBaseUrl boolean false Allow AI base URLs on loopback or private networks (for local models). Owner decision; not editable in the admin.
ai.apiKey string unset Provider key from the environment. When set it wins over a key stored in the settings.
ai.requestsPerMinute integer 20 AI requests per admin per minute, counted per process.
ai.timeoutMs integer 60000 Time limit for one provider request.
collaboration.enabled boolean true Live collaboration and its Socket.IO server.
collaboration.path string '/magic-editor-x/realtime' Socket.IO path on the Strapi HTTP server.
collaboration.allowedOrigins string[] [] Extra browser origins allowed to open the socket. The admin URL and the server URL are always allowed.
collaboration.pollIntervalMs integer 400 How often each process reads updates written by other processes (50 to 10000).
collaboration.roomTtlMinutes integer 30 Keep a room's live state this long after the last person left.
collaboration.maxMessageBytes integer 2097152 (2 MiB) Largest accepted socket message.
collaboration.snapshotIntervalMinutes integer 10 Automatic version while people edit live. 0 turns it off.
collaboration.tokenTtlSeconds integer 60 Lifetime of the one-time token that opens the socket.
history.maxSnapshotsPerField integer 50 Versions kept per field and locale; older ones are deleted.

The validator rejects wrong types and ranges at startup and names the key, never the value. Keys from 1.x that no longer exist are ignored with a warning; see Migrating from 1.x.

Environment variables

Name Required Default Effect
MAGIC_EDITOR_X_ENCRYPTION_KEY Only to store an AI key in the settings unset 32 or more characters. Encrypts the AI provider key (AES-256-GCM). Without it the settings page cannot store a key; you can still pass one with ai.apiKey. Generate one with node -e "console.log(require('crypto').randomBytes(32).toString('base64'))". Keep it stable: a different key makes a stored provider key unreadable, and the settings page then asks you to enter it again.

The plugin also uses Strapi's own admin.auth.secret (ADMIN_JWT_SECRET) to sign collaboration tokens. Every process of a cluster must use the same value.

AI settings (admin)

Settings > Magic Editor X > Configuration stores these values in the Strapi store:

Setting Default Range
Enabled off
Provider anthropic anthropic, openai, openai-compatible
Base URL provider default (https://api.anthropic.com, https://api.openai.com); required for openai-compatible https, or private hosts when ai.allowPrivateBaseUrl is on
Model claude-opus-5-5 (Anthropic), gpt-6-luna (OpenAI) letters, digits and ._:/@-
API key none never returned; changing the provider or base URL requires entering it again
Max input characters 8000 200 to 50000
Max output tokens 4096 64 to 16000

Live collaboration

When a document has been saved once, the editor joins the room of its field. Everyone with Content Manager read access to that document, locale and field and the collaborate action can join; people with update access can type, others watch as viewers.

  • Edits merge at character level when two people type in the same text field of a block, and per block otherwise. Every client and server converge on the same document (Yjs CRDT).
  • Presence avatars show who is in the room; the badge shows the connection state (Connecting, Syncing, Live, Reconnecting).
  • Changes made by others become part of your form. Save the entry as usual to store them.
  • Text typed during a short network or server interruption is kept and sent after the reconnect.
  • A new entry that has not been saved yet has no room.
  • Access is checked again every five minutes; an admin who loses access is disconnected.

Running several instances

Collaboration works with several Node processes and several machines that share one database, for example Railway with 2 replicas and pm2 with 4 processes each, behind a load balancer without sticky sessions. No Redis is needed.

How it works:

  • The browser connects with the WebSocket transport only. A WebSocket connection is one long-lived request, so it does not need sticky routing. Your proxy must allow WebSocket upgrades on collaboration.path (default /magic-editor-x/realtime) and send them to Strapi.
  • The session token is signed with a key derived from admin.auth.secret, so any process can accept a token issued by another one. All processes must use the same ADMIN_JWT_SECRET.
  • Every update is written to the table magic_editor_x_collab_updates before it is acknowledged. Other processes read new rows every collaboration.pollIntervalMs and send them to their own sockets.
  • Presence is stored in magic_editor_x_collab_presence with heartbeats; leases and one-time keys in magic_editor_x_locks. Seeding a room, compaction, automatic versions and cleanup each run once across all processes.
  • Clients resynchronise their state every 20 seconds and after each reconnect, so a process restart loses nothing that was acknowledged.

The plugin creates these three tables on startup. They are not content types, so Strapi's schema sync leaves them alone.

Behind a proxy, also set server.proxy in config/server (koa: true and the number of trusted hops in maxIpsCount) so Strapi sees the real client address.

The acceptance run with several processes is described in CONTRIBUTING.md.

AI assistant

The assistant is off until an administrator turns it on in Settings > Magic Editor X > Configuration and gives it a provider:

Provider Request Default model (2026-11-11)
Anthropic POST {base}/v1/messages, headers x-api-key and anthropic-version: 2026-10-21 claude-opus-5-5
OpenAI POST {base}/v1/chat/completions, Authorization: Bearer, max_completion_tokens gpt-6-luna
OpenAI-compatible (Ollama, vLLM, LM Studio and similar) POST {base}/v1/chat/completions, optional bearer key, max_tokens none; you name the model
  • The key stays on the server. It is encrypted at rest with MAGIC_EDITOR_X_ENCRYPTION_KEY or read from ai.apiKey, and it is never sent to the browser or written to logs.
  • The selected text (with its inline formatting) and a fixed instruction are sent to the provider. Nothing else from the document is sent. The text is never logged.
  • Base URLs must be public https URLs. Loopback and private hosts are allowed only with ai.allowPrivateBaseUrl: true in config/plugins. Redirects are not followed.
  • Input is limited by "Max input characters", output by "Max output tokens". Each admin can send ai.requestsPerMinute requests per minute per process.
  • The answer is sanitised to the inline tags the editor uses before it reaches the browser. The admin reviews the suggestion and chooses Replace selection; nothing changes before that.

Data format

The field stores an Editor.js document as JSON:

{
  "time": 1762866000000,
  "version": "2.31.7",
  "blocks": [
    { "id": "kq1x9w0abc", "type": "header", "data": { "text": "Release notes", "level": 2 } },
    {
      "id": "kq1x9w0abd",
      "type": "paragraph",
      "data": { "text": "Read the <a href=\"https://example.test\">guide</a>." },
      "tunes": { "alignmentTune": { "alignment": "left" } }
    }
  ]
}

Data of each block type as stored after sanitising (shared/sanitize-policy.mjs):

Block data
paragraph { text } (inline HTML)
header { text, level: 1-6 }
list { style: 'ordered' | 'unordered' | 'checklist', meta?: { start?, counterType? }, items: [{ content, meta?, items: [...] }] }
checklist { items: [{ text, checked }] }
quote { text, caption, alignment: 'left' | 'center' }
warning { title, message }
alert { type: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark', align: 'left' | 'center' | 'right', message }
toggle { text, status: 'open' | 'closed', fk?, items } (the next items blocks are its content)
code { code } (plain text)
codeFlask { code, language, showlinenumbers? }
raw { html } (see rawHtml)
table { withHeadings, stretched, content: string[][] }
image { file: { url, mime?, alt?, width?, height?, size?, formats?, id?, documentId? }, caption, withBorder, withBackground, stretched }
simpleImage { url, caption, withBorder, withBackground, stretched }
linkTool { link, meta: { title, description, site_name?, image?: { url } } }
attaches { file: { url, name?, extension?, size?, title? }, title }
embed { service, source, embed, width?, height?, caption } (embed is always https)
personality { name, description, link, photo }
button { text, link, style, openInNewTab }
delimiter {}
custom simple block { content, <field values>, blockType: 'simple', blockName }
custom embedded-entry block { entry: { id, documentId, title, <display fields> }, contentType, displayMode }

Inline HTML may contain b, strong, i, em, u, s, mark, code, a (href, target, rel, title), br, span (class cdx-tooltip with data-tooltip), sub and sup. Links allow http, https, mailto, tel and relative URLs. Escape plain-text fields (code, personality, button.text, link card text) when you render them.

Tunes are stored per block in tunes: alignmentTune: { alignment }, textVariant: '' | 'call-out' | 'citation' | 'details', indentTune: { indentLevel }.

The Content API returns the object as stored. Entries saved with 1.x may still contain a JSON string until they are saved again; with api.autoParseJSON (default) the plugin parses such strings in Content API GET responses.

Admin API and permissions

Permissions

Action Label in Roles Gates
plugin::magic-editor-x.access Use the editor (uploads, link previews, custom blocks, version history) Editor configuration, link previews, uploads (with the Media Library permission), content type list, custom block list, version history, collaboration and AI routes
plugin::magic-editor-x.collaborate Edit together in real time Joining live rooms
plugin::magic-editor-x.ai.use Use the AI assistant AI requests
plugin::magic-editor-x.custom-blocks.manage Manage custom blocks Settings > Custom blocks and its routes
plugin::magic-editor-x.settings.read Read settings Settings > Configuration (read)
plugin::magic-editor-x.settings.update Update settings Saving settings, testing the AI connection

Uploads also need the Media Library action plugin::upload.assets.create. Version history and collaboration also apply the Content Manager permissions of the document: read access (including conditions such as "is creator", locale and field permissions) to list versions and join a room, update access to save versions, restore and type. A document you cannot read answers 404, the same as a document that does not exist.

Super Admins have all actions. The access action keeps its 1.x id, so roles that had it keep using the editor.

Routes

All routes are admin routes served at /magic-editor-x/... and need an admin session (Authorization: Bearer <admin JWT>). There are no Content API routes. Errors use the Strapi envelope { "data": null, "error": { "status", "name", "message", "details" } }; validation errors carry details.fieldErrors keyed by field path. Editor.js tool routes answer { "success": 0, "message" } on errors, as the tools expect.

Method Path Actions Body / query Response
GET /magic-editor-x/config access { data: { collaboration, ai, uploads, linkPreview, rawHtml, permissions } }
GET /magic-editor-x/link access ?url= { success: 1, link, meta }
POST /magic-editor-x/image/byFile access, upload multipart image { success: 1, file: { url, ... } }
POST /magic-editor-x/image/byUrl access, upload { url } { success: 1, file }
POST /magic-editor-x/file/upload access, upload multipart file { success: 1, file: { url, name, title, size, extension } }
GET /magic-editor-x/content-types access { data: [{ uid, kind, displayName, attributes }] } (types you can read)
GET /magic-editor-x/custom-blocks access (?all=true also needs custom-blocks.manage) ?all=true { data: [block] }
GET /magic-editor-x/custom-blocks/export custom-blocks.manage { data: { format: 'magic-editor-x/custom-blocks', version: 2, exportedAt, blocks } }
POST /magic-editor-x/custom-blocks/import custom-blocks.manage export document { data: { created: [name], skipped: [{ name, reason }] } }
PUT /magic-editor-x/custom-blocks/order custom-blocks.manage { ids } (every block once) { data: [block] }
POST /magic-editor-x/custom-blocks custom-blocks.manage block definition 201 { data: block }
PUT /magic-editor-x/custom-blocks/:id custom-blocks.manage full block definition { data: block }
DELETE /magic-editor-x/custom-blocks/:id custom-blocks.manage { data: { id } }
POST /magic-editor-x/custom-blocks/:id/duplicate custom-blocks.manage 201 { data: block }
POST /magic-editor-x/collaboration/session access, collaborate { uid, documentId, locale?, field, initialValue? } { data: { token, path, canEdit, expiresAt } }
GET /magic-editor-x/history access ?uid&documentId&locale&field { data: [version], meta: { canRestore, canCreate } }
GET /magic-editor-x/history/:id access { data: { ...version, content } }
POST /magic-editor-x/history access { uid, documentId, locale?, field, content } 201 new version, 200 with meta.created: false when unchanged
POST /magic-editor-x/ai/:action access, ai.use { text, language?, tone? } { data: { text } }
GET /magic-editor-x/settings settings.read { data: { ai, environment } } (no secrets)
PUT /magic-editor-x/settings settings.read, settings.update { ai: { enabled, provider, baseUrl, model, maxInputChars, maxOutputTokens, apiKey? } } { data: { ai, environment } }
POST /magic-editor-x/settings/ai/test settings.read, settings.update { ai: {...} } { data: { ok: true } }

upload means plugin::upload.assets.create. AI actions: improve, grammar, shorten, expand, summarize, simplify, translate (with language), tone (with tone), continue. Provider problems answer with name: 'AIProviderError' and details.code (DISABLED, NOT_CONFIGURED, NO_API_KEY, AUTH_FAILED, PROVIDER_RATE_LIMIT, TIMEOUT, REFUSED, PROVIDER_ERROR). Too long text answers 413, too many requests 429.

Example: save a version.

POST /magic-editor-x/history
Authorization: Bearer <admin JWT>
Content-Type: application/json

{ "uid": "api::article.article", "documentId": "k9d2w4xq8m1n0p3r5t7v9b1c", "locale": "en", "field": "body",
  "content": { "blocks": [{ "id": "a1", "type": "paragraph", "data": { "text": "Hello" } }] } }
{
  "data": {
    "id": "s8f2k1x0w9q7e5r3t1y6u4i2",
    "version": 3,
    "trigger": "manual",
    "createdAt": "2026-11-11T09:30:00.000Z",
    "createdBy": "Anna Beispiel",
    "stats": { "blocks": 1, "words": 1, "characters": 5 },
    "restorable": true
  },
  "meta": { "created": true }
}

Security and privacy

  • Stored content: every Magic Editor X value is normalised and sanitised on save by a Document Service middleware (Content Manager, Content API, imports and code). Unknown keys of known block types are dropped, URLs are checked, inline HTML is limited to the tags above and the raw HTML block follows rawHtml. Values over 5 MiB, with more than 5000 blocks or nested deeper than 24 levels are rejected with 400, never truncated. The admin sanitises again before rendering (DOMPurify with the same rules).
  • Outgoing requests: link previews and images by URL only fetch public http(s) addresses: the host is resolved once, every address must be public, the connection is pinned to that address, redirects are re-checked (at most 3), and size, type and time are limited. The AI provider is called only when an administrator configured it.
  • Uploads are checked by their first bytes (not by the file name or the browser's MIME type) and stored through the Media Library with the admin as creator.
  • Collaboration: tokens are signed, expire after collaboration.tokenTtlSeconds and work once; the socket accepts the admin and server origins and collaboration.allowedOrigins; messages are size-limited and must be valid Yjs updates; viewers cannot write.
  • Secrets: the AI key is encrypted with AES-256-GCM (random IV, versioned format) and never returned. Changing the provider or base URL requires entering the key again, so a stored key cannot be sent to another host.
  • Logs contain operation names and error codes only, never content, URLs with queries, tokens, user ids or email addresses.
  • Stored data: custom block definitions, versions (field content and the admin who saved it), live rooms (Yjs updates, removed collaboration.roomTtlMinutes after the last person left) and presence rows (admin display name, colour, caret position; removed when the socket closes or after missed heartbeats).
  • Content Security Policy: Editor.js and the Design System add inline styles, which Strapi's default style-src 'unsafe-inline' allows. The socket connects to the same origin as the admin, which connect-src 'self' covers; add the wss: origin only when the admin runs on another host. Embed iframes need frame-src only on your frontend.

Report vulnerabilities privately through GitHub security advisories on the repository.

Troubleshooting

Symptom Cause Fix
The field shows "The editor could not be loaded." The role lacks plugin::magic-editor-x.access, or the server is unreachable Grant the action; check the server log.
No upload or "You do not have permission to upload files" The role lacks plugin::upload.assets.create Grant Media Library create to the role.
No version history (clock) button The entry was never saved Save the entry once.
Badge shows "Live editing unavailable" No collaborate action, no read access to the document, or collaboration.enabled: false Grant the action or check the Content Manager permissions.
Badge stays at "Connecting" or "Reconnecting" The proxy does not forward WebSocket upgrades on collaboration.path, or the origin is not allowed Allow upgrades on the path; add the admin origin to collaboration.allowedOrigins when the admin runs on another host.
Settings say the API key cannot be stored MAGIC_EDITOR_X_ENCRYPTION_KEY is missing or shorter than 32 characters Set the variable and restart, or use ai.apiKey.
Settings say the stored key is unreadable The encryption key changed Enter the provider key again.
AI error "The AI provider rejected the key." Wrong key for this provider Enter the key again and use Test connection.
Startup error [magic-editor-x] invalid configuration for: <key> Wrong type or range in config/plugins Fix the named key (see the reference table).
400 "A Magic Editor X field contains invalid content" The value is not editor JSON, too large or too deep Send an Editor.js object within the limits.

Migrating from 1.x

2.0 is a major release. Stored content keeps working; routes, permissions and configuration changed. The full guide is in the CHANGELOG. In short:

  1. Update the package and rebuild the admin: npm install magic-editor-x@2 && npm run build.
  2. Remove 1.x configuration keys (enabledTools, linkPreviewTimeout, maxImageSize, maxFileSize, allowedImageTypes, collaboration.wsPath, wsUrl, sessionTTL, allowedAdminRoles, allowedAdminUserIds, cors) and use the new keys above.
  3. Grant the new actions to your roles: collaborate, ai.use, custom-blocks.manage, settings.read, settings.update. Collaboration grants from 1.x are replaced by Content Manager permissions; Strapi drops the old tables on the first start.
  4. If you used the AI assistant, configure your own provider in Settings > Magic Editor X > Configuration.
  5. If your raw HTML blocks need scripts or iframes, set rawHtml: 'allow'.

On the first start the plugin converts 1.x versions that only contained collaboration state and cleans custom block icons and templates. Both run once across all processes.

Development and tests

npm ci
npm run lint
npm run format:check
npm test                  # unit tests, no Strapi host needed
npm run build             # admin and server bundles, then a runtime check
npm run verify
MEX_HOST_URL=http://127.0.0.1:1421 MEX_CREDS=/path/to/creds.json npm run test:integration

CONTRIBUTING.md explains the isolated acceptance host, the integration suite on SQLite and PostgreSQL and the multi-process acceptance run. AGENTS.md is the contract for coding agents.

Maintenance status

Actively maintained. Releases are made with semantic-release from main; every release runs lint, tests, build, package verification and a production dependency audit first. Supported line: Strapi 5.

Languages

The admin is translated into English, German (formal Sie), French, Spanish and Portuguese.

License

MIT © 2025-2026 Schero D.

About

Free, MIT-licensed block editor for Strapi 5: live collaboration across servers, version history, custom blocks, Media Library uploads and an optional AI assistant with your own provider.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages