Skip to content

Dashboard briefing

View on GitHub

Some numbers you can only get by looking at a dashboard: a SaaS vendor’s usage graphs with no export, a Grafana you can view but not query, an analytics share link. The charts are drawn in the browser after the app loads, so fetching those pages with a reader returns an empty shell.

This recipe reads the dashboard for you. It opens the page in a real browser, takes a screenshot, and asks a vision model to turn what it sees into a typed briefing:

DASHBOARD BRIEFING - https://plausible.io/plausible.io
Period: Last 30 days ↑ trending up
Unique visitors: 128k
Pageviews: 340k
Worth a look:
- Jun 24: spike to ~2x the surrounding baseline
Traffic is up over the period with a clear weekday rhythm. The Jun 24 spike
stands out against an otherwise steady trend; worth checking what shipped
or got posted that day.

The output is a Schema, so the briefing is data rather than prose. You can post it to Slack, diff it against last week’s, or alert when anomalies is non-empty. Put it on a schedule and nobody has to remember to look.

Try it

Start a headless Chromium with its DevTools port open (screenshots need a real rendering engine; see the CDP provider for other ways to get one):

Terminal window
docker run -d --name chromium -p 127.0.0.1:9222:9222 chromedp/headless-shell

Then run it. The default target is Plausible’s own public dashboard, live traffic for plausible.io, public on purpose:

Terminal window
GOOGLE_API_KEY=... pnpm tsx recipes/dashboard-briefing/run-node.ts

Point it at your own dashboard, e.g. a Plausible share link, a public Grafana, or any URL you can open in a browser:

Terminal window
DASHBOARD_URL="https://plausible.io/share/yoursite.com?auth=..." \
GOOGLE_API_KEY=... pnpm tsx recipes/dashboard-briefing/run-node.ts

Configuration

Env varDefaultMeaning
GOOGLE_API_KEY(required)Gemini API key for the vision model.
DASHBOARD_URLhttps://plausible.io/plausible.ioThe dashboard to read.
MODELgemini-3-flash-previewVision-capable model id.
SETTLE2 secondsHow long to let the page render before the screenshot.
CDP_URLhttp://127.0.0.1:9222Chromium debug address (http:// is resolved to the ws:// endpoint automatically) or a full ws:// URL.
LOG_LEVELInfoSet Debug for screenshot/turn details.

How it works

There is no agent loop here. The recipe opens the page, waits a moment for it to render, screenshots the full page, and decodes one vision LanguageModel turn against the Briefing schema (period, trend, headline metrics, anomalies, summary). The schema’s field annotations double as instructions to the model, and the prompt holds it to what is visible: values read verbatim, estimates marked with ~, no invented numbers.

  • recipe.ts: the briefing schema and the screenshot-then-decode flow.
  • app.ts: composition (Chromium Browser Layer, Gemini LanguageModel Layer), env config, and the briefing formatter.
  • run-node.ts: attaches the Node HttpClient and starts the runtime.

Next to agent usability testing this is the other half of the Browser story: that recipe acts on pages through a tool loop; this one reads pixels through a single structured turn.