The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
DraftComponent Helpers

Real-Time Updates

How Mercure broadcasts live content changes to all open browser sessions automatically when a component is published.

CWA is live by default. When an admin publishes a component, every open browser session receives the update via the Mercure hub — no page reload, no polling, no WebSocket code on your end.

How It Works

  1. An admin publishes a component via the CMS
  2. The Symfony API sends an update to the Mercure hub (because mercure: true is on the entity)
  3. The hub broadcasts the update to all subscribed browser connections
  4. The Nuxt module's resource store receives the event and updates the relevant IRI
  5. Vue's reactivity re-renders any component bound to that resource
  6. A non-intrusive notification toasts for regular visitors ("Content updated")

You write none of this plumbing. It's in the module.

Prerequisites

PHP Side

Add mercure: true to the #[ApiResource] attribute on any entity you want to broadcast:

#[ApiResource(mercure: true)]
class Title extends AbstractComponent { ... }

Without this, the resource updates silently (the API saves the change, but no Mercure event fires).

Infrastructure

You need a Mercure hub running alongside your API. The Docker Compose template includes one via dunglas/mercure.

Required environment variables:

# API → hub (internal, server-side)
MERCURE_URL=http://mercure/.well-known/mercure

# Browser → hub (public-facing)
MERCURE_PUBLIC_URL=https://mercure.example.com/.well-known/mercure

# Shared secret for publisher JWT (keep private)
MERCURE_JWT_SECRET=your_secure_secret

MERCURE_URL and MERCURE_PUBLIC_URL can be the same in simple deployments (e.g. a single server where your API and hub are on the same host). They differ in Docker Compose setups where the API uses an internal hostname.

No Front-End Code Needed

The module subscribes to the Mercure hub in its Nuxt plugin. Topics are derived automatically from the IRIs of resources that have been fetched for the current page. You never write EventSource or WebSocket code.

The subscription lifecycle:

  • On page load: the module opens an EventSource connection to MERCURE_PUBLIC_URL
  • Topics: all IRIs currently in cwa.resources.currentIds
  • On navigation: the subscription updates to the new page's resource IRIs
  • On sign-in: Mercure re-initialises to include private topics (admin resources)

The Visitor Notification

When a Mercure update arrives for a non-admin visitor, a toast notification appears: "Content on this page has been updated." The visitor can dismiss it. Whether they dismiss it or not, the resource store has already updated — new content is in the DOM.

Admins editing in real time see their changes immediately without any notification.

Troubleshooting

No live updates arriving in the browser:

  1. Check that MERCURE_PUBLIC_URL is reachable from browsers — not an internal Docker hostname
  2. Confirm mercure: true is on the PHP entity
  3. Open DevTools → Network → Filter by EventSource — you should see a persistent connection to the hub
  4. Check the hub logs for authentication errors

Hub 401 errors:

  • The MERCURE_JWT_SECRET must match exactly between the API (publisher) and the hub (subscriber)
  • Verify the secret is identically set in both services

Updates arrive but the component doesn't re-render:

  • Confirm the component uses useCwaResource or useCwaImageResource — both react to store updates
  • Bare $fetch calls are not reactive; use cwa.resources.getResource(iri) for reactive lookups

Advanced: Custom Topics

By default CWA subscribes only to the exact IRIs of resources fetched for the current page. The module does not subscribe to wildcard or collection topics automatically.

To subscribe to additional topics (e.g. a {+https://example.com/component/products} wildcard that covers all products), you need two things:

  1. Hub side — your Mercure hub must be configured to allow that topic pattern for subscriber tokens.
  2. Module side — open a second EventSource in a Nuxt plugin or composable that passes the extra topics in the topic query parameter.

There is no built-in CWA API for registering custom topics today. This is an advanced use case best solved by adding a Nuxt plugin that opens a secondary EventSource connection alongside the one the module manages. The module's resource store is reactive — once a resource IRI updates in the store (via $cwa.resources.setResource(iri, data)) any component bound to that IRI will re-render, regardless of which EventSource delivered the update.