A dashboard is only useful if it is current, and nobody wants to paste numbers into it every morning. The fix is a small job that computes the numbers and pushes them to Output Charts on a schedule. This guide shows two places to run it: cron on a server you already have, and GitHub Actions if you would rather not have a server at all.
Both send the same request: a PUT of a JSON document to a visual's push URL, with an API key. If you have not pushed before, start with How to update a dashboard chart with cURL.
What you need
- A Solo plan, since API push is part of Solo.
- An API key from Account → API keys (it starts with
oc_live_). - The visual's push URL: in the editor, select the visual and choose Copy push URL under Push from code.
The examples build the JSON with jq, which escapes values correctly, so a stray quote in a label cannot break the request.
Option 1: cron
Put the key and the URL in a file only the job's user can read:
# /home/deploy/.output-charts (chmod 600)
export OC_KEY="oc_live_..."
export VISUAL_URL="https://api.outputcharts.com/visuals/<visual-id>/data"
Then write the job. This one counts today's orders in Postgres and pushes the number to a KPI:
#!/usr/bin/env bash
# /home/deploy/push-orders.sh
set -euo pipefail
source /home/deploy/.output-charts
count=$(psql "$DATABASE_URL" -tAc "select count(*) from orders where created_at >= current_date")
jq -n --argjson value "$count" '{label: "Orders today", value: $value, format: "number"}' |
curl --fail-with-body -sS -X PUT "$VISUAL_URL" \
-H "Authorization: Bearer $OC_KEY" \
-H "Content-Type: application/json" \
--data @-
--fail-with-body makes curl exit with an error when the API refuses the push, while still printing the API's message, so the failure lands in the log instead of passing silently.
Schedule it with crontab -e. This runs every hour, two minutes past:
2 * * * * /home/deploy/push-orders.sh >> /var/log/push-orders.log 2>&1
cron starts jobs with an almost empty environment, which is why the script sources its own settings rather than relying on your shell's. Anything else it needs, like DATABASE_URL, goes in the same file.
Option 2: GitHub Actions
GitHub Actions can run the job for you on a schedule, with no server. Add the key and the URL as repository secrets named OC_KEY and OC_VISUAL_URL (Settings → Secrets and variables → Actions), then add a workflow. This one pushes the number of open issues every morning:
# .github/workflows/dashboard.yml
name: Update dashboard
on:
schedule:
- cron: "0 6 * * *" # 06:00 UTC every day
workflow_dispatch: # also runs from the Actions tab
permissions:
issues: read
jobs:
push:
runs-on: ubuntu-latest
steps:
- name: Count open issues
id: count
env:
GH_TOKEN: ${{ github.token }}
run: |
open=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --limit 1000 --json number --jq length)
echo "open=$open" >> "$GITHUB_OUTPUT"
- name: Push to Output Charts
env:
OC_KEY: ${{ secrets.OC_KEY }}
VISUAL_URL: ${{ secrets.OC_VISUAL_URL }}
OPEN: ${{ steps.count.outputs.open }}
run: |
jq -n --argjson value "$OPEN" '{label: "Open issues", value: $value, format: "number"}' |
curl --fail-with-body -sS -X PUT "$VISUAL_URL" \
-H "Authorization: Bearer $OC_KEY" \
-H "Content-Type: application/json" \
--data @-
gh and jq come installed on GitHub's Ubuntu runners. Two things to know about scheduled workflows: the times are in UTC, and GitHub can start them a few minutes late when it is busy. In a public repository, GitHub also turns schedules off after 60 days without activity in the repository.
The same steps work outside a schedule. Put them at the end of a deploy workflow to chart build times, test counts or bundle sizes after every release.
Pushing a chart instead of a number
Swap the jq filter for the document your visual takes. For a line chart of the last seven days, your job would produce rows like these:
{
"xKey": "day",
"curve": "monotone",
"series": [{ "key": "orders", "label": "Orders" }],
"data": [
{ "day": "2026-10-12", "orders": 182 },
{ "day": "2026-10-13", "orders": 207 },
{ "day": "2026-10-14", "orders": 199 }
]
}
Every push replaces the whole document, so send all seven rows each time. The JSON to chart tool shows the shape for each visual type.
Things to know
- Re-running is safe. A push replaces the document, so a retried job leaves the same result.
- Give each job its own key. Solo has up to five, and revoking one stops only that job.
- Each key can push 60 times a minute, far more than any schedule needs.
- Open dashboards update by themselves. They check for new data every 15 seconds, so a screen on the wall shows the new numbers without a reload.
Create a free account to build the dashboard; upgrading to Solo turns on API keys.