Clicktag docs

Email reports

Clicktag emails daily, weekly or monthly stats digests: set workspace defaults once for every site, give any site its own settings (up to 25 recipients) or switch it off, and get one workspace digest across all sites, plus API alerts that email when an API fails, slows down or goes quiet, checked every minute.

Base URL: https://clicktag.io. Download OpenAPI or read this page as Markdown.

How the layers work

Layer Covers Wins when
Workspace defaults Every verified site set to Workspace default The site's mode is inherit (new sites start here)
Site settings One site, up to 25 recipients The site's mode is custom
Workspace digest One email per recipient across all your sites Always, independent of the site modes

A site on Custom never picks up default changes; a site on Workspace default always does. A site set to Off sends nothing, and unverified sites never send.

Access

Every route below except unsubscribe needs the owner's Firebase ID bearer token or a management key (read for GET, manage for changes); test sends need the Firebase token. The unsubscribe endpoints are public: the token in the link is the capability.

Method Route Result
GET /api/reports/defaults Workspace defaults and which sites use them
PUT /api/reports/defaults Save workspace defaults
GET /api/reports/workspace Workspace digest settings
PUT /api/reports/workspace Save workspace digest settings
POST /api/reports/workspace/test Email the digest to yourself now
GET /api/reports/workspace/preview Render the digest as HTML
PATCH /api/sites/{hostname} Set reports_mode to inherit, custom or off
GET /api/sites/{hostname}/reports Mode, site subscriptions and what the site sends
POST /api/sites/{hostname}/reports Add a recipient (201)
PATCH /api/sites/{hostname}/reports/{id} Update frequency, schedule, sections
DELETE /api/sites/{hostname}/reports/{id} Remove a recipient
POST /api/sites/{hostname}/reports/{id}/test Queue a test email for the current window
GET /api/sites/{hostname}/reports/preview Render the email as HTML
GET /api/reports/unsubscribe/{token} Confirmation page (HTML)
POST /api/reports/unsubscribe/{token} One-click unsubscribe (HTML)

Cadence and windows

Frequency Sends Covers
daily every day yesterday (local)
weekly Mondays previous Monday to Sunday
monthly the 1st of the month previous calendar month

send_hour is a local wall-clock hour (0-23) in the subscription's IANA timezone; daylight-saving changes follow the clock, not a fixed UTC offset, so a send hour that a spring-forward change skips sends when the clocks jump, and one that a fall-back change repeats sends once. Due reports are queued at 7 minutes past each hour. Every report covers the last fully elapsed period, so a weekly report mailed Monday 09:00 Europe/Amsterdam always covers the Monday-Sunday that just ended in that timezone.

Timezones are stored in canonical form, so europe/amsterdam comes back as Europe/Amsterdam; fixed offsets such as +02:00 are refused with 400 invalid timezone.

Changes compare with the period before of the same kind: the day before, the Monday to Sunday before, or the whole previous calendar month. A top row's change uses its own count in that period, even when it wasn't a top row then.

Sections

Key Default Contents
overview always on Totals, change vs previous period, chart, live count
pages on Top 5 pages with change vs previous period
referrers on Top 5 referrers with change
countries off Top 5 countries with change
events off Top 5 events with change
alerts on Spike/dip callout for abnormal days
api on Requests, error rates, p95, top and failing endpoints

The alert section flags the most extreme day in the period whose pageviews land more than 2.5 standard deviations and more than 50% away from the trailing 28-day mean, and names the top 3 referrers of a spike day. It needs at least 14 days of history before the period, so new sites get no callout for about two weeks.

The api section shows request volume and p95 latency with change, 5xx and 4xx rates, the top 5 endpoints and the endpoints with the most 5xx responses. It only appears when the site received API requests in the period or the one before; a site with API traffic but no pageviews in either period gets it as the headline instead of empty web totals.

Workspace defaults

PUT /api/reports/defaults accepts any subset of enabled, recipients (up to 10), frequency, timezone, send_hour and sections. Changes apply on save to every site on Workspace default; each recipient gets one email per site. GET also returns sites (how many sites inherit, which are on Custom or Off), stalled (default recipients that failed five times in a row on an inheriting site) and dropped (addresses removed by an unsubscribe or a hard bounce since the last save). A save clears dropped and resets the failure counts of default and digest recipients, so stalled ones are retried.

bash
curl -X PUT "$TT_HOST/api/reports/defaults" \
  -H "Authorization: Bearer $TT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"recipients":["team@company.com"],"frequency":"weekly","timezone":"Europe/Amsterdam","send_hour":9}'

Send back the updated_at you read to avoid overwriting someone else's change: if the settings changed in between, the save returns 409. The defaults and the digest share one version, so save one before editing the other. POST /api/sites/{hostname}/reports on a site that isn't set to Custom returns 409 with switch this site to custom reports first.

Per-site settings

PATCH /api/sites/{hostname} with {"reports_mode":"custom"} gives the site its own recipients; the first switch to Custom copies the current default recipients, schedule and sections into the site, so nothing changes until you edit them. Switching away from Custom keeps the site's own recipients for when you switch back. GET /api/sites/{hostname}/reports returns mode, the site's subscriptions and effective: who the site mails right now and when, or why it sends nothing.

