emdash

n8n community node integration for EmDash CMS

Package Information

Released: this month
Downloads: 0 weekly / 0 monthly
Latest Version: 0.1.4
Author: Christopher J. Nelson

Available Nodes

Documentation generating…

Documentation

n8n-nodes-emdash

Consume and manage content, media, menus, schemas, taxonomies, search, URL redirects, comments, settings, sections, and widget areas from EmDash CMS in n8n workflows.

This is an independent Black Swamp AI community integration. It is not affiliated with, endorsed by, sponsored by, or maintained by EmDash or Cloudflare Inc. Product names and marks belong to their respective owners and are used only to identify compatibility.

Installation · Compatibility · Credentials · Operations · Migration · Usage · Troubleshooting · Resources · Black Swamp AI

Installation

On self-hosted n8n instances, install this community node through the n8n web interface:

  1. Open Settings → Community Nodes in your n8n workspace.
  2. Select Install a community node.
  3. Enter @blackswampai/n8n-nodes-emdash in the npm package name field.
  4. Agree to the risks of installing third-party code and select Install.

For additional guidance on managing community nodes, see the n8n Community Nodes installation documentation.

Compatibility

Surface Tested baseline Notes
n8n 2.30.6 Runtime, picker-source, and user-verified picker baseline
EmDash CMS v1 (emdash@1.0.1+) Cloudflare Workers REST API endpoint
Node.js development 22.22.0 and 24 CI and package checks run on both lanes.

Credentials

To authenticate with your EmDash instance:

