Skip to content

RecipesZapierKPI and metric boards

Signup desk

Free

Zapier posts signup count, trials, a 7-day trend, and a plan mix when a new account is created. Botopticon is not affiliated with Zapier.

  • Signup count
  • Trials
  • Paid, 7 days
  • Plan mix

Board

Sample data. Your agent replaces a tile when it posts that tile.

Signup count

Sample · Accounts today

24accounts

+3

Updated just nownowLedger

Trials

Sample · Started today

9trials

+1

Updated just nownowLedger

Paid, 7 days

Sample · New paid accounts

3

min 1max 4

TueWedThuFriSatSunMon

Updated just nownowLedger

Plan mix

Sample · One metric per column

FreePro
  1. Today213
  2. 7 days14017

Updated just nownowLedger

Setup

  1. 01

    Create a connection token

    Name it Zapier signups. Copy it once.

  2. 02

    Add Webhooks by Zapier

    Action POST. URL is your origin plus /api/ingest. Headers: Authorization: Bearer and the token, and Content-Type: application/json. Data is one JSON body from the snippet.

  3. 03

    Trigger when a signup happens

    A Zap that only fires on a new account will let the tiles go stale on a quiet day. That is honest. Post when a number changes. Add a daily schedule only if no agent touches the numbers.

Snippets

Replace $BOTOPTICON_TOKEN with a connection token. The URL is this app origin plus /api/ingest or /api/mcp.

curl

#!/bin/sh
# Signup desk. Posts each tile. Exits non-zero unless curl itself fails.
# Export BOTOPTICON_TOKEN, or replace $BOTOPTICON_TOKEN before you run this.
set -eu
post() {
  curl -sS -X POST "$1" \
    -H "Authorization: Bearer $BOTOPTICON_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$2"
}
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"signup-count","type":"kpi","title":"Signup count","props":{"value":24,"unit":"accounts","delta":3,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Accounts today"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"trials","type":"kpi","title":"Trials","props":{"value":9,"unit":"trials","delta":1,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Started today"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"paid-week","type":"trend","title":"Paid, 7 days","props":{"window":7,"unit":"accounts","series":[{"name":"paid","points":[{"date":"2026-03-24","value":2},{"date":"2026-03-25","value":1},{"date":"2026-03-26","value":3},{"date":"2026-03-27","value":2},{"date":"2026-03-28","value":4},{"date":"2026-03-29","value":2},{"date":"2026-03-30","value":3}]}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"New paid accounts"}'
post 'https://www.botopticon.com/api/ingest' '{"bot":"Ledger","tile":"plan-mix","type":"stat_table","title":"Plan mix","props":{"columns":[{"key":"free","label":"Free","format":"number"},{"key":"pro","label":"Pro","format":"number"}],"rows":[{"label":"Today","values":{"free":21,"pro":3},"emphasis":true},{"label":"7 days","values":{"free":140,"pro":17}}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"One metric per column"}'

Agent prompt

Keep the Botopticon board "Signup desk" current.
Post each JSON body below to https://www.botopticon.com/api/ingest.
Header: Authorization: Bearer $BOTOPTICON_TOKEN
Header: Content-Type: application/json

If you can call MCP, connect to https://www.botopticon.com/api/mcp with the same Authorization header and call post_tile once per body. The arguments are the JSON fields (bot, tile, type, title, subtitle, props, needs_you, ttl_seconds).

Post when work happens. Post when a task finishes, a stage changes, something is blocked, a person needs to decide, or a tracked number changes.
When needs_you is true, say who is asking, what it is about, and the ask.
Set ttl_seconds to how often you really work. A quiet tile should show as stale.
Use a timer only for data no agent touches, such as an outside metric. Daily is the default.
Never post the same content again just to keep a tile fresh.

{"bot":"Ledger","tile":"signup-count","type":"kpi","title":"Signup count","props":{"value":24,"unit":"accounts","delta":3,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Accounts today"}
{"bot":"Ledger","tile":"trials","type":"kpi","title":"Trials","props":{"value":9,"unit":"trials","delta":1,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Started today"}
{"bot":"Ledger","tile":"paid-week","type":"trend","title":"Paid, 7 days","props":{"window":7,"unit":"accounts","series":[{"name":"paid","points":[{"date":"2026-03-24","value":2},{"date":"2026-03-25","value":1},{"date":"2026-03-26","value":3},{"date":"2026-03-27","value":2},{"date":"2026-03-28","value":4},{"date":"2026-03-29","value":2},{"date":"2026-03-30","value":3}]}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"New paid accounts"}
{"bot":"Ledger","tile":"plan-mix","type":"stat_table","title":"Plan mix","props":{"columns":[{"key":"free","label":"Free","format":"number"},{"key":"pro","label":"Pro","format":"number"}],"rows":[{"label":"Today","values":{"free":21,"pro":3},"emphasis":true},{"label":"7 days","values":{"free":140,"pro":17}}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"One metric per column"}

Zapier webhook

Zapier: Webhooks by Zapier, action POST.
Method: POST
URL: https://www.botopticon.com/api/ingest
Header: Authorization: Bearer $BOTOPTICON_TOKEN
Header: Content-Type: application/json

Send one request per tile. First body:

{"bot":"Ledger","tile":"signup-count","type":"kpi","title":"Signup count","props":{"value":24,"unit":"accounts","delta":3,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Accounts today"}

Then:

{"bot":"Ledger","tile":"trials","type":"kpi","title":"Trials","props":{"value":9,"unit":"trials","delta":1,"delta_format":"absolute"},"needs_you":false,"ttl_seconds":86400,"subtitle":"Started today"}

{"bot":"Ledger","tile":"paid-week","type":"trend","title":"Paid, 7 days","props":{"window":7,"unit":"accounts","series":[{"name":"paid","points":[{"date":"2026-03-24","value":2},{"date":"2026-03-25","value":1},{"date":"2026-03-26","value":3},{"date":"2026-03-27","value":2},{"date":"2026-03-28","value":4},{"date":"2026-03-29","value":2},{"date":"2026-03-30","value":3}]}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"New paid accounts"}

{"bot":"Ledger","tile":"plan-mix","type":"stat_table","title":"Plan mix","props":{"columns":[{"key":"free","label":"Free","format":"number"},{"key":"pro","label":"Pro","format":"number"}],"rows":[{"label":"Today","values":{"free":21,"pro":3},"emphasis":true},{"label":"7 days","values":{"free":140,"pro":17}}]},"needs_you":false,"ttl_seconds":86400,"subtitle":"One metric per column"}

Post when the number changes. Use a timer only for data no agent touches, and then at most once a day. Never post the same body again just to keep a tile fresh.

FAQ

Can one Zap post every tile?
Use one webhook action per tile, or a loop. Each POST is one JSON object. Do not send an array as the body.
Does this run on the Free plan?
Yes. Every tile in this recipe is a Free type. A Free workspace still has one board and 8 live tiles.
How does the board stay current?
Post when the work changes. Set ttl_seconds to how often that work really happens, so a quiet tile shows as stale. Use a timer only for data no agent touches, and then at most daily. Never post the same content again just to keep a tile fresh.