POST /api/sites/{hostname}/reports accepts email, frequency, and optional timezone (default UTC), send_hour (default 9) and sections. The site must be verified (403) and set to Custom (409). One subscription per site, email and frequency; duplicates return 409. At most 25 subscriptions per site, paused ones included and an address on two frequencies counting twice; the next one returns 429 with too many recipients for this site. Addresses you add are active right away, without a confirmation email.

bash
curl -X POST "$TT_HOST/api/sites/$TT_HOSTNAME/reports" \
  -H "Authorization: Bearer $TT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"teammate@company.com","frequency":"weekly","timezone":"Europe/Amsterdam","send_hour":9}'

PATCH accepts any subset of frequency, timezone, send_hour, enabled, sections. Setting enabled to false pauses without deleting. Setting it back to true resets fail_count and needs a verified site. Moving an address to a frequency it already has returns 409.

POST .../test queues a real email to that subscription's address for the current last-full-period window and returns 202 with the window it used, or 502 when the queue is unavailable. It sends at most once per 30 seconds per subscription (429 otherwise), and a paused subscription returns 409. Test sends never consume or block the scheduled window; a delivered test resets fail_count and sets last_sent_at.

GET .../preview?frequency=weekly&tz=Europe/Amsterdam&sections=pages,referrers,alerts renders the email HTML inline; omit sections to see everything on. overview is always included, unknown section keys are ignored, frequency defaults to weekly and an unknown tz falls back to UTC.

Workspace digest

One email per recipient with total visitors and pageviews against the previous period, a row per site with visitors in either period, the biggest movers (up to three each way among sites with at least 50 visitors in either period), the quiet sites, and one requests and 5xx line per API site. It follows the same cadence and windows as site reports.

PUT /api/reports/workspace accepts enabled, recipients (up to 10), frequency, timezone, send_hour and updated_at, with the same rules as the defaults. POST /api/reports/workspace/test emails the digest for the last full period to you, the signed-in owner, at most once per 30 seconds (429 otherwise), and returns the address and window. It needs at least one digest recipient and a verified site (400 otherwise), though it only mails you. GET /api/reports/workspace/preview?frequency=weekly&tz=Europe/Amsterdam renders it as HTML.

Delivery and unsubscribe

Mail is sent from reports@totallytics.com over a Postmark broadcast stream with List-Unsubscribe and RFC 8058 one-click headers. Unsubscribing from a site's own subscription sets enabled to false and keeps history; re-enable from the site's settings. Unsubscribing from a default or digest email removes that address from that workspace list right away (a default address stops for every inheriting site); it shows up under dropped until the next save.

A permanent failure (an invalid address, or one Postmark marks inactive, for example after a hard bounce) disables a site's own subscription immediately. On a default or digest email, an inactive address is removed from the workspace list and an invalid one counts as a failure. Transient failures retry three times, then the send is marked failed and fail_count rises. Recipients with five consecutive failures stop being scheduled until re-enabled or saved again.

API alerts

Per-site rules on API traffic, checked every minute. All routes need the owner's Firebase ID token or a management key (read for GET, manage for changes), except POST .../test, which needs the Firebase token. Adding, changing and testing rules also needs a verified site; listing and deleting don't.

Method Route Result
GET /api/sites/{hostname}/alerts List rules
POST /api/sites/{hostname}/alerts Add a rule (201)
PATCH /api/sites/{hostname}/alerts/{id} Pause or resume with enabled
DELETE /api/sites/{hostname}/alerts/{id} Remove a rule
POST /api/sites/{hostname}/alerts/{id}/test Email a sample alert now
Metric Fires when threshold
error_rate the share of 5xx responses in the window is above the threshold percent, 0 to below 100
p95_ms p95 latency in the window is above the threshold ms, below 600000
silence the window has no requests while the same window yesterday had min_requests none

window_minutes is 5, 15 or 60, ending a minute back so in-flight batches land first. Set method and route (the template shown in the API view, such as /v1/orders/:id) to watch one endpoint; leave both out for the whole API. Windows with fewer than min_requests requests (default 20) never fire a rule, and a firing rule resolves in them with a "too few requests" email. A p95_ms window without latency buckets keeps the current state. recipients defaults to the signed-in owner's email; a management key has none, so it must send recipients (400 recipients is required when using a management key otherwise). Up to 10 recipients per rule and 20 rules per site, after which adding one returns 429.

bash
curl -X POST "$TT_HOST/api/sites/$TT_HOSTNAME/alerts" \
  -H "Authorization: Bearer $TT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"metric":"error_rate","threshold":2,"window_minutes":15,"method":"POST","route":"/v1/orders"}'

A rule is ok or firing. Crossing the threshold sends one alert and marks it firing; nothing more is sent until it recovers, which sends one resolved email. An alert stays firing or resolved for at least 10 minutes, so a value hovering at the threshold can't flap. last_value holds the value behind the latest change. Pausing resets the rule to ok. POST .../test emails a sample only to you, the signed-in owner, once per 30 seconds per rule, and leaves the state alone.

Alerts come from alerts@totallytics.com on a transactional stream with a link to the site's API view. Every firing and resolved email carries a one-click unsubscribe link (and List-Unsubscribe headers) for its own recipient: GET /api/alerts/unsubscribe/{id}/{token} shows a confirm page and POST removes that address from the rule, or pauses the rule when it was the last one. Report unsubscribes don't affect alerts.