Most people never open the dashboard; they'd read it if it came to them. A picture of yesterday's numbers in the team's Slack channel every morning, or a PDF of the monthly dashboard in the board's inbox, gets looked at. BI tools have scheduled exports, but they're often limited to paid tiers, one tool, or ugly layouts. A screenshot works with any dashboard, including your own admin.
Capture a dashboard
Log in with a token or session cookie, wait for the panels to finish loading, and capture at a wide viewport:
curl -X POST "https://shotkit.net/api/take" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://grafana.example.com/d/abc123/sales?orgId=1&from=now-24h&to=now&kiosk","authorization":"Bearer YOUR_SERVICE_ACCOUNT_TOKEN","viewport_width":1600,"viewport_height":1000,"full_page":true,"wait_until":["networkidle0"],"delay":2,"format":"png","response_type":"json"}' \
--fail-with-body -o shot.jsonGrafana's kiosk mode hides its menus; Metabase's public or embedded dashboards and Looker Studio's view mode do the same. networkidle0 waits for the data queries, and a short delay covers charts that animate in.
One panel only
Crop to one chart with selector, or hide everything else with hide_selectors:
curl -X POST "https://shotkit.net/api/take" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://admin.example.com/metrics","cookies":["session=REPORTING_SESSION; Domain=admin.example.com; Secure"],"selector":"#revenue-chart","wait_for_selector":"#revenue-chart canvas","device_scale_factor":2,"format":"png","response_type":"json"}' \
--fail-with-body -o shot.jsonPost it to Slack
With response_type=json you get a public URL to the image, which Slack can show in an image block:
const shot = await take({ url, authorization, full_page: true, response_type: "json", cache_ttl: 86400 });
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
blocks: [
{ type: "section", text: { type: "mrkdwn", text: "*Sales, last 24 hours*" } },
{ type: "image", image_url: shot.screenshot_url, alt_text: "Sales dashboard" },
],
}),
});Run it from a cron job each morning. For email reports, attach a PDF instead: same request with format: "pdf", pdf_fit_one_page and pdf_print_background.
Keep the data private
The file URL is unguessable but public until it expires. For sensitive numbers, keep cache_ttl at the 4-hour minimum, or download the image and upload it to Slack with its files API so it lives only in your workspace.
Frequently asked questions
Does Grafana need its image renderer plugin for this?
No. The screenshot is taken by shotkit's browser, so nothing needs to be installed on your Grafana server. Use a service account token with viewer access.
My dashboard shows a loading spinner in the screenshot. What do I do?
Wait for something that only appears when data has loaded: wait_for_selector on a chart's canvas, or a longer delay. Raising timeout helps for slow queries.
Can I screenshot dashboards on our internal network?
Only if the dashboard is reachable from the internet, for example through an authenticated reverse proxy. The browser runs on shotkit's servers, not inside your network.