### Install dependencies for Apollo Server example Source: https://mercure.rocks/docs/use-cases/graphql Install the required npm packages for the Apollo Server example. Requires Node.js 22 or later. ```bash npm install @apollo/server @as-integrations/express5 express graphql @graphql-tools/schema graphql-subscriptions ``` -------------------------------- ### Install Mercure Helm chart with development keys Source: https://mercure.rocks/docs/deployment/kubernetes Adds the Mercure Helm repository and installs the chart, setting publisher and subscriber JWT keys. Generate each key once with `openssl rand -base64 32` and export as MERCURE_PUBLISHER_JWT_KEY / MERCURE_SUBSCRIBER_JWT_KEY. Anyone can forge tokens signed with the development key. ```bash helm repo add mercure https://charts.mercure.rocks helm install mercure mercure/mercure \ --set publisherJwtKey="$MERCURE_PUBLISHER_JWT_KEY" \ --set subscriberJwtKey="$MERCURE_SUBSCRIBER_JWT_KEY" ``` -------------------------------- ### Install Mercure on Arch Linux using yay Source: https://mercure.rocks/docs/getting-started/installation Install the Mercure hub on Arch Linux from the AUR using the yay helper. Alternatively, build directly from the PKGBUILD with makepkg -sri. ```bash yay -S mercure ``` -------------------------------- ### fetchEventSource with QUERY method Source: https://mercure.rocks/docs/concepts/subscribing JavaScript example using @microsoft/fetch-event-source to send a QUERY request. Since EventSource only issues GET requests, use fetchEventSource with method: 'QUERY' and a URLSearchParams body. The onmessage callback logs event data. ```javascript import { fetchEventSource } from "@microsoft/fetch-event-source"; const body = new URLSearchParams(); body.append("match", "https://example.com/books/1"); body.append("match_urlpattern", "https://example.com/users/:id"); await fetchEventSource("https://hub.example.com/.well-known/mercure", { method: "QUERY", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body, onmessage: (event) => { console.log(event.data); }, }); ``` -------------------------------- ### Subscriber authorization_details example Source: https://mercure.rocks/docs/concepts/authorization Example of an authorization_details token for a subscriber, with subscribe action and topics using URLPattern and exact match types. ```json { "authorization_details": [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://example.com/users/42/*", "match_type": "urlpattern" }, { "match": "https://example.com/announcements" } ] } ] } ``` -------------------------------- ### Publisher authorization_details example Source: https://mercure.rocks/docs/concepts/authorization Example of an authorization_details token for a publisher, with publish action and topics using URLPattern and exact match types. ```json { "authorization_details": [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["publish"], "topics": [ { "match": "https://example.com/books/:id", "match_type": "urlpattern" }, { "match": "https://example.com/announcements" } ] } ] } ``` -------------------------------- ### caddy mercure-token --dev (quickstart token) Source: https://mercure.rocks/docs/concepts/authorization Mints a Mercure access token matching the quickstart's local hub with zero configuration. Use this for local development only. ```bash caddy mercure-token --dev # matches the quickstart's local hub, zero config ``` -------------------------------- ### Install Mercure broadcasting driver Source: https://mercure.rocks/docs/use-cases/laravel-broadcasting Run this artisan command to install the Mercure broadcasting driver in a Laravel release that supports the Mercure installer. ```bash php artisan install:broadcasting --mercure ``` -------------------------------- ### Start mercure hub Source: https://mercure.rocks/docs/production/troubleshooting Starts the mercure hub normally after removing the quarantine attribute. This is the standard way to run the hub. ```bash ./mercure run ``` -------------------------------- ### Start Mercure hub with JWT keys and algorithms Source: https://mercure.rocks/docs/deployment/configuration Sets environment variables for publisher and subscriber JWT public keys and algorithms, then runs the hub with the Caddyfile. Uses RS256 algorithm. ```bash MERCURE_PUBLISHER_JWT_KEY="$(cat publisher.key.pub)" \ MERCURE_PUBLISHER_JWT_ALG=RS256 \ MERCURE_SUBSCRIBER_JWT_KEY="$(cat subscriber.key.pub)" \ MERCURE_SUBSCRIBER_JWT_ALG=RS256 \ ./mercure run --config Caddyfile ``` -------------------------------- ### Apply Secret and install Mercure Helm chart Source: https://mercure.rocks/docs/deployment/kubernetes Commands to apply the Secret manifest and install or upgrade the Mercure chart with the production values file. Run the apply before installing the chart. ```bash kubectl apply -f mercure-secret.yaml helm upgrade --install mercure mercure/mercure -f values.yaml ``` -------------------------------- ### Run the Mercure conformance test suite Source: https://mercure.rocks/docs/ecosystem/conformance-tests Clones the Mercure repository, installs dependencies, and runs the Playwright conformance tests. Requires an isolated playground hub with the bundled development key running before execution. ```bash git clone https://github.com/dunglas/mercure cd mercure/conformance-tests npm ci npx playwright install --with-deps npx playwright test ``` -------------------------------- ### Example subscription event JSON Source: https://mercure.rocks/docs/concepts/active-subscriptions Each event's data is a JSON document with fields for the matcher, subscriber, active status, and payload. ```json { "id": "/.well-known/mercure/subscriptions/urlpattern/https%3A%2F%2Fexample.com%2F%3Aselector/urn%3Auuid%3Abb3de268-05b0-4c65-b44e-8f9acefc29d6", "type": "subscription", "match_type": "urlpattern", "match": "https://example.com/:selector", "subscriber": "urn:uuid:bb3de268-05b0-4c65-b44e-8f9acefc29d6", "active": true, "payload": { "username": "alice" } } ``` -------------------------------- ### Example authorization_details attribute value Source: https://mercure.rocks/docs/concepts/authorization-servers Example JSON array stored in the `authorization_details` user attribute, granting subscribe actions on specific topics with a payload. ```json [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://example.com/users/42/notifications" }, { "match": "https://example.com/announcements" } ], "payload": { "user": "https://example.com/users/42" } } ] ``` -------------------------------- ### Run Mercure hub with Docker Source: https://mercure.rocks/docs/getting-started/quickstart Starts the Mercure hub container with HTTP/3 support and the playground directive. The hub is served on https://localhost. The playground enables anonymous subscriptions and a debugger at https://localhost/.well-known/mercure/debug/ with a default secret. Drop the playground for production. ```bash docker run -p 80:80 -p 443:443 -p 443:443/udp \ -e MERCURE_EXTRA_DIRECTIVES=playground \ dunglas/mercure ``` -------------------------------- ### HTTP exchange for hub discovery Source: https://mercure.rocks/docs/concepts/subscribing Example of a GET request and response showing the Link header that advertises the Mercure hub. ```http GET /books/1 Host: example.com 200 OK Content-Type: application/ld+json Link: ; rel="mercure" ``` -------------------------------- ### Run Mercure in Docker development mode with playground directive Source: https://mercure.rocks/docs/deployment/docker Starts the dunglas/mercure image with the playground directive enabled, which turns on the debug UI, anonymous subscribers, echo endpoints, and permissive CORS. Do not expose this to the internet. ```bash docker run \ -e MERCURE_EXTRA_DIRECTIVES=playground \ -p 80:80 -p 443:443 \ dunglas/mercure ``` -------------------------------- ### Configure the Mercure load test with environment variables Source: https://mercure.rocks/docs/production/load-testing Sets environment variables to target a real hub and configure subscriber and publisher rates, injection duration, and connection duration. Start below expected traffic and increase load while measuring latency and errors. ```bash HUB_URL=https://hub.example.com/.well-known/mercure \ JWT='' \ INITIAL_SUBSCRIBERS=1000 \ SUBSCRIBERS_RATE_FROM=50 \ SUBSCRIBERS_RATE_TO=200 \ PUBLISHERS_RATE_FROM=10 \ PUBLISHERS_RATE_TO=100 \ INJECTION_DURATION=300 \ CONNECTION_DURATION=600 \ ./mvnw gatling:test ``` -------------------------------- ### Helm chart installation commands for Mercure Source: https://mercure.rocks/docs/getting-started/installation Install Mercure hub on Kubernetes using Helm. The chart includes settings for draining SSE connections during rolling updates. Persistent BoltDB deployments need the Recreate strategy; use a shared transport for rolling upgrades. ```bash helm repo add mercure https://charts.mercure.rocks helm install my-release mercure/mercure ``` -------------------------------- ### GET /mercure/health/{name}/ready Source: https://mercure.rocks/docs/production/health-monitoring Per-hub readiness when running multiple hubs. ```APIDOC ## [GET] /mercure/health/{name}/ready ### Description Per-hub readiness when running multiple hubs. ### Method GET ### Endpoint /mercure/health/{name}/ready ### Parameters #### Path Parameters - **name** (string) - Required - The name of the hub. ### Response #### Success Response (200) - **status** (integer) - 200 if the hub is ready. #### Error Response (503) - **status** (integer) - 503 if the hub is not ready. ``` -------------------------------- ### Advanced subscription with fetch-event-source Source: https://mercure.rocks/docs/concepts/subscribing Uses Microsoft's fetch-event-source package for custom headers, retry handling, or QUERY requests. This example sets an Authorization header with a JWT. Note that fetch-event-source relies on browser APIs; for Node.js use the eventsource package. ```javascript import { fetchEventSource } from "@microsoft/fetch-event-source"; await fetchEventSource(url, { headers: { Authorization: `Bearer ${jwt}` }, onmessage: (event) => { console.log(event.data); }, onerror: (err) => { console.error(err); }, }); ``` -------------------------------- ### Subscribe to Mercure from Python with sseclient Source: https://mercure.rocks/docs/concepts/subscribing This Python example uses the sseclient package to subscribe to Mercure and print event data. It requires anonymous subscriptions. Note that the similarly named sseclient-py package has a different constructor. ```python from sseclient import SSEClient for event in SSEClient("https://hub.example.com/.well-known/mercure?match=topic"): print(event.data) ``` -------------------------------- ### Agent event stream example Source: https://mercure.rocks/docs/use-cases/ai-agent-progress Shows the sequence of structured events an agent publishes to describe its progress, including step started/completed, tool called/completed, token chunks, and run completion. The browser updates its state from these events; concurrent steps need unique step IDs and separate state. ```json { "type": "step.started", "step": "search_web", "input": {"query": "mercure protocol"} } { "type": "tool.called", "tool": "fetch", "url": "https://mercure.rocks" } { "type": "tool.completed", "tool": "fetch", "bytes": 14732 } { "type": "step.completed", "step": "search_web", "results": 5 } { "type": "step.started", "step": "summarize" } { "type": "token", "text": "Mercure is a..." } { "type": "token", "text": " protocol for..." } { "type": "step.completed", "step": "summarize" } { "type": "run.completed", "output": "..." } ``` -------------------------------- ### GET /mercure/health/{name}/live Source: https://mercure.rocks/docs/production/health-monitoring Per-hub liveness. ```APIDOC ## [GET] /mercure/health/{name}/live ### Description Per-hub liveness. ### Method GET ### Endpoint /mercure/health/{name}/live ### Parameters #### Path Parameters - **name** (string) - Required - The name of the hub. ### Response #### Success Response (200) - **status** (integer) - 200 if the hub is live. #### Error Response (503) - **status** (integer) - 503 if the hub is not live. ``` -------------------------------- ### Subscribe to Mercure from Node.js with eventsource package Source: https://mercure.rocks/docs/concepts/subscribing This Node.js example uses the eventsource package to subscribe to Mercure. It requires anonymous subscriptions; use the package's custom fetch option to attach an Authorization header for protected hubs. ```javascript import { EventSource } from "eventsource"; const es = new EventSource( "https://hub.example.com/.well-known/mercure?match=topic", ); es.onmessage = (event) => console.log(event.data); ``` -------------------------------- ### Subscriber payload example in authorization_details Source: https://mercure.rocks/docs/concepts/authorization Shows a JSON authorization_details structure with subscribe actions and payloads. The hub selects the payload from the first applicable subscribe detail for each subscription matcher. Only include metadata that presence listeners are allowed to see. ```json { "authorization_details": [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [{ "match": "https://example.com/users/42" }], "payload": { "username": "alice", "ip": "10.0.0.1" } }, { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://example.com/books/:id", "match_type": "urlpattern" } ], "payload": { "username": "alice" } } ] } ``` -------------------------------- ### GET /mercure/health/ready Source: https://mercure.rocks/docs/production/health-monitoring Returns 200 if all transports can serve traffic, 503 otherwise. Use for readiness. ```APIDOC ## [GET] /mercure/health/ready ### Description Returns 200 if all transports can serve traffic, 503 otherwise. Use for readiness. ### Method GET ### Endpoint /mercure/health/ready ### Response #### Success Response (200) - **status** (integer) - 200 if all transports can serve traffic. #### Error Response (503) - **status** (integer) - 503 if any transport cannot serve traffic. ``` -------------------------------- ### Apollo Server with Mercure integration (server.mjs) Source: https://mercure.rocks/docs/use-cases/graphql Full server implementation that sets up Apollo Server, a GraphQL subscription resolver, and an Express endpoint to register subscriptions and forward results to Mercure. Requires MERCURE_URL and MERCURE_PUBLISHER_JWT environment variables. The publisher token must grant access to https://example.com/graphql/subscriptions/* using a URL Pattern. The example is a public message feed with no application login. ```javascript import { randomUUID } from "node:crypto"; import express from "express"; import { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@as-integrations/express5"; import { makeExecutableSchema } from "@graphql-tools/schema"; import { getOperationAST, parse, subscribe, validate } from "graphql"; import { PubSub } from "graphql-subscriptions"; const { MERCURE_URL, MERCURE_PUBLISHER_JWT } = process.env; if (!MERCURE_URL || !MERCURE_PUBLISHER_JWT) { throw new Error("Set MERCURE_URL and MERCURE_PUBLISHER_JWT"); } const pubsub = new PubSub(); const schema = makeExecutableSchema({ typeDefs: ` type Message { id: ID!, text: String! } type Query { health: Boolean! } type Mutation { addMessage(text: String!): Message! } type Subscription { messageAdded: Message! } `, resolvers: { Query: { health: () => true }, Mutation: { addMessage: async (_, { text }) => { const message = { id: randomUUID(), text }; await pubsub.publish("MESSAGE_ADDED", { messageAdded: message }); return message; }, }, Subscription: { messageAdded: { subscribe: () => pubsub.asyncIterableIterator("MESSAGE_ADDED"), }, }, }, }); async function publish(topic, result, type = "message") { const response = await fetch(MERCURE_URL, { method: "POST", headers: { Authorization: `Bearer ${MERCURE_PUBLISHER_JWT}` }, body: new URLSearchParams({ topic, data: JSON.stringify(result), type }), signal: AbortSignal.timeout(10000), }); if (!response.ok) throw new Error(`Publish failed: ${response.status}`); } const app = express(); app.use(express.json()); const apollo = new ApolloServer({ schema }); await apollo.start(); app.post("/graphql", expressMiddleware(apollo)); const registrations = new Map(); app.post("/graphql/subscriptions", async (req, res) => { const { query, variables, operationName } = req.body; let document; try { document = parse(query); } catch { return res.status(400).json({ error: "Invalid GraphQL document" }); } const errors = validate(schema, document); if (errors.length) return res.status(400).json({ errors }); if (getOperationAST(document, operationName)?.operation !== "subscription") { return res.status(400).json({ error: "Expected a subscription" }); } const results = await subscribe({ schema, document, variableValues: variables, operationName, }); if (!(Symbol.asyncIterator in results)) { return res.status(400).json(results); } const id = randomUUID(); const topic = `https://example.com/graphql/subscriptions/${id}`; const stop = () => { clearTimeout(timer); registrations.delete(id); return results.return(); }; const timer = setTimeout(() => void stop(), 5 * 60 * 1000); registrations.set(id, stop); async function forward() { try { for await (const result of results) await publish(topic, result); await publish(topic, {}, "complete"); } catch (error) { console.error(error); await publish(topic, { errors: [{ message: "Subscription failed" }] }); } finally { await stop(); } } void forward().catch(console.error); res.json({ id, topic, lastEventId: "earliest" }); }); app.delete("/graphql/subscriptions/:id", async (req, res) => { await registrations.get(req.params.id)?.(); res.sendStatus(204); }); app.listen(4000, "127.0.0.1", () => { console.log("GraphQL ready at http://localhost:4000/graphql"); }); ``` -------------------------------- ### Browser EventSource setup for agent progress Source: https://mercure.rocks/docs/use-cases/ai-agent-progress Creates an EventSource for a specific run using a Mercure topic with the user and run IDs. It maintains local state and updates the UI on each event, closing the stream when the run completes. Requires the same userId and runId on both browser and worker. ```javascript const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append( "match", `https://example.com/users/${userId}/runs/${runId}`, ); url.searchParams.set("last_event_id", "earliest"); const es = new EventSource(url, { withCredentials: true }); const state = { steps: [], output: "" }; es.onmessage = (event) => { const msg = JSON.parse(event.data); switch (msg.type) { case "step.started": state.steps.push({ name: msg.step, status: "running" }); break; case "step.completed": state.steps[state.steps.length - 1].status = "done"; break; case "token": state.output += msg.text; break; case "run.completed": state.output = msg.output ?? state.output; es.close(); break; } render(state); }; ``` -------------------------------- ### Data flow diagram: source to hub to clients Source: https://mercure.rocks/docs/use-cases/live-data ASCII diagram showing the flow of data from a source to the hub and then to connected clients. The source POSTs to the hub when a value changes, and clients GET the hub with a match parameter to receive updates. ```text data source hub clients | | | | POST to hub | GET hub?match=... | | -------------------> | -------------------------> | | (when value changes)| | | | -------------------------> | every connected | | -------------------------> | client gets it ``` -------------------------------- ### Mercure authorization detail JSON example Source: https://mercure.rocks/docs/concepts/authorization-servers Shows the structure of a Mercure authorization detail with type, actions, topics, and payload. The type must be exactly 'https://mercure.rocks/authorization-detail'. Entries with other types are ignored, but a malformed Mercure entry rejects the whole token. ```json // A Mercure authorization detail { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://example.com/users/42/notifications" }, { "match": "https://example.com/books/:id", "match_type": "urlpattern" }, ], "payload": { "user": "https://example.com/users/42" }, } ``` -------------------------------- ### Mercure publish/subscribe flow recap Source: https://mercure.rocks/docs/getting-started/quickstart This ASCII diagram shows the publish/subscribe flow: the publisher sends updates via POST to the hub, the subscriber connects via GET with a match parameter, and the hub sends SSE updates to the subscriber. ```text publisher -- POST /.well-known/mercure --> hub subscriber -- GET /.well-known/mercure?match=... --> hub subscriber <-- SSE updates ---------------------- hub ``` -------------------------------- ### Caddyfile: Configure write_timeout and drain_timeout in mercure directive Source: https://mercure.rocks/docs/production/rolling-updates Sets write_timeout to 1200s and drain_timeout to 300s. The drain starts on Caddy's stopping event, before shutdown_delay. Connections opened during the delay get a full drain_timeout. A Caddy grace_period shorter than drain_timeout cuts the drain short. ```caddyfile localhost { mercure { write_timeout 1200s drain_timeout 300s } } ``` -------------------------------- ### Build custom Caddy binary with Mercure module using xcaddy Source: https://mercure.rocks/docs/getting-started/installation Build a custom Caddy binary that includes the Mercure Caddy module along with any other modules you need. Use the Caddy download page as an alternative to assemble a build in the browser. ```bash xcaddy build \ --with github.com/dunglas/mercure/caddy ``` -------------------------------- ### Set MERCURE_LICENSE and run Mercure Source: https://mercure.rocks/docs/production/high-availability Sets the MERCURE_LICENSE environment variable to the license key supplied with the Self-Hosted plan, then runs the Mercure hub with the Caddyfile configuration. The license is validated locally at startup; a missing, invalid, or expired license prevents startup. ```bash export MERCURE_LICENSE='' ./mercure run --config Caddyfile ``` -------------------------------- ### Run Mercure hub binary with playground directive Source: https://mercure.rocks/docs/getting-started/installation Run the Mercure hub binary with the playground directive enabled Gridview listens at https://localhost. For production, remove playground, configure keys, and set SERVER_NAME and MERCURE_TRUSTED_ISSUERS. On macOS, xattr -d com.apple.quarantine ./mercure may be needed. Set SERVER_NAME=:3000 if ports 80 or 443 are unavailable. ```bash MERCURE_EXTRA_DIRECTIVES='playground' \ ./mercure run --config Caddyfile ``` -------------------------------- ### HTTP GET request to subscribe to Mercure updates Source: https://mercure.rocks/docs/concepts/subscribing A raw HTTP GET request to the hub's well-known URL with match parameters. The hub keeps the connection open and writes Server-Sent Events into it. ```http GET /.well-known/mercure?match=https://example.com/books/1 HTTP/2 Host: hub.example.com Accept: text/event-stream ``` -------------------------------- ### Subscribe with match and match_urlpattern query parameters Source: https://mercure.rocks/docs/concepts/topics-and-matchers Opens an SSE connection to the Mercure hub with two match parameters: an exact topic and a URL pattern. The bare match parameter selects the exact matcher type; match_urlpattern selects the urlpattern type. Parameter names are case-sensitive and any other name under the reserved match prefix is rejected with 400 Bad Request. ```http GET /.well-known/mercure?match=https://example.com/books/1&match_urlpattern=https://example.com/users/:id HTTP/2 ``` -------------------------------- ### GET /.well-known/mercure/subscriptions Source: https://mercure.rocks/docs/concepts/active-subscriptions Fetches all active subscriptions on the hub. Requires a subscribe grant covering the request path. ```APIDOC ## GET /.well-known/mercure/subscriptions ### Description Fetches all active subscriptions on the hub. ### Method GET ### Endpoint /.well-known/mercure/subscriptions ### Parameters None ### Response #### Success Response (200) - **id** (string) - The identifier of the collection. - **type** (string) - Always "subscriptions". - **subscriptions** (array) - List of subscription objects. - **id** (string) - The subscription identifier. - **type** (string) - Always "subscription". - **match** (string) - The topic matcher. - **match_type** (string) - The matcher type (e.g., "urlpattern"). - **subscriber** (string) - The subscriber identifier. - **active** (boolean) - Whether the subscription is active. - **payload** (object) - Additional payload. #### Response Example { "id": "/.well-known/mercure/subscriptions", "type": "subscriptions", "subscriptions": [ { "id": "/.well-known/mercure/subscriptions/urlpattern/https%3A%2F%2Fexample.com%2F%3Aselector/urn%3Auuid%3Abb3de268", "type": "subscription", "match": "https://example.com/:selector", "match_type": "urlpattern", "subscriber": "urn:uuid:bb3de268", "active": true, "payload": { "username": "alice" } } ] } ``` -------------------------------- ### Check subscribers_connected metric with kubectl exec Source: https://mercure.rocks/docs/production/rolling-updates Run this command to check the active subscribers metric during a deploy. A healthy drain shows a smooth ramp down on the old replica and a matching ramp up on the new one. A sudden drop may indicate forced termination. ```bash kubectl exec -it $POD -- wget -qO- localhost:2019/metrics | grep subscribers_connected ``` -------------------------------- ### Check and set file descriptor limits on Linux Source: https://mercure.rocks/docs/production/load-testing Use prlimit to inspect the current limit for the Mercure process, ulimit to set it for the current shell, and a systemd override to persist the limit. ```bash prlimit --pid $(pgrep mercure) # Set the limit for this shell and its child processes ulimit -n 100000 # Persist via systemd # /etc/systemd/system/mercure.service.d/override.conf [Service] LimitNOFILE=100000 ``` -------------------------------- ### GET /mercure/health/live Source: https://mercure.rocks/docs/production/health-monitoring Returns 200 if all transports are fundamentally operational, 503 if a transport reports a liveness failure. Use for liveness. ```APIDOC ## [GET] /mercure/health/live ### Description Returns 200 if all transports are fundamentally operational, 503 if a transport reports a liveness failure. Use for liveness. ### Method GET ### Endpoint /mercure/health/live ### Response #### Success Response (200) - **status** (integer) - 200 if all transports are fundamentally operational. #### Error Response (503) - **status** (integer) - 503 if a transport reports a liveness failure. ``` -------------------------------- ### Subscribe to product availability with match_urlpattern Source: https://mercure.rocks/docs/use-cases/live-data Creates an EventSource that subscribes to a family of product availability topics using the match_urlpattern parameter. One connection receives updates for all products matching the pattern. ```javascript const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append( "match_urlpattern", "https://shop.example.com/products/:id/availability", ); new EventSource(url); ``` -------------------------------- ### GET /.well-known/mercure/subscriptions/{match_type}/{match}/{subscriber} Source: https://mercure.rocks/docs/concepts/active-subscriptions Fetches a single subscription. Requires a subscribe grant covering the request path. ```APIDOC ## GET /.well-known/mercure/subscriptions/{match_type}/{match}/{subscriber} ### Description Fetches a single subscription. ### Method GET ### Endpoint /.well-known/mercure/subscriptions/{match_type}/{match}/{subscriber} ### Parameters #### Path Parameters - **match_type** (string) - Required - The type of matcher (e.g., "urlpattern"). - **match** (string) - Required - The matcher pattern (URL-encoded). - **subscriber** (string) - Required - The subscriber identifier. ### Response #### Success Response (200) - **id** (string) - The subscription identifier. - **type** (string) - Always "subscription". - **match** (string) - The topic matcher. - **match_type** (string) - The matcher type. - **subscriber** (string) - The subscriber identifier. - **active** (boolean) - Whether the subscription is active. - **payload** (object) - Additional payload. #### Response Example { "id": "/.well-known/mercure/subscriptions/urlpattern/https%3A%2F%2Fexample.com%2F%3Aselector/urn%3Auuid%3Abb3de268", "type": "subscription", "match": "https://example.com/:selector", "match_type": "urlpattern", "subscriber": "urn:uuid:bb3de268", "active": true, "payload": { "username": "alice" } } ``` -------------------------------- ### GET /.well-known/mercure/subscriptions/{match_type}/{match} Source: https://mercure.rocks/docs/concepts/active-subscriptions Fetches subscriptions for a specific matcher. Requires a subscribe grant covering the request path. ```APIDOC ## GET /.well-known/mercure/subscriptions/{match_type}/{match} ### Description Fetches subscriptions for a specific matcher. ### Method GET ### Endpoint /.well-known/mercure/subscriptions/{match_type}/{match} ### Parameters #### Path Parameters - **match_type** (string) - Required - The type of matcher (e.g., "urlpattern"). - **match** (string) - Required - The matcher pattern (URL-encoded). ### Response #### Success Response (200) - **id** (string) - The identifier of the collection. - **type** (string) - Always "subscriptions". - **subscriptions** (array) - List of subscription objects. - **id** (string) - The subscription identifier. - **type** (string) - Always "subscription". - **match** (string) - The topic matcher. - **match_type** (string) - The matcher type. - **subscriber** (string) - The subscriber identifier. - **active** (boolean) - Whether the subscription is active. - **payload** (object) - Additional payload. #### Response Example { "id": "/.well-known/mercure/subscriptions/urlpattern/https%3A%2F%2Fexample.com%2F%3Aselector", "type": "subscriptions", "subscriptions": [ { "id": "/.well-known/mercure/subscriptions/urlpattern/https%3A%2F%2Fexample.com%2F%3Aselector/urn%3Auuid%3Abb3de268", "type": "subscription", "match": "https://example.com/:selector", "match_type": "urlpattern", "subscriber": "urn:uuid:bb3de268", "active": true, "payload": { "username": "alice" } } ] } ``` -------------------------------- ### Subscribe to Mercure from Go with r3labs/sse Source: https://mercure.rocks/docs/concepts/subscribing This Go program uses the r3labs/sse/v2 package to subscribe to Mercure and print event data. It requires anonymous subscriptions. ```go package main import ( "fmt" "log" "github.com/r3labs/sse/v2" ) func main() { client := sse.NewClient("https://hub.example.com/.well-known/mercure?match=topic") if err := client.SubscribeRaw(func(msg *sse.Event) { fmt.Println(string(msg.Data)) }); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Enable tracing in Caddy route with Mercure Source: https://mercure.rocks/docs/production/tracing Adds the `tracing` directive inside a `route` block to start collecting traces for Mercure spans. The `mercure` directive is configured within the same route. ```caddyfile route { tracing mercure { # ... } } ``` -------------------------------- ### Combining matchers in a subscription Source: https://mercure.rocks/docs/concepts/topics-and-matchers Shows how to create a subscription with multiple matchers (match and match_urlpattern) to receive topics matching any of them. ```APIDOC ## Subscription with multiple matchers ### Description A subscription can include several `match*` parameters, which are combined as a logical OR. The subscriber receives topics that match any of the provided matchers. ### Method GET ### Endpoint `https://hub.example.com/.well-known/mercure` ### Parameters #### Query Parameters - **match** (string) - Required - Exact topic matcher. Example: `https://example.com/site/announcement` - **match_urlpattern** (string) - Required - URL Pattern matcher. Example: `https://example.com/users/:id/notifications` ### Request Example ``` const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append("match", "https://example.com/site/announcement"); url.searchParams.append( "match_urlpattern", "https://example.com/users/:id/notifications", ); new EventSource(url); ``` ### Response #### Success Response (200) - **EventSource** - The subscriber receives events for topics matching any of the provided matchers. #### Response Example ``` // The subscriber receives: // - exactly the announcement topic, OR // - any user-notifications URL. ``` ``` -------------------------------- ### Protected resource metadata response Source: https://mercure.rocks/docs/concepts/authorization-servers Example JSON response from the protected resource metadata endpoint. It lists the authorization server, supported bearer methods, and the Mercure-specific authorization details type. ```json { "resource": "https://hub.example.com/.well-known/mercure", "bearer_methods_supported": ["header"], "authorization_servers": ["https://auth.example.com/realms/main"], "authorization_details_types_supported": [ "https://mercure.rocks/authorization-detail" ], "mercure_cookie": "__Secure-mercure_access_token" } ``` -------------------------------- ### Capture a heap snapshot of the Mercure hub Source: https://mercure.rocks/docs/production/debugging Capture a heap snapshot and view it in the browser. The inuse_space view shows current live memory; the alloc_space view shows cumulative allocations, useful for finding allocation hotspots that aren't necessarily leaks. ```bash go tool pprof -http=:8080 http://localhost:2019/debug/pprof/heap ``` -------------------------------- ### Remove quarantine attribute on macOS Source: https://mercure.rocks/docs/production/troubleshooting Removes the quarantine attribute from the mercure binary on macOS to bypass the "cannot be opened because the developer cannot be verified" error. Run once per binary before starting the hub. ```bash xattr -d com.apple.quarantine ./mercure ``` -------------------------------- ### JWT token for per-user Mercure subscription Source: https://mercure.rocks/docs/use-cases/notifications Example JWT payload with authorization_details granting subscribe access to a user's notifications topic and a shared announcements topic. The token is carried by the cookie. ```json { "iss": "https://example.com", "aud": "https://hub.example.com/.well-known/mercure", "exp": 4102444800, "authorization_details": [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://example.com/users/42/notifications" }, { "match": "https://example.com/site/announcements" } ] } ] } ``` -------------------------------- ### Connect to a document topic with EventSource Source: https://mercure.rocks/docs/use-cases/collaborative-editing Sets up an EventSource connection to the Mercure hub for a specific document topic, using both match and match_urlpattern parameters. Requires the hub URL and the document ID. ```javascript // Connect to the document const docId = "books/42"; const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append("match", `https://docs.example.com/${docId}`); url.searchParams.append( "match_urlpattern", `/.well-known/mercure/subscriptions/exact/${encodeURIComponent(`https://docs.example.com/${docId}`)}/:subscriber`, ); const es = new EventSource(url, { withCredentials: true }); ``` -------------------------------- ### Browser: create job and subscribe to Mercure updates Source: https://mercure.rocks/docs/use-cases/async-jobs Posts job creation to /api/reports, then opens an EventSource to the Mercure hub with a unique topic per user/job. Uses last_event_id=earliest to replay retained events for fast workers. Handles progress, done, and failed update types. ```javascript const res = await fetch("/api/reports", { method: "POST", body: JSON.stringify({ filters }), headers: { "Content-Type": "application/json" }, }); if (!res.ok) throw new Error(`Job creation failed: ${res.status}`); const { jobId, userId } = await res.json(); const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append( "match", `https://example.com/users/${userId}/jobs/${jobId}`, ); url.searchParams.set("last_event_id", "earliest"); const es = new EventSource(url, { withCredentials: true }); es.onmessage = (e) => { const update = JSON.parse(e.data); switch (update.type) { case "progress": progress.textContent = `${update.rows} rows processed`; break; case "done": window.location = update.url; es.close(); break; case "failed": showError(update.error); es.close(); break; } }; ``` -------------------------------- ### Subscribe to the Mercure hub for a public channel Source: https://mercure.rocks/docs/use-cases/laravel-broadcasting After obtaining the token, Echo subscribes to the Mercure hub using a GET request with the topic as a query parameter. The channel 'chat' becomes the Mercure topic 'https://laravel.alt/echo/channel/chat'. ```http GET https://example.com/.well-known/mercure?match=https%3A%2F%2Flaravel.alt%2Fecho%2Fchannel%2Fchat ``` -------------------------------- ### Run Mercure Docker image with TLS Source: https://mercure.rocks/docs/deployment/docker Run the Mercure hub with Caddy, obtaining an automatic TLS certificate for the public hostname. Set SERVER_NAME to your public hostname and point its DNS record at the server; the default localhost uses a local certificate authority. Generate each JWT key once with `openssl rand -base64 32` and export it as MERCURE_PUBLISHER_JWT_KEY / MERCURE_SUBSCRIBER_JWT_KEY. ```bash docker run \ -e SERVER_NAME=hub.example.com \ -e MERCURE_TRUSTED_ISSUERS=https://app.example.com \ -e MERCURE_PUBLISHER_JWT_KEY \ -e MERCURE_SUBSCRIBER_JWT_KEY \ -p 80:80 -p 443:443 \ dunglas/mercure ``` -------------------------------- ### Presence token payload with name and color Source: https://mercure.rocks/docs/use-cases/collaborative-editing Example JWT payload for a user subscribing to a document topic, including authorization details with a payload containing the user's name and color. The hub uses this payload for presence events. ```json { "iss": "https://example.com", "aud": "https://hub.example.com/.well-known/mercure", "exp": 4102444800, "authorization_details": [ { "type": "https://mercure.rocks/authorization-detail", "actions": ["subscribe"], "topics": [ { "match": "https://docs.example.com/books/42" }, { "match": "/.well-known/mercure/subscriptions/exact/https%3A%2F%2Fdocs.example.com%2Fbooks%2F42/:subscriber", "match_type": "urlpattern" } ], "payload": { "name": "Alice", "color": "#ff0066" } } ] } ``` -------------------------------- ### Simple publish pattern in pseudocode Source: https://mercure.rocks/docs/concepts/publishing Publish from the same code path that mutates the underlying state. This pseudocode shows updating the database and then publishing to the hub with the topic and data. ```pseudocode function updateBook(id, data): db.update(id, data) hub.publish( topic="https://example.com/books/" + id, data=json(data), ) ``` -------------------------------- ### Server-provided notification count payload Source: https://mercure.rocks/docs/use-cases/notifications Example notification payload where the server includes the new total unread count. Render the unread field as the authoritative count. Include a version or timestamp if concurrent publishers can produce counts out of order. ```json { "type": "mention", "from": "alice", "unread": 7 } ``` -------------------------------- ### Subscribe to multiple topics with match parameters Source: https://mercure.rocks/docs/reference/faq Pass several match* parameters to the EventSource URL to subscribe to multiple topics over one connection. The SSE stream carries updates matching either parameter. ```javascript const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append("match", "https://example.com/announcements"); url.searchParams.append( "match_urlpattern", "https://example.com/users/:id/notifications", ); new EventSource(url); ``` -------------------------------- ### Enable Prometheus metrics in Caddyfile GLOBAL_OPTIONS Source: https://mercure.rocks/docs/production/health-monitoring Add the `metrics` directive to the global options block to enable Prometheus metrics on the admin API at `/metrics`. The hub then exposes Caddy's built-in metrics plus Mercure-specific ones. ```caddyfile { metrics } ``` -------------------------------- ### Run Mercure hub with JWT keys via Docker Source: https://mercure.rocks/docs/getting-started/installation Generate each key once with openssl rand -base64 32 and export it as MERCURE_PUBLISHER_JWT_KEY / MERCURE_SUBSCRIBER_JWT_KEY: anyone can forge tokens signed with the development key. ```bash docker run \ -e MERCURE_PUBLISHER_JWT_KEY \ -e MERCURE_SUBSCRIBER_JWT_KEY \ -p 80:80 -p 443:443 \ dunglas/mercure ``` -------------------------------- ### GET /.well-known/mercure Source: https://mercure.rocks/docs/concepts/topics-and-matchers Opens an SSE connection to subscribe to updates. The subscriber sends between 1 and 100 match* query parameters to specify matchers. The hub delivers updates whose topic matches at least one of the provided matchers. ```APIDOC ## GET /.well-known/mercure ### Description Opens an SSE connection to subscribe to updates. The subscriber sends between 1 and 100 match* query parameters to specify matchers. The hub delivers updates whose topic matches at least one of the provided matchers. ### Method GET ### Endpoint /.well-known/mercure ### Parameters #### Query Parameters - **match** (string) - Optional - Exact matcher. Alias for match_exact. Specifies a topic to match exactly. - **match_exact** (string) - Optional - Exact matcher. Explicit spelling of match. - **match_urlpattern** (string) - Optional - URL Pattern matcher. Specifies a URL pattern to match families of URLs. ### Request Example GET /.well-known/mercure?match=https://example.com/books/1&match_urlpattern=https://example.com/users/:id HTTP/2 ### Response #### Success Response (200) - **SSE stream** - The connection is established and updates are sent as Server-Sent Events. #### Response Example (SSE stream) ### Error Handling - **400 Bad Request** - Returned if a query parameter name is under the reserved `match` prefix but is not `match`, `match_exact`, or `match_urlpattern` (parameter names are case-sensitive). ``` -------------------------------- ### Subscribe with match and match_urlpattern parameters Source: https://mercure.rocks/docs/concepts/topics-and-matchers Builds a Mercure EventSource URL with both an exact `match` topic and a `match_urlpattern` pattern. The subscription receives the exact announcement topic or any user-notifications URL. URL Pattern compilation is budgeted at 2 MiB per pattern and 8 MiB per request; exceeding the aggregate budget returns `400 Bad Request` before any pattern is compiled, and exact matchers do not consume this budget. ```javascript const url = new URL("https://hub.example.com/.well-known/mercure"); url.searchParams.append("match", "https://example.com/site/announcement"); url.searchParams.append( "match_urlpattern", "https://example.com/users/:id/notifications", ); new EventSource(url); ```