Skip to content

Custom Metrics API

The custom metrics API is the most flexible part of numbrs. If you can run a curl command, you can get data onto a dashboard. Use it for system stats, GitHub Actions results, cron job outputs, IoT readings — anything numeric.

Estimated setup time: 2 minutes

Get your API key from Settings → API Keys, then push a metric:

Terminal window
curl -X POST https://numbrs.lol/api/ingest \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"metric": "my.first.metric", "value": 42}'

That’s it. The data point is in your database.

If you’re self-hosting, replace https://numbrs.lol with your own URL.

Endpoint: POST /api/ingest
Authentication: Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
"metric": "server.cpu_pct",
"value": 23.4,
"timestamp": "2025-03-25T20:00:00Z",
"tags": {
"host": "mac-mini",
"env": "production"
}
}
FieldTypeRequiredDescription
metricstringyesDot-separated name, e.g. server.cpu_pct
valuenumberyesThe numeric value to record
timestampISO 8601noWhen the measurement was taken. Defaults to now.
tagsobjectnoKey-value string pairs for filtering in dashboards

Send up to 100 metrics in one request — just use an array:

Terminal window
curl -X POST https://numbrs.lol/api/ingest \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '[
{"metric": "server.cpu_pct", "value": 23.4, "tags": {"host": "mac-mini"}},
{"metric": "server.mem_used_gb", "value": 6.1, "tags": {"host": "mac-mini"}},
{"metric": "server.disk_used_gb", "value": 142.7, "tags": {"host": "mac-mini"}}
]'

Batch requests are more efficient than individual calls when you’re pushing multiple metrics at once.

Tags are key-value pairs you attach to a metric when pushing it. They let you push the same metric name from multiple sources and then filter by tag in the dashboard panel.

Example: you’re tracking CPU on three machines. Instead of three metric names, use one name + a host tag:

Terminal window
# Machine 1
{"metric": "server.cpu_pct", "value": 45.2, "tags": {"host": "mac-mini"}}
# Machine 2
{"metric": "server.cpu_pct", "value": 12.8, "tags": {"host": "vps-1"}}
# Machine 3
{"metric": "server.cpu_pct", "value": 78.1, "tags": {"host": "raspberry-pi"}}

In the dashboard panel editor:

  1. Select metric: server.cpu_pct
  2. Add tag filter: host = mac-mini

Each panel shows one filtered slice. Add three panels — one per host — to compare them side by side on the same dashboard.

Common tag keys people use:

  • host — which machine
  • env — production / staging / local
  • repo — which GitHub repo
  • project — which codebase
  • channel — which Slack/Discord channel

Tags are completely free-form. Use whatever makes sense for your data.

Use dot-separated names following a source.category.name pattern:

server.cpu_pct
server.disk.used_gb
github.myrepo.deploy_count
bitcoin.price_usd
home.office.temp_c

Keep names lowercase with underscores for spaces. Consistent naming makes filtering in dashboards much easier.

CodeMeaning
200Data accepted
400Bad request — check your JSON structure
401Invalid or missing API key
422Validation error — check field types
429Rate limited — slow down

Push CPU, RAM, and disk from any Unix system:

#!/usr/bin/env bash
# numbrs-system-stats.sh — run every 5 minutes via cron
API_KEY="your-api-key"
HOST="mac-mini"
BASE_URL="https://numbrs.lol/api/ingest"
# CPU usage (macOS)
CPU=$(top -l 1 -s 0 | grep "CPU usage" | awk '{print $3}' | tr -d '%')
# Memory pressure % (macOS)
MEM=$(memory_pressure | grep "System-wide memory free percentage" | awk '{print 100 - $NF}')
# Disk used GB
DISK=$(df -g / | awk 'NR==2{print $3}')
curl -sX POST "$BASE_URL" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "[
{\"metric\":\"server.cpu_pct\", \"value\":$CPU, \"tags\":{\"host\":\"$HOST\"}},
{\"metric\":\"server.mem_pct\", \"value\":$MEM, \"tags\":{\"host\":\"$HOST\"}},
{\"metric\":\"server.disk_used_gb\",\"value\":$DISK, \"tags\":{\"host\":\"$HOST\"}}
]"

Add to cron: */5 * * * * API_KEY=... bash ~/numbrs-system-stats.sh

Terminal window
BATTERY=$(pmset -g batt | grep -Eo '\d+%' | tr -d '%')
curl -sX POST https://numbrs.lol/api/ingest \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"metric\":\"mac.battery_pct\",\"value\":$BATTERY}"

Add a step to any workflow:

- name: Record deploy in numbrs
run: |
curl -sX POST https://numbrs.lol/api/ingest \
-H "Authorization: Bearer ${{ secrets.NUMBRS_API_KEY }}" \
-H "Content-Type: application/json" \
-d "{
\"metric\": \"github.deploys\",
\"value\": 1,
\"tags\": {
\"repo\": \"${{ github.repository }}\",
\"branch\": \"${{ github.ref_name }}\",
\"status\": \"success\"
}
}"

Pull the price from a public API and push it to numbrs every 5 minutes:

#!/usr/bin/env bash
PRICE=$(curl -s "https://api.coinbase.com/v2/prices/BTC-USD/spot" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['amount'])")
curl -sX POST https://numbrs.lol/api/ingest \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"metric\":\"bitcoin.price_usd\",\"value\":$PRICE}"
import urllib.request, json
def push(api_key, metric, value, tags=None, timestamp=None):
payload = {"metric": metric, "value": value}
if tags:
payload["tags"] = tags
if timestamp:
payload["timestamp"] = timestamp
data = json.dumps(payload).encode()
req = urllib.request.Request(
"https://numbrs.lol/api/ingest",
data=data,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
)
urllib.request.urlopen(req)
push("your-api-key", "app.response_time_ms", 47.3, {"endpoint": "/api/users"})

Once metrics are flowing in, go to Dashboards, add a panel, and select your metric from the dropdown. Choose a panel type based on what you’re measuring:

  • Line / Area — time series, great for trends
  • Stat — latest single value (current CPU, current price)
  • Gauge — current value within a range (battery %, disk %)

Metrics are retained for 90 days on the hosted plan.