This project is not covered by Drupal’s security advisory policy.
Live Breakdown shows how a total splits into parts, live. It renders a donut chart and a table in a block, and updates them in the browser within about a second of new data arriving, without page reloads or Ajax calls on a timer.

It works for any "share of total" data: traffic by source, votes by option, tickets by status, sales by region, or market share by venue.
How it works
A small companion service written in Go (standard library only) holds the current data and pushes updates to browsers with Server-Sent Events. Drupal provides the block, the settings, and a publish form. The live stream goes straight from the Go service to the browser, so open tabs never hold a PHP-FPM worker.
Features
- Live updates over SSE. One long-lived connection per browser replaces repeated polling requests.
- Handles bad networks. The widget reconnects automatically. It detects proxies that accept the stream but never send data, falls back to polling, and switches back to live streaming when it can.
- Cache-friendly. The block is fully cacheable. The snapshot route sends
public, max-age=2, so
Varnish or a CDN can absorb the polling traffic. - Saves resources. Updates pause when a tab is in the background, and several blocks on one page share a single connection.
- Publish form. Admins can enter names and values by hand and push them to every open page right away.
- Accessible and themeable. Colors use the Okabe-Ito palette, which is safe for colorblind readers, and the
chart has a text summary for screen readers. Every color is a CSS custom property (--lb-*) that your theme can
override. - Clear status. A badge tells readers whether the data is live, reconnecting, polling, paused, or offline.
Requirements
- Drupal 11
- The bundled Go service is required. It ships in the module's
go-service/folder and must be running and reachable from both PHP and visitors' browsers. To build or run it from source you need Go 1.22 or later. The server that runs a pre-built binary does not need Go installed.
What the Go service does
Drupal provides the block, the settings page, the publish form, and a snapshot route. It holds no live data itself; it asks the Go service over HTTP. The Go service holds the current numbers and pushes every change to the browsers that have the page open:
GET /stream: called by each visitor's browser directly. A Server-Sent Events connection that stays open; every update is pushed down it.GET /snapshot: called by Drupal through its/live-breakdown/snapshotroute. Returns the current numbers as JSON for the first page load, and as a fallback when streaming is blocked.POST /publish: called by Drupal's publish form. Accepts new numbers (protected by a token) and broadcasts them to every browser at once.GET /healthzandGET /readyz: health checks for monitoring and load balancers.- A built-in simulator generates demo data. For real use, replace it with code that reads your data source, or push updates to
/publish.
Why a separate service instead of PHP
A live stream is a connection that stays open as long as the tab is open, often for hours. In PHP, each open connection ties up a PHP-FPM worker for that whole time. Sites usually have only a few dozen workers, so a few dozen visitors could exhaust them. The Go service holds thousands of mostly idle connections cheaply in one process, which is why browsers connect to it directly instead of going through Drupal.
Is it mandatory?
Yes, as the module is written. Without it, the block's badge shows "Offline", the settings page reports "Not reachable", and the publish form has nothing to edit. Go itself is not strictly required, though: any server that offers the same endpoints and JSON format (Node, Rust, or a hosted push service) works. The Go service is the reference implementation shipped with the module.
How to run it
Go is a compiled language. The compiler produces a single self-contained native executable (about 8 MB) that needs no runtime or libraries on the server.
- Development:
go run .ingo-service/compiles to a temporary location and runs it immediately. Requires the Go toolchain. - Build a binary:
go build -o livebreakdown ., then run./livebreakdown. You can cross-compile from any machine, for exampleGOOS=linux GOARCH=amd64 go build -o livebreakdown .on a Mac for a Linux server. - Production: run the binary as a long-running service, like nginx or Redis: a systemd unit, or a small Docker image or Kubernetes deployment (with a readiness probe on
/readyzandLB_DRAIN_DELAYfor clean shutdowns). - DDEV: the included
ddev/docker-compose.live-breakdown.yamlruns the service in the official Go image.
The service is configured with environment variables: LB_ADDR (listen address, default :8090), LB_PUBLISH_TOKEN, LB_ALLOWED_ORIGINS, LB_TICK, LB_HEARTBEAT, LB_MAX_STREAM_LIFETIME, LB_DRAIN_DELAY, and LB_DEBUG. The README describes each one.
Getting started
- Install the module:
composer require 'drupal/live_breakdown:^1.0@alpha', thendrush en live_breakdown. - Start the Go service, which ships inside the module: from
web/modules/contrib/live_breakdown/go-service, rungo run . - Set the service URL and stream URL at Configuration › Web services › Live Breakdown.
- Place the Live Breakdown: live share chart block.
The README covers running the service inside DDEV, the publish token, and deploying to production.
Connecting your own data
The Go service ships with a simulator so you can see it working right away. For real data, replace the simulator with a
reader for your feed, or push updates from Drupal or any other system to the POST /publish endpoint. The hub and HTTP layer don't change.
Project information
- Project categories: Content display, Developer tools, Integrations
2 sites report using this module
- Created by jamestarleton on , updated
This project is not covered by the security advisory policy.
Use at your own risk! It may have publicly disclosed vulnerabilities.
Releases
Widget CSS anchored on the root so host theme table and SVG rules can't recolor it
Development version: 1.0.x-dev updated 9 Nov 2026 at 16:30 UTC

