Glossary

Mercure

A protocol for one-way delivery of live server updates to clients, with a hub, topics, authorization, and connection recovery.

Short definition

Publish/subscribe for web clients over HTTP and SSE.

Mercure separates the backend that publishes a change from browsers or other clients that subscribe to it. The hub maintains long-lived HTTP connections, matches subscriptions against topics, and distributes relevant updates. It is useful, for example, when complementing a conventional API with a live order status change.

Transport from the hub to a subscriber uses Server-Sent Events. It is therefore primarily one-way from server to client and is not the same as WebSocket. The client does not send commands back through the same SSE connection; it usually writes changes to an API through a separate HTTP request.

The problem it solves

Fast change delivery without regular polling

When a client checks every few seconds to see whether anything has changed, it creates needless latency and traffic. Mercure lets a backend notify connected clients as soon as a change occurs.

  • live changes to order, payment, or shipping status in an ecommerce administration interface
  • progress of an import, export, or another long-running server task
  • dashboard updates, notifications, and multi-user collaboration over one resource
  • delivery of public and private updates to multiple subscribers without directly coupling them to a publisher
  • complementing an authoritative HTTP API with a signal that tells the frontend to change or reload data

Practical example

Live order status in an ecommerce administration interface

A PHP backend first changes an order safely in the database. It then publishes an update for that order topic to the hub. Open administration interfaces that subscribe to the topic and are authorized for it receive a JSON payload and update the row or reload the order detail through the API.

The example uses the topic parameter from the stable Mercure 0.x line. The Mercure 1.0 specification, currently labelled alpha, replaces it with the exact match parameter and match_urlpattern for URL patterns. Client and token syntax must therefore match the deployed hub version. Knowing a topic does not itself authorize a client to receive private updates.

JavaScript

const hub = new URL('https://hub.example.cz/.well-known/mercure');
hub.searchParams.append('topic', 'https://shop.example.cz/orders/42');

const events = new EventSource(hub, { withCredentials: true });

events.onmessage = ({ data }) => {
  const update = JSON.parse(data);
  renderOrderStatus(update.status);
};

events.onerror = () => showTemporaryConnectionWarning();

How it works

Text diagram: backend → Mercure hub → SSE connection → browser → verification through API

The diagram describes a common flow, not the only possible implementation. A hub can run separately, or an application can implement the protocol directly.

  1. 1. Backend changes state The application stores a new order status, for example. The database write is authoritative; a real-time message does not replace it.
  2. 2. Publisher sends an update The backend sends an authorized HTTPS POST to the hub. An update contains at least a topic and usually data; it is marked private for confidential data.
  3. 3. Hub selects subscribers The hub matches the topic against active subscription matchers and, for a private update, checks whether each subscriber may receive that topic.
  4. 4. SSE delivers the event The hub writes the update as text/event-stream to a long-lived HTTP connection. The browser processes the event without another polling request.
  5. 5. Frontend updates the screen The client uses the payload or reloads the resource through the API. After an outage, it reconciles the display with the current authoritative state.

Main parts and principles

The hub routes updates, a topic identifies them, and a token limits access

Each role has a distinct responsibility. Confusing them often leads to faulty authorization or unrealistic delivery expectations.

Hub

A server that accepts publications and handles subscriptions. It maintains many long-lived connections, distributes matching updates, and enforces operational and authorization policies.

Publisher and subscriber

A publisher owns a resource and announces its new version. A subscriber is a client that subscribes to selected topics, typically a browser, mobile application, or another server.

Topic, matcher, and update

A topic is a textual identifier for an updated resource, often an IRI. A subscriber selects topics through a selector or matcher according to the protocol version. An update carries at least one topic, a new representation or partial change, and can be public or private.

SSE connection

A subscription runs as a long-lived HTTP response with the text/event-stream type. Unlike WebSocket, it is not a fully bidirectional channel; a client uses a separate HTTP/API call for writes.

JWT and permissions

JWT carries signed permissions, not encrypted data. Stable 0.x implementations use the mercure.publish and mercure.subscribe claims. The 1.0 alpha specification moves to an OAuth 2.0 JWT access token with authorization_details and topic matchers; the format must match the hub version.

Reconnect and Last-Event-ID

EventSource normally reconnects after an interruption. The last event identifier can let a hub recover missing updates only if the hub retains them and recognizes the ID; it does not provide an automatic infinite history.

Benefits, limitations, and common mistakes

Simpler browser delivery in exchange for managing connections, permissions, and recovery

Benefits

  • a server can notify a client immediately without short polling
  • native EventSource works over conventional HTTP and automatically attempts to reconnect
  • one hub separates a publisher from a larger number of subscribers
  • topics route updates to specific resources or resource groups
  • private updates can be delivered only to authorized subscribers

Limitations and common mistakes

  • treating SSE as a bidirectional protocol and attempting to send commands to the server over the same connection
  • publishing a sensitive payload as a public update or allowing overly broad topic selectors
  • relying on an update as the only authoritative state instead of the database and API
  • assuming every disconnected client always receives the entire history without configured retention and recovery
  • ignoring connection limits, CORS, token expiry, proxy buffering, and idle connection termination

Comparison and suitability

Mercure is a path to web subscribers, not a universal backend broker.

Compared with low-level Server-Sent Events, Mercure adds standardized publication, a hub, topics, authorization, discovery, and recovery mechanisms. Compared with a webhook, it maintains a long-lived connection to subscribers; a webhook is a separate HTTP request between systems for a particular event.

Compared with RabbitMQ, Mercure primarily targets the delivery of updates to web clients. RabbitMQ is a message broker for backend communication, with queues, acknowledgements, and consumer management. A Mercure hub is therefore not an automatic replacement for an integration queue.

WebSocket provides fully bidirectional communication and is suitable when both sides send messages frequently. Mercure over SSE is more natural when a server primarily informs clients and their commands continue through a conventional HTTP API.

Production considerations

The real-time layer must survive an outage without leaking data or corrupting state.

Solution quality shows during disconnection, token expiry, and permission changes, not only on the happy path on a local machine.

  • design topics so they can be authorized safely and do not expose needless sensitive information; authorization must be evaluated by the hub, not only in the frontend
  • configure CORS, cookies, or an Authorization header correctly for the chosen client, and avoid long-lived or excessively broad tokens
  • disable unwanted event-stream buffering in the reverse proxy and configure timeouts, keep-alive, and HTTP/2 or newer according to infrastructure capabilities
  • measure connection count, publication latency, rejected subscriptions, reconnects, lost cursors, and overloaded clients
  • reload the current resource from the API after reconnecting or detecting a suspicious gap; a real-time update optimizes change delivery but is not the source of truth

Common questions

Mercure without common misconceptions

Does Mercure use WebSocket?

Not for standard delivery of updates to subscribers. Mercure uses Server-Sent Events over a long-lived HTTP response with the text/event-stream type.

Can a client send a change to the server over the same SSE connection?

No. SSE is one-way from server to client. A client normally sends a change through a separate POST, PUT, or PATCH request to an API.

Does Last-Event-ID guarantee that a client never loses an update?

Not by itself. It helps identify the last received event, but the hub must retain matching history and the client must recover state if the cursor is unknown or too old.

Is JWT required for public updates?

Depending on hub policy, a subscriber may receive public updates without a token. A publisher must be authorized, and only subscribers authorized for matching topics may receive private updates.

Does Mercure replace RabbitMQ or a database?

No. A hub delivers updates to clients, while a database remains the source of truth and a backend queue may still provide reliable asynchronous processing between services.

How I design API and integration flows in practice

I connect live updates to authoritative data, permissions, and safe recovery.

For orders and operational applications, I separate writing business state from delivering it to a browser and account for failure in every layer.

Request a call

I will call you on the next working day between 9:00 and 17:00.

You can also call me directly.

+420 605 181 728

Leave your phone number and send a callback request.

By sending, you agree to processing your data in order to handle your request.