Live blogging for Craft CMS 5
Press ⌘↵. It's on the site.
Live is live blogging for Craft: a composer that publishes in one keystroke, and a feed that updates itself over the top of a page nobody re-rendered. No entry save, no cache purge, no PHP process per reader.
Publish, and watch a cached page catch up
On the left, the composer. On the right, a reader's page, cached since kick-off and never rendered again. Between them, the one file that changes. Publish something, edit an old update, delete one, pin another — then wait for the next poll. Turn off the wifi and publish anyway, or have Alex publish in the same millisecond as you.
This runs the plugin's own rules in your browser: sequence numbers allocated on arrival, revisions bumped on edit, tombstones on delete, and a reader that fetches only what it is missing. End the post and the reader stops asking.
Built for being read by everyone at once
A live blog is written forty times an hour by someone watching something happen, and read by everybody at the same moment. Almost nothing else on a Craft site behaves like that.
An update is its own element
One lightweight save: no revisions, no provisional draft, no search indexing, and the parent entry is never touched. Two journalists on one match are creating separate elements, so neither can overwrite the other.
Order from a sequence, not a clock
Each update gets a per-post number allocated under a row lock. Two editors publishing in the same millisecond get 412 and 413, and a reader holding 412 asks for "everything after 412" — a question with one right answer.
Delivery is static files
Each publish writes an immutable JSON file for the update and rewrites one small head.json. Readers poll head; nginx or your CDN answers without waking Craft.
- Every reader in the same poll window asks for the same URL
- One command rebuilds the files from the database
The page cache is never invalidated
The HTML page can be cached for a day, by Craft, Blitz, Varnish or a CDN. Updates arrive over the top of it. That is the point.
One card, rendered once
Updates carry HTML rendered by your own live/_update.twig at publish time, so an appended update is byte-identical to a server-rendered one. There is no second copy of the card in JavaScript to drift.
A composer for people watching something
A textarea, Markdown and a button per update type. ⌘↵ publishes; a dropped connection queues the update and retries; an edit stays where it is and quietly replaces the reader's copy.
- Update types with their own field layouts — a Goal asks for a scorer
- Pinning, key moments, and upcoming / live / paused / ended
Pro: a newsroom on top
Who else has the post open. Updates written now and released at 14:00 by your cron. Server-sent events for the internal dashboard. Throttled CDN purging for Cloudflare, Fastly or a webhook.
Pro: GraphQL shaped like the client
Poll liveFeed — one indexed row — and fetch liveUpdates(since: 412) only when the sequence moves. Each update type is its own schema component, so a token gets the commentary without the newsroom's internal feed.
One include
Server-rendered on first paint, updating itself afterwards. Copy the partials into your own templates to take over the markup — Craft looks there first.
{% include 'live/_feed.twig' with { feed: entry.commentary } %}
{# Or build it yourself #}
{% set feed = entry.commentary %}
{{ feed.state }} {# upcoming | live | paused | ended #}
{{ feed.count }}
{{ feed.pinned }} {# the pinned update, or null #}
{% for goal in feed.updates.type('goal').all() %}…{% endfor %}
{% for key in feed.highlights.all() %}…{% endfor %}
{# feed.seq changes on every publish and nothing else #}
{% cache using key "feed-#{entry.id}-#{feed.seq}" %}…{% endcache %}
What a reader asks for
A few hundred bytes of static JSON, every few seconds. When seq moves, the reader fetches the immutable file for each update it is missing; when a rev moves, it replaces that update in place.
GET /live-feed/1/923-14/head.json?t=357211
{
"seq": 413,
"state": "live",
"count": 218,
"pinned": 8811,
"poll": 5,
"updates": [ { "id": 8940, "seq": 413, "rev": 0 }, … ],
"removed": [ 402 ]
}
GET /live-feed/1/923-14/u-413.json?r=0
Frequently Asked Questions
The questions worth answering before you install it.
Lite is, and it is a complete live blog, not a demo of one: the composer, update types, the Twig API, static snapshots and polling, pinning, key moments and the four states. Pro is a one-off $99 with a $79/year renewal, and adds presence, scheduled updates, server-sent events, CDN purging and GraphQL.
Because every publish would be an entry save — a revision, a provisional draft, a search-index job and every cache the entry carries — forty times an hour while thousands of people read. In Live an update is its own element, so a publish is one lightweight save and the entry is never touched.
Yes, safely. They are creating separate elements, so there is nothing to overwrite, and order is settled by a sequence number allocated under a row lock. Pro adds presence, so they can see who else is in the post and don't cover the same moment twice.
Ten thousand requests for one small static file every few seconds — and with a CDN in front, close to one request per poll window reaching your server, because every reader in the window asks for the same URL. No PHP process, no database connection, no template render.
That is what it is designed for. Updates arrive over the top of the cached page rather than changing it, so publishing never invalidates the page cache. Pro adds throttled purging for readers who never run the JavaScript.
Yes. A live blog is only as public as its entry: on a scheduled, disabled or draft entry, updates are kept but nothing is served or written to the web root until the entry goes live.
For an internal dashboard, perhaps. For a cup final, no. Every connected reader holds a PHP process open, so on FPM your ceiling is pm.max_children — and you find out where it is at the moment a live blog goes well. Polling static JSON has no ceiling. SSE is Pro, and off by default.
None of them. Delivery is files on disk served by the web server you already run, and publishing needs no queue worker.
Craft CMS 5.3+ and PHP 8.2+.
Start free, upgrade for the newsroom
Lite is free and is a complete live blog. Pro is $99 with a $79/year renewal, and adds presence, scheduled updates, server-sent events, CDN purging and GraphQL.