Skip to main content

Template analytics

A template you reuse — an order confirmation, an appointment reminder, a promo blast — accumulates engagement history spread across every campaign that sent it. Template analytics consolidates that history: one rollup that answers “which message actually converts” without opening each campaign individually. GET /api/v1/templates/{id}/analytics returns the template’s cross-campaign totals and rates, plus a per-campaign funnel so you can see where engagement came from.

What the rollup returns

The response carries four blocks:
  • template — the template’s id, name, channel, and status, so the rollup is self-describing.
  • totals — cross-campaign counters: campaigns (how many campaigns used the template), sent, delivered, failed, terminal, opened, clicked.
  • rates — conversion fractions rounded to two decimals (0.42 = 42%):
    • delivery_rate = delivered / terminal
    • open_rate = opened / delivered
    • click_rate = clicked / delivered
  • campaigns — one row per campaign that references the template, newest first, each with its channel and sent → delivered → failed → opened → clicked funnel.
Two details matter when you read the numbers:
  • Terminal is the denominator, not sent. Delivery rate divides delivered by terminal messages — messages that reached a final state. A campaign still sending reports a lower, honest rate instead of a padded one, because in-flight rows never inflate the denominator.
  • degraded: true means “no data right now,” not “zero engagement.” During a transient database wobble the API serves a zeroed fallback with degraded: true rather than an error. Treat that response as “try again shortly” — a template with a real history never shows zeros on a healthy read.
Sent counts read the campaign-level counter (messages handed to a provider), the same convention as every other sent surface in Orbit, so template analytics and campaign detail agree when you compare them.

Query the rollup

Fetch the analytics for one template by id:
cURL
Node.js
Browser (web SDK)
The response:

Compare two template versions

Editing a template’s body creates a new version with a new id — the old version’s history stays behind. Fetch analytics for both ids and compare the rates:
Node.js
Normalize before you judge: delivery rate carries the same denominator convention on both versions, and open/click rates divide by deliveries — so a version with far fewer sends still compares fairly on rates even though its raw counters are smaller. Wait until the newer version has accumulated enough terminal messages for its rates to stabilize; a version with twelve sends tells you nothing yet.

Spot a delivery drop after an edit

When a template edit correlates with worse deliverability, compare per-campaign funnels rather than the lifetime totals — totals blend old and new history. Pull the analytics for the current version and read campaigns newest-first: the most recent rows are all post-edit sends. If delivery_rate on recent campaigns sits clearly below the template’s pre-edit level while sent volumes are comparable, the content change is the first suspect — a new URL domain, a shortened link, or reworded copy can change carrier filtering. Check the per-campaign failed counter alongside: a delivery drop with flat failures points at filtering; rising failures point at rejects (inspect the campaign’s error breakdown for codes).

Break down by channel

Templates with the same copy on SMS and WhatsApp rarely perform identically. The campaigns rows each carry channel, so group and aggregate client-side:
Node.js
Compute channel rates from the aggregated counters (clicked/delivered for click-through) rather than averaging per-campaign rates — per-campaign rows carry different weights, and a naive mean overweighs small campaigns.

Troubleshooting

  • All zeros with degraded: true. A transient database blip served the fallback. Retry; persistent degradation means contact support, not that the template has no history.
  • campaigns stops at 500 rows. The rollup is a recency-ordered overview, capped at the 500 most recent campaigns. Older campaigns still exist — read them through the campaigns API if you need the full archive.
  • open_rate is 0 on SMS/WhatsApp sends. Opens are recorded only where the channel reports them: email opens via tracking, chat-channel reads via read receipts. SMS has no open signal, so opened stays 0 and open_rate follows.
  • 404 on the call. The template id does not exist in your tenant (or was deleted). List templates via GET /api/v1/messages/templates to confirm the id.