EmDash API Credential

  1. In n8n, create an EmDash API credential.
  2. Site URL: Enter the root URL of your EmDash installation (for example, https://cms.example.com). The node automatically normalizes trailing slashes and routes requests through the /_emdash/api endpoint prefix.
  3. API Token: Enter a Personal Access Token (PAT) generated in your EmDash administrative panel.

Personal Access Token Scopes and RBAC

EmDash 1.0.1 defines the following valid PAT scopes: content:read, content:write, media:read, media:write, schema:read, schema:write, taxonomies:manage, menus:manage, settings:read, settings:manage, mcp:tools, transfer:export, transfer:analyze, transfer:execute, and admin.

Effective authorization requires both the PAT scope and the user's underlying RBAC role. Scopes required by resource:

  • Content operations:
    • Read queries (GET) require content:read. Write and mutation operations (including creation, updates, publish, unpublish, schedule, unschedule, duplicate, restore, and permanent delete) require content:write. (EmDash does not use a separate content:publish scope).
    • Editorial and collaboration operations:
      • Get Translations: PAT content:read, RBAC content:read (non-published variants filtered without content:read_drafts).
      • Get Authors: PAT content:read, RBAC content:read_drafts (editorial draft visibility due to author PII and email).
      • Get Trashed: PAT content:read, RBAC content:read_drafts.
      • Get Edit Lock: PAT content:read, RBAC content:edit_own / content:edit_any.
      • Acquire Edit Lock: PAT content:write, RBAC content:edit_own / content:edit_any.
      • Release Edit Lock: PAT content:write, RBAC content:edit_own / content:edit_any.
    • Important note on token scopes: There is NO Personal Access Token scope named content:read_drafts. Draft visibility is enforced via internal user RBAC role capabilities under the content:read PAT scope.
  • Media operations: Read queries (GET) generally require media:read, except Get Usage which requires Personal Access Token scope admin (not media:read) alongside RBAC capabilities media:read + content:read_drafts. For Get and Get Many with includeUsage=1, an inline coverage-aware usage summary is returned, but usage.count is only readable when the caller holds both the RBAC content:read_drafts capability and, when authenticated by a PAT/OAuth token, the admin token scope (a media:read PAT alone cannot expose draft-derived usage counts). Mutations (binary uploads, staged upload target generation, raw chunk uploads, confirmation, image replacement, metadata updates, folder creation, folder rename, and file/folder deletion) require media:write.
  • Menu operations:
    • PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require menus:manage (which is also implicitly granted by content:write or admin). EmDash does NOT define menus:read, menu:read, or menu:write as Personal Access Token scopes.
    • RBAC permissions: The authenticated user must separately possess the menus:read capability for reads, and menus:manage capability (Editor or Administrator role) for mutations.
  • Taxonomy operations: Read queries (GET) require content:read. Bulk tagging requires content:write. Schema mutations and term management require taxonomies:manage (implicitly granted by content:write or admin). (EmDash does not define taxonomy:read or taxonomy:write scopes).
  • Search operations: Queries and prefix suggestions require content:read. Administrative operations (rebuilding an index or enabling search on a collection) require admin. (EmDash does not define search:read or search:admin scopes).
  • Redirect operations: Neither redirects:read nor redirects:write exists as a PAT scope. All redirect rules and 404 access log operations require admin due to fail-closed middleware scope enforcement.
  • Schema operations:
    • PAT scopes: Read queries (GET) require schema:read (or admin). Write and mutation operations (POST, PUT, DELETE) require schema:write (or admin).
    • RBAC permissions: Reads require the schema:read capability. Schema modifications require schema:manage (Administrator or Developer role).
    • Write-only token discovery fallback: Tokens possessing only schema:write can execute mutations but cannot access read endpoints used by editor listSearch selectors. Every collection and field resource locator provides a manual "By Slug" mode to allow workflow execution with write-only credentials.
  • Comment moderation operations: EmDash does not define granular comments:* PAT scopes (such as comments:read or comments:moderate). All comment moderation endpoints live under /_emdash/api/admin/comments and strictly require a Personal Access Token with the admin scope in combination with administrative RBAC permissions.
  • Settings operations:
    • PAT scopes: Read queries (GET) require settings:read (or admin). Update operations (POST) require settings:manage (or admin).
    • RBAC permissions: The authenticated user must separately possess the settings:read capability for reads, and settings:manage capability (Administrator role) for updates.
  • Section operations:
    • PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate sections:* PAT scopes.
    • RBAC permissions: The authenticated user must separately possess the sections:read capability for reads, and sections:manage capability (Editor or Administrator role) for mutations.
  • Widget Area operations:
    • PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate widgets:* PAT scopes.
    • RBAC permissions: The authenticated user must separately possess the widgets:read capability for reads, and widgets:manage capability (Editor or Administrator role) for mutations.

Operations

The EmDash community node provides 103 operations across 11 core resources:

Comment (6 operations)

  • Get Many (getAll): Retrieve comments with cursor pagination and status, collection, and search filters.
  • Get Counts (getCounts): Retrieve comment counts grouped by moderation status (pending, approved, spam, trash).
  • Get (get): Retrieve a single comment by ID including author metadata, IP hash, and status.
  • Update Status (updateStatus): Update the moderation status of a comment (approved, pending, spam, trash).
  • Bulk Action (bulkAction): Apply moderation action (approve, spam, trash) or permanently delete up to 100 comments in a single request.
  • Delete (delete): Permanently delete a comment by ID (irreversible).

Content (22 operations)

  • Get Many (getAll): Retrieve entries in a collection with cursor pagination, publication status filtering, and date ranges.
  • Get (get): Retrieve a single content item by ID or URL slug.
  • Create (create): Create a draft content entry with JSON data, SEO metadata, locale, and taxonomy terms.
  • Update (update): Mutate existing content with optimistic concurrency control (_rev).
  • Delete (delete): Soft delete an entry to trash.
  • Publish (publish): Promote draft changes to live version.
  • Unpublish (unpublish): Revert published live entry to draft.
  • Schedule (schedule): Set a future publication timestamp.
  • Unschedule (unschedule): Cancel scheduled publication.
  • Duplicate (duplicate): Clone an existing entry into a new draft.
  • Restore (restore): Restore a trashed entry.
  • Permanently Delete (permanentDelete): Hard delete a trashed entry.
  • Compare Draft and Live (compare): Diff draft changes against the live version.
  • Discard Draft (discardDraft): Discard pending draft edits and revert to live version.
  • Get Content Terms (getContentTerms): Retrieve taxonomy terms assigned to an entry.
  • Set Content Terms (setContentTerms): Replace taxonomy term assignments on an entry.
  • Get Translations (getTranslations): Retrieve translation variants linked to the same translation group.
  • Get Authors (getAuthors): Retrieve distinct authors of content items within a collection.
  • Get Trashed (getTrashed): Retrieve soft-deleted content items in a collection with cursor pagination and locale filtering.
  • Get Edit Lock (getLock): Check current edit lock status and holder information for a content item.
  • Acquire Edit Lock (acquireLock): Acquire or refresh an edit lock lease on a content item.
  • Release Edit Lock (releaseLock): Release the caller’s edit lock lease on a content item.

Media (15 operations)

  • Get Many (getAll): List media files with cursor pagination, MIME type, folder filtering, and case-insensitive filename substring search (q). Note: includeUsage provides a coverage-aware usage summary; usage.count is null unless the caller holds both the RBAC content:read_drafts permission and admin token scope (use Get Usage for complete usage references).
  • Get (get): Get metadata for a media file by ID. Note: includeUsage provides a coverage-aware usage summary (usage.count is null unless caller holds both the RBAC content:read_drafts permission and admin token scope).
  • Upload (upload): Upload binary files directly via multipart form data, with optional fieldId allowlist targeting, pixel dimensions (width, height), and LQIP placeholder thumbnail (thumbnailBinaryPropertyName).
  • Replace Image (replaceImage): Replace the binary file of an existing image (image/jpeg, image/png, or image/webp) while preserving its ID, filename, and storage identity. Updates bytes, size, dimensions, and content hash, while invalidating and explicitly resetting blurhash, dominantColor, and focalX/focalY to null (does not regenerate derived metadata). Requires positive integer width and height.
  • Get Upload Target (getUploadTarget): Initiate a staged upload workflow by requesting a pre-signed or direct upload destination for a pending file (filename, contentType, size). When deduplication (deduplicate: true) is enabled and a matching checksum is found, the endpoint short-circuits the upload and immediately returns { existing: true, mediaId, storageKey, url }.
  • Upload Pending File (uploadPending): Upload raw binary data directly to the staged upload URL / pending media endpoint (PUT /media/{id}/upload) using raw binary streaming (Content-Type, Content-Length) rather than multipart form data.
  • Confirm Upload (confirmUpload): Finalize a staged media upload (POST /media/{id}/confirm) after binary data has been written, optionally recording validated size, width, and height.
  • Update Metadata (update): Update media title, alt text, caption, focal points (focalX and focalY must be provided together between 0.0 and 1.0, or cleared via clearFocalPoint/null), positive integer dimensions, or folder (use "unfiled" or empty string to unfile).
  • Delete (delete): Delete a media record and associated storage file.
  • Get Usage (getUsage): Retrieve content entries and site settings referencing a media file with cursor pagination (cursor, limit). Requires PAT scope admin and RBAC media:read + content:read_drafts.
  • Get Many Folders (getAllFolders): List media folders.
  • Get Folder (getFolder): Get single media folder metadata by ID.
  • Create Folder (createFolder): Create a new folder to organize media assets.
  • Update Folder (updateFolder): Update media folder name.
  • Delete Folder (deleteFolder): Delete a media folder (unfiles referencing media items by setting folder_id to null; does not require the folder to be empty).

Menu (9 operations)

  • Get Many (getAll): Retrieve all navigation menus with optional locale filtering.
  • Get (get): Retrieve a single menu and its navigation item hierarchy by menu name with optional locale filtering.
  • Create (create): Create a new navigation menu with name and label; optionally configure target locale or translate an existing menu (translationOf).
  • Update (update): Update a menu label with optional locale filtering.
  • Delete (delete): Permanently delete a menu and all its navigation items for the targeted menu and locale (does not delete referenced content).
  • Create Item (createItem): Add a navigation item to a menu (custom, page, post, taxonomy, or collection) with optional parent, ordering, target, and styling.
  • Update Item (updateItem): Update navigation item label, URL, target, attributes, parent, or sort order (supports explicit null to move items to root).
  • Delete Item (deleteItem): Remove a navigation item from a menu (does not delete referenced content).
  • Reorder Items (reorderItems): Atomically update menu hierarchy and sibling ordering via an array of item IDs, parent references, and sort positions.

Redirect (9 operations)

  • Get Many (getAllRedirects): List URL redirect rules with cursor pagination and search, group, enabled, auto filters.
  • Get (getRedirect): Retrieve redirect rule by ID.
  • Create (createRedirect): Create a redirect rule (301, 302, 307, 308, 410, 451).
  • Update (updateRedirect): Update redirect rule source, destination, status code, enabled state, or group.
  • Delete (deleteRedirect): Delete a redirect rule by ID.
  • Get 404 Entries (get404Entries): Retrieve recorded 404 Not Found error entries with cursor pagination and search filter.
  • Get 404 Summary (get404Summary): Retrieve aggregation summary of top 404 error paths.
  • Prune 404 Log (prune404Log): Delete 404 error log entries older than an ISO 8601 datetime threshold.
  • Clear All 404 Entries (clear404Log): Destructively delete all recorded 404 log entries.

Schema (12 operations)

  • Get Many Collections (getCollections): Retrieve all collections defined in the schema.
  • Get Collection (getCollection): Retrieve a single collection schema by slug, optionally including its field definitions (includeFields).
  • Create Collection (createCollection): Register a new collection schema with slug, label, and optional metadata (supports, admin, source, urlPattern, routable, hasSeo, hidden, sortOrder, editLocking, group). Server defaults for supports are preserved when omitted.
  • Update Collection (updateCollection): Update collection schema label, metadata, comments moderation, or title/date field bindings (rejects empty updates). Use sortOrder (integer) to update sidebar position, or enable clearSortOrder: true (or pass sortOrder: null) to clear explicit sidebar position and revert to default alphabetical ordering (note that sortOrder and clearSortOrder are mutually exclusive).
  • Delete Collection (deleteCollection): Permanently deletes the collection schema and drops its underlying content table. Relations involving the collection are also removed, which cascades to bound reference fields on other collections. When content exists, deletion fails unless force=true is explicitly provided.
  • Reorder Collections (reorderCollections): Update admin sidebar display order of collections via an array of collection slugs. Listed collections receive explicit positions 0..N; omitted collections have explicit order cleared and sort alphabetically. Rejects unknown or duplicate slugs.
  • Get Many Fields (getFields): Retrieve all field definitions for a collection schema.
  • Get Field (getField): Retrieve a single field schema by slug within a collection.
  • Create Field (createField): Add a new field definition to a collection schema across 17 supported field types (string, text, url, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug, repeater, blocks). Field constraints (validation) and widget rendering options (options) are passed as flexible JSON objects. For new reference fields, specify targetCollection in the validation JSON (e.g. { "targetCollection": "authors" }). Referenced block types must already exist in EmDash.
  • Update Field (updateField): Update an existing field schema's label, type, options, widget, or validation rules (rejects empty updates). Passing empty string "" clears the widget (JSON null is rejected upstream by the EmDash schema with VALIDATION_ERROR). Note that target collection on an active reference field is immutable. Upstream enforces strict migration restrictions: mutating required, unique, or setting translatable: false requires manual content migration and is rejected upstream with FIELD_UPDATE_REQUIRES_MIGRATION; type changes across SQL column affinities are rejected with FIELD_TYPE_COLUMN_CHANGE (compatible text-alias transitions such as text to string or no-op reassertions succeed).
  • Delete Field (deleteField): Permanently deletes the field and drops its column from the content table. When deleteRelation=true is enabled on a reference field, it also cascades to delete the underlying relationship, all relation edges, and the field bound to the opposite side of the relation on the other collection.
  • Reorder Fields (reorderFields): Update field display ordering within a collection via an array of field slugs. Upstream updates each supplied field slug sequentially; partial field lists update only listed fields while omitted fields retain existing sort orders (which may cause position collisions); unmatched or unknown field slugs silently update 0 rows without error (returns 200, unlike reorderCollections which returns 404); duplicate slugs are rejected locally; provide the complete field list for deterministic ordering.

Caution on Schema Mutations:

  • Collection Deletion: Dropping a collection is irreversible and removes the backing SQLite table and all content entries. Always test with disposable collections.
  • Reference Field Cascade: Deleting a reference field with deleteRelation=true cascades across collection boundaries, modifying the schema of the related collection by removing the reciprocal field.

Search (5 operations)

  • Search (search): Full-text search across indexed content with cursor pagination, collections filter, locale, status, and scope (all or title).
  • Suggest (suggest): Autocompletion prefix suggestions with collection and locale filters.
  • Get Stats (getStats): Retrieve search index statistics and document counts.
  • Rebuild Index (rebuildIndex): Trigger a search index rebuild for a specific collection.
  • Enable / Configure Search (enableSearch): Configure SQLite FTS5 search indexing for a collection, including tokenizer strategies (porter unicode61, unicode61, trigram) and column weight mapping.

Section (5 operations)

  • Get Many (getAll): Retrieve sections with cursor pagination and optional source (theme, user, import) or search filters.
  • Get (get): Retrieve a single section by slug.
  • Create (create): Create a new section with slug, title, structured JSON content, and optional description, keywords, preview media ID, source (user or import), or theme ID.
  • Update (update): Update section slug, title, description, keywords, structured JSON content, or preview media ID (pass null or empty string to clear preview media).
  • Delete (delete): Delete a custom or imported section (theme-defined sections are protected and cannot be deleted).

Settings (2 operations)

  • Get (get): Retrieve current site settings object directly from the CMS without static schema constraints.
  • Update (update): Update site settings with a validated JSON object or expression via POST /settings (merges updates with existing settings; unspecified settings remain unchanged).

Taxonomy (10 operations)

  • Get Many (getAllTaxonomies): List all registered taxonomies.
  • Get (getTaxonomy): Retrieve taxonomy schema and metadata.
  • Update (updateTaxonomy): Update taxonomy schema (label, labelSingular, hierarchical, collections).
  • Delete (deleteTaxonomy): Delete taxonomy definition and its terms.
  • Get Many Terms (getAllTerms): List terms within a taxonomy.
  • Get Term (getTerm): Retrieve single taxonomy term by slug.
  • Create Term (createTerm): Create a new term with label, slug, description, parent, and locale.
  • Update Term (updateTerm): Update an existing term by slug.
  • Delete Term (deleteTerm): Delete a term from a taxonomy.
  • Reorder Terms (reorderTerms): Update display ordering of taxonomy terms (POST /taxonomies/{name}/reorder).

Widget Area (8 operations)

  • Get Many (getAll): Retrieve all registered widget areas with their widgets.
  • Get (get): Retrieve a widget area by name including its ordered widgets.
  • Create (create): Register a new custom widget area with name, label, and optional description.
  • Delete (delete): Delete a widget area (cascades deletion to all contained widgets).
  • Create Widget (createWidget): Add a widget (content with structured content blocks, menu with menu name, or component with component ID and JSON properties) to a widget area.
  • Update Widget (updateWidget): Update widget type, title, content blocks, menu name, component ID, or component properties.
  • Delete Widget (deleteWidget): Remove a widget from a widget area (does not delete referenced content, menus, or components).
  • Reorder Widgets (reorderWidgets): Update display ordering of widgets in an area using an ordered array of widget IDs.

Existing trigger workflows

Version 0.1.4 removes the EmDash webhook trigger because the EmDash webhook notifier plugin is currently broken and its event delivery cannot be verified. After upgrading, existing workflows that contain emdashTrigger will have a missing node and must be migrated before they can run. Replace it with Schedule Trigger and EmDash actions to poll for changes, or use another independently supported event source.

Usage

Declarative architecture

This integration relies on declarative routing throughout the node definition. Binary uploads use preSend hooks to construct multipart form payloads directly in memory, and response envelopes use postReceive hooks to unwrap API payloads. Any irregular or nested API structures (such as generic "weird JSON" payloads) are addressed declaratively with JMESPath or parameter expressions rather than requiring programmatic execution.

Dynamic collection discovery

Collection, folder, and taxonomy fields use n8n resource locators. You can select items interactively from a live EmDash instance or toggle to manual mode to provide dynamic expressions or IDs from upstream workflow nodes.

Cursor pagination

List operations support EmDash opaque cursor pagination. Set Return All to true to fetch all available records automatically, or disable it and specify a custom Limit.

Staged and Direct Media Upload Workflows

EmDash CMS supports both single-step direct uploads and multi-step staged uploads:

  • Direct Upload (upload):

    • Upload binary assets directly in one request via multipart form data (POST /media).
    • Supports optional folder placement (folderId), duplicate checksum matching (deduplicate: true), automatic filename collision avoidance (ensureUniqueFilename: true), field allowlist enforcement (fieldId), explicit image dimensions (width, height), and downscaled thumbnail binary attachments (thumbnailBinaryPropertyName) for low-quality image placeholder (LQIP) generation.
  • Staged Upload Workflow (getUploadTarget → uploadPending → confirmUpload):

    • Recommended for large files, streaming pipelines, or decoupled architectures.
    • Step 1: Get Upload Target (POST /media/upload-url):
      • Registers a pending upload with filename, MIME contentType, and file size in bytes (must be an integer $\ge 0$).
      • Optional fields include contentHash, fieldId, deduplicate, ensureUniqueFilename, and folderId (passing 'unfiled' or empty string places the item at root).
      • Deduplication short-circuit: When deduplicate: true is enabled and a matching checksum is detected, the EmDash API short-circuits the upload flow and immediately returns the existing media asset:
        {
          "existing": true,
          "mediaId": "...",
          "storageKey": "...",
          "url": "..."
        }
        
        In this case, downstream Upload Pending File and Confirm Upload steps must be skipped.
    • Step 2: Upload Pending File (PUT /media/{id}/upload):
      • Writes the raw file binary buffer directly to the pending media endpoint using raw binary streaming (Content-Type and Content-Length headers). Unlike direct upload, this does not wrap data in multipart form boundaries, maximizing throughput and minimizing memory overhead.
    • Step 3: Confirm Upload (POST /media/{id}/confirm):
      • Finalizes the pending upload and transitions the asset to ready state.
      • Optionally supplies verified size ($\ge 0$), width ($> 0$), and height ($> 0$) dimensions. Unconfigured dimensions are not defaulted to 0.
  • Image Replacement (replaceImage):

    • The PUT /media/{id}/replace endpoint replaces the binary file of an existing image asset (image/jpeg, image/png, or image/webp).
    • Preserves the existing media record's ID, filename, creation timestamp, and storage key / URL identity while updating file size, width, height, and content hash.
    • Image replacement does NOT regenerate derived image metadata: upstream explicitly invalidates and resets blurhash to null, dominantColor to null, focalX to null, and focalY to null.
    • Requires positive integer width and height parameters. Replacement MIME type must exactly match the original item.
  • Media Usage Reference Inspection (getUsage):

    • Querying referencing content entries and site settings requires Personal Access Token scope admin (not media:read) alongside RBAC capabilities media:read and content:read_drafts.
    • Supports cursor pagination via cursor and limit (1–100, default 50).
    • Preserves the complete response payload (items, nextCursor, siteSettings, coverage) without auto-flattening or stripping.
    • In Get Many (getAll) and Get (get), the includeUsage toggle attaches an inline usage summary; however, usage.count remains null unless the caller possesses both the RBAC content:read_drafts permission and the admin token scope (a media:read PAT alone cannot expose draft-derived usage counts). Dedicated media reference inspection via Get Usage (GET /media/{id}/usage) separately requires PAT scope admin, RBAC media:read, and RBAC content:read_drafts.

Collaborative edit locks and concurrency control

EmDash provides dual-layer write protection to prevent conflicting edits in multi-user editorial environments:

  • Collaborative edit locks:
    • Edit locks coordinate active editing sessions between users and automated workflows to prevent accidental overwrites during active authoring.
    • Locks currently use a 7-minute lease in EmDash 1.0.1 and expire automatically unless refreshed. Calling Content → Acquire Edit Lock on an item already locked by the caller refreshes this lease duration.
    • Session tokens (token): Specify an optional caller session token (up to 128 characters) when acquiring an edit lock. When releasing the lock via Content → Release Edit Lock, supplying the same token ensures that one workflow session does not inadvertently release a lock another session still relies on.
    • Takeover risk (takeover: true): Callers must already be authorized to edit the entry (owned content may be authorized through content:edit_own, while other content requires content:edit_any). Once authorized, enabling takeover: true allows the caller to replace the active lock holder. Use this with caution: breaking an active lease will disrupt the current editor's in-flight work.
  • Relationship between edit locks and _rev:
    • Edit locks coordinate collaborative presence and in-flight sessions; _rev revision tokens provide optimistic concurrency control at write/commit time.
    • Neither replaces the other: holding an edit lock does not eliminate the need for _rev checks during updates, and supplying _rev does not bypass an edit lock held by another editor unless overrideLock: true is explicitly provided. Workflows should use edit locks to coordinate long-running editorial tasks and pass _rev to guarantee data integrity against stale writes.

Author discovery and privacy

The Content → Get Authors operation returns distinct author records for a collection, including author name, user ID, email address, and avatar URL. Workflows that process or forward author information to notifications, external integrations, or analytics platforms must handle these records responsibly and comply with applicable privacy standards (such as GDPR or internal data handling policies).

Comment moderation and privacy

Comment records returned by moderation endpoints contain commenter personal information, including author email (authorEmail) and cryptographic IP hash (ipHash). Workflows that process or forward comment outputs to notification channels, logs, or external systems should handle and redact these fields appropriately in accordance with organizational privacy standards.

Automated comment moderation workflows

To automate comment moderation workflows (such as AI content analysis, automated spam detection, or alerts), configure an n8n workflow using the Schedule Trigger node to periodically poll Comment → Get Many filtered by status: pending.

Menu management and hierarchy semantics

The Menu resource enables full lifecycle management of EmDash navigation structures, supporting multi-level hierarchies, localized menu variants, and referenced or custom navigation links:

  • Token scope and RBAC: EmDash enforces two distinct authorization layers:
    • Personal Access Token (PAT) Scopes:
      • Menu reads (GET): requires content:read
      • Menu writes (POST, PUT, DELETE): requires menus:manage (or content:write, which implicitly grants menus:manage, or admin)
      • Caution: Do NOT configure invented PAT scopes such as menus:read, menu:read, or menu:write — they do not exist in EmDash's token system.
    • Underlying User RBAC Permissions:
      • Menu reads: user must have menus:read role capability
      • Menu writes: user must have menus:manage role capability (Editor or Administrator)
  • Menu translations: When creating a translated menu variant, configure translationOf with the canonical menu ID and specify the target locale code. The menu name must match the canonical menu name. EmDash clones existing navigation items into the new menu and joins it to the canonical translation group.
  • Custom URL safety: Navigation items configured with type: custom validate URLs through EmDash's upstream safeHref sanitizer. Permitted URL schemes include http, https, mailto, tel, relative web paths (/about), and fragment identifiers (#contact). Potentially unsafe protocols (such as javascript: or data:) are rejected.
  • Referenced content semantics: Navigation items linking to CMS entries (page, post, taxonomy, or collection) require referenceCollection (the target collection slug) and referenceId. In EmDash, referenceId corresponds to the translation-group identifier of the referenced content rather than an individual revision ID, allowing navigation links to resolve to the appropriate language variant automatically.
  • Hierarchy and ordering: The reorderItems operation accepts a JSON or native expression list of { id, parentId, sortOrder } objects. Setting parentId to a sibling item ID creates nested sub-menus, while null positions items at the root level. sortOrder defines a zero-based integer display sequence among siblings. When updating single items via updateItem, passing an empty string or literal "null" moves an item back to the root level, whereas omitting parentId preserves existing hierarchy.
  • Menu webhooks: Workflows responding to navigation changes should be scheduled periodically or sequenced downstream of content publishing flows.

Example: Automated campaign navigation update

A common content automation scenario involves publishing a promotional landing page and immediately integrating it into the site navigation menu:

  1. Trigger on Publish: A Schedule Trigger with EmDash actions detects a newly published landing page in the pages collection (e.g. translationGroupId: "grp_summer_sale").
  2. Add Navigation Item: An EmDash node executes Menu → Create Item:
    • Menu: main-navigation
    • Type: Page
    • Label: Summer Sale
    • Reference Collection: pages
    • Reference ID: ={{ $json.translationGroupId }}
    • Additional Fields → Target: _self
  3. Reorder Menu: A subsequent EmDash node executes Menu → Reorder Items to place the new campaign link prominently at the front of the top-level navigation (sortOrder: 0).

Settings Management

The Settings resource provides direct access to site-wide configuration stored in EmDash CMS:

  • Get Settings (get): Fetches the full settings object. The response envelope is automatically unwrapped to return the raw settings data.
  • Update Settings (update): Updates site settings by sending a validated JSON payload via POST /settings.
  • Merge semantics: EmDash merges submitted settings with existing configuration; unspecified fields remain untouched, so workflows can submit partial settings objects containing only the targeted updates.
  • Dynamic JSON input and schema behavior: The n8n node parameter accepts a flexible JSON object or expression for forward compatibility. Note that current upstream EmDash 1.0.1 parses update payloads with a finite Zod schema (settingsUpdateBody) that strips unknown properties; arbitrary custom keys are not persisted by EmDash 1.0.1, though future CMS releases may accept additional fields without requiring node UI changes.
  • Best practices: While partial updates do not overwrite omitted settings, calling Get Settings first can be useful when reviewing current values or computing dynamic property updates. Backups or exporting settings prior to broad configuration changes are always recommended.
  • Authentication and permissions:
    • Personal Access Token (PAT) Scopes: Reading settings via Get requires settings:read (or admin). Modifying settings via Update requires settings:manage (or admin).
    • RBAC Capabilities: The authenticated user account must possess the corresponding internal RBAC permission (settings:read capability for reads; settings:manage capability, typical of the Administrator role, for updates).

Section Management

The Section resource provides full lifecycle management of reusable template and layout sections within EmDash CMS:

  • Structured Content Blocks: Section content is structured JSON representing component and layout blocks (such as block definitions, settings, and nested layouts). The node validates content via validateStructuredContent before dispatch to ensure a valid JSON object or array structure.
  • Source Constraints and Protection: Sections can be created with source user or import. EmDash strictly rejects creating sections with source: "theme" (HTTP 400 Bad Request), as theme sections are defined in codebase templates. Furthermore, theme-defined sections are protected and cannot be deleted via the API (EmDash returns HTTP 403 Forbidden).
  • Preview Media Semantics: The optional previewMediaId links a media library asset to the section to provide visual thumbnails in page and layout builders. In Update Section, passing an explicit null, literal "null", or empty string "" clears the existing preview media association. Non-string, non-null values (such as numbers, booleans, arrays, or objects) are strictly rejected with a validation error.
  • Dynamic Section Discovery: The section resource locator uses getSections listSearch, which queries GET /sections with limit=100 and passes the interactive search term to the upstream search query parameter, with client-side fallback formatting.
  • Authentication and Permissions:
    • PAT Scopes: Section reads (GET) require content:read. Section mutations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate sections:* PAT scopes.
    • RBAC Capabilities: The authenticated user must separately possess the sections:read role capability for reads, and sections:manage capability (Editor or Administrator) for mutations.
  • Webhooks: Workflows managing sections should be scheduled or triggered downstream of content workflows.

Widget Area and Widget Configuration

The Widget Area resource manages theme-registered and custom widget zones and the widgets placed inside them:

  • Widget Types: Widgets support three distinct types:
    • content: Renders structured content blocks configured via the content JSON array.
    • menu: Renders an existing navigation menu specified by menuName.
    • component: Renders a site or theme component specified by componentId, with customizable options in componentProps JSON object.
  • Cascade Deletion: Deleting a widget area (DELETE /widget-areas/{name}) permanently cascades deletion to all contained widgets in the database.
  • Widget Deletion Scope: Deleting an individual widget (DELETE /widget-areas/{name}/widgets/{id}) removes the widget from the area without deleting the parent widget area, and without deleting referenced menus, components, or content items.
  • Widget Update Clearing Semantics: In Update Widget, passing an empty string "" clears title, menuName, or componentId (upstream schema accepts strings, and the route handler converts empty strings "" to NULL in the database). Omitted fields are not included in the payload, preserving existing values. For content, an empty array [] is preserved, and for componentProps, an empty object {} is preserved. Changing widget type does not implicitly send or clear fields from the previous type unless explicitly supplied.
  • Widget Reordering Semantics: The reorderWidgets operation accepts an array or comma-separated list of widget IDs (widgetIds). EmDash accepts a partial widget ID list, but only supplied widgets receive new zero-based sort positions; for deterministic ordering, provide the complete ordered list of widgets in the area.
  • Timestamp Conventions: Upstream EmDash widgetAreaSchema returns snake_case timestamps (created_at and updated_at), differing from the camelCase conventions used by content and comments.
  • Update Safety: Upstream EmDash requires at least one field to update on PUT /widget-areas/{name}/widgets/{id}; omitting all update fields returns HTTP 400 ("No fields to update"). The node validates this preSend to avoid unnecessary network roundtrips.
  • Pagination: The GET /widget-areas endpoint returns all registered widget areas in { items: [...] } without cursor pagination.
  • Authentication and Permissions:
    • PAT Scopes: Widget area reads (GET) require content:read. Widget area and widget mutations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate widgets:* PAT scopes.
    • RBAC Capabilities: The authenticated user must separately possess the widgets:read role capability for reads, and widgets:manage capability (Editor or Administrator) for mutations.

Troubleshooting

For local development, run npm run dev -- --custom-user-folder /tmp/n8n-node-run and open
http://localhost:5690 manually. The pinned CLI browser shortcut can open port 5678 instead. If 5690
is occupied, use
N8N_PORT=5692 npm exec -- n8n-node dev --custom-user-folder /tmp/n8n-node-run and open port 5692.

  • Token permissions: Ensure your Personal Access Token includes the required scopes for the operations invoked. Operations that modify system settings (such as index rebuilds, search enablement, or redirect/404 management) require the admin scope.
  • Base URL and routing: Enter the bare root URL of your EmDash installation (for example, https://cms.example.com). The node automatically normalizes trailing slashes and prefixes paths with /_emdash/api.
  • Concurrent edits: If an update fails with an ENTRY_LOCKED or revision mismatch error, fetch the latest content item revision using Get to obtain the current _rev token before retrying.
  • Report defects: File reproducible bug reports on GitHub Issues without including credentials or sensitive tokens.

Resources

License

MIT

Discussion