> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading the SMS click-through rollup (Insights → SMS click-through)

> Tile-by-tile walkthrough of the /insights/sms-ctr page: the totals strip and per-bucket table, group and window controls, drilling from a CTR movement to the campaign or link behind it, API parity, and the misreads that waste operator time.

# Reading the SMS click-through rollup (Insights → SMS click-through)

The [link tracking analytics guide](/guides/link-tracking-analytics) closes with a one-line pointer to this page. This guide is where that pointer lands: **Insights → SMS click-through** (`/insights/sms-ctr`) rolls every tracked short link up into a per-campaign (or per-queue) click-through rate — the channel-level answer the per-link view can't give. If you need the per-link drill-down, go back to Link tracking; if you need the reconciliation math, mint mechanics, or email-parity reading, the [SMS click-through parity guide](/guides/sms-click-through-parity) covers those in depth. This page is the operator walkthrough of the rollup itself.

## 1. The tile map — what the page is made of

Open the dashboard sidebar's **Insights** entry; the **SMS click-through** tile on the hub grid routes into `/insights/sms-ctr`. One card holds the whole page, top to bottom:

1. **Header** — the title plus two `SegmentedControl`s: **Group by** (Campaign / Queue) and the **time window** (24h / 7d / 30d).
2. **Totals strip** — five KPI tiles aggregating every bucket in the window (Section 2).
3. **Bucket table** — one row per campaign or queue, with the per-bucket counters and rates (Section 2).
4. **Pagination bar** — appears only when the window holds more than 25 buckets.

The page honors the standard all-states contract: skeleton placeholders while loading, a retryable error lane ("Couldn't load the SMS click-through report") on a failed fetch, and a first-run empty state ("No tracked click-throughs yet") that links through to the Link tracking page — it never renders a healthy-looking blank dashboard.

## 2. KPI tiles and the bucket table

The **totals strip** carries five tiles, recomputed on every window change:

* **Sends (window)** — outbound SMS in the window, whether or not they carried a tracked link.
* **Sends with tracked links** — the trackable slice: sends that carried at least one tracked short link.
* **Sends clicked** — sends whose tracked links recorded at least one click.
* **Overall CTR** — sends clicked ÷ sends with tracked links, formatted as a one-decimal percentage.
* **Verified CTR** — verified (bot- and preview-filtered) clicks ÷ sends with tracked links. This is the number that compares against the email channel's Clicked metric.

Below the strip, the **bucket table** breaks the same counters down per campaign (or per queue, on the queue grouping). Its columns, left to right: **Campaign/Queue**, **Sends**, **Tracked**, **Clicked**, **Clicks** (raw), **Verified**, **CTR**, **Verified CTR**. A bucket with no tracked sends shows `—` in both rate columns rather than a misleading zero.

Rows sort by tracked sends descending, so buckets where click-through was measurable rank first; the ordering is fixed and the column headers don't re-sort. Campaign, variant, and link-level follow-up all start from this table (Section 4).

## 3. Filters and window semantics

Two controls scope every number on the page:

* **Group by: Campaign / Queue** — `Campaign` buckets on the `campaign_id` stamped at send time. `Queue` buckets on the messaging-service id recorded at send time, falling back to the provider tag when no queue resolves — exactly the precedence the API's `group` parameter uses.
* **Window: 24h / 7d / 30d** — the trailing aggregation window, defaulting to 7 days. There is deliberately no 90d option here; the schema-backed enum is the three values above, unlike the links page's wider 1–90 day range.

Switching either control restarts the table at page 1 — the old page index would otherwise slice rows that no longer exist. Pagination runs 25 buckets per page, and the totals strip always aggregates **all** buckets in the window, not just the page on screen. Numbers refetch every 60 seconds to stay in lockstep with the server-side cache, so a fresh send shows up on the strip within about a minute without a manual reload.

Sends where the scoped key never resolved — no `campaign_id` on the campaign grouping, no resolvable queue on the queue grouping — collect in the `unattributed` bucket. That is a catch-all, not an error grouping; the fix lives at send time (stamp the key on the payload), and the parity guide's [unattributed-bucket section](/guides/sms-click-through-parity) walks through it.

## 4. Actioning a CTR movement

Reading the number is the start; the page exists to tell you where to go next:

* **CTR dipped on one campaign** — identify the bucket, then open [Insights → Link tracking](/guides/link-tracking-analytics) and scope it with `campaign_id` for the per-link breakdown: which URL dragged the rate, and whether raw vs verified says it's real engagement loss or preview-fetch noise.
* **Comparing variants** — when the campaign ran A/B variants, the [campaign A/B testing guide](/guides/campaign-ab-testing) is the read surface for variant-level splits; the rollup here is the campaign-level backstop that tells you whether the whole campaign regressed or one variant did.
* **Queue grouping disagrees with campaign grouping** — a queue bucket with low CTR and healthy campaign buckets usually means a routing change moved sends into a queue whose recipients behave differently; check the [smart-send fallback chains guide](/guides/smart-send-fallback-chains) if fallback swapping is in play.
* **Tracked share is the problem, not CTR** — if `untracked` (sends − tracked) is the large number, no creative change moves CTR; shorten more of what you send. The parity guide covers the mint switches in precedence order.
* **Export for a spreadsheet or warehouse** — the rollup numbers pull straight from the API (Section 5), which is the reliable way to snapshot tiles into a CSV pipeline. For the per-link CSV, the **Export** button on the Link tracking page writes a windowed file with summary, top-links, and timeline sections.
* **Alert instead of watch** — wire a threshold or anomaly rule so a degrading CTR pages you rather than waits for a manual read; the parity guide's alerting section maps the two rule surfaces.

## 5. API parity

Every tile on the page maps to one endpoint — `GET /api/v1/analytics/sms-click-through` — with `group` and `window` taking exactly the control values (`campaign`/`queue`, `24h`/`7d`/`30d`) plus `page` and `pageSize` (default 25, max 100). The response returns the paged `rows`, the window-wide `totals` object, and `pagination` under the standard `{ data, meta }` envelope. Rate fields come back `null` when a bucket had no tracked sends — never a fabricated zero.

```bash cURL theme={null}
curl "https://api.orbit.devotel.io/api/v1/analytics/sms-click-through?group=campaign&window=7d&pageSize=25" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

All four workspace roles (owner, admin, developer, viewer) can read it, and the response is cached 60 seconds server-side. For request and response schemas, see the [SMS click-through API reference](/api-reference/sms-click-through).

## 6. Common misreads

* **Clicks vs link detection.** The first is engagement; the second is coverage. `Clicks` counts taps on links that were minted; `Sends − Tracked` is the volume that structurally cannot click. A high CTR on a small `Tracked` base is correct, not inflated — read the tracked share before the rate.
* **CTR vs delivered rate.** The denominator is tracked **sends**, not delivered messages — SMS has no bounce equivalent, so undelivered sends stay in the denominator and depress CTR. If CTR moved, check delivery health first ([usage and delivery anomaly alert rules](/guides/usage-anomaly-alert-rules)) before treating it as an engagement problem.
* **Raw vs verified CTR.** Raw counts bot and link-preview fetches, which spike on send day; verified applies the same quality filter the per-link analytics use. Comparing raw SMS CTR to email's Clicked metric is apples-to-oranges — email's number is already filtered.
* **`—` is not zero.** A bucket with no tracked sends has an undefined rate, and both the page and the API return null. Treating it as a 0.0% regression invents a problem.
* **`unattributed` is not an error.** It's the catch-all bucket for sends with no resolvable campaign or queue key; its size is an attribution hygiene signal, not a pipeline fault.
* **The page has no 90-day window.** The enum is 24h / 7d / 30d by design. For quarter-scale trend lines, pull the API on a schedule or use the Links insights endpoint's wider range.

## Troubleshooting

* **The totals strip disagrees with the visible rows.** It aggregates every bucket in the window, including pages beyond the one on screen — that is the correctness guarantee, not a bug.
* **A campaign I sent today isn't a row yet.** Buckets appear once the rollup resolves attribution; the 60-second cache means a fresh send lands within about a minute. If it stays absent past that, the send carried no tracked link — check the mint switches.
* **The empty state shows but I sent traffic this week.** The window may be narrower than your send cadence (a 24h window reads empty between weekly waves). Widen to 7d, and confirm at least one send carried a tracked link — the empty state only clears on sends the pipeline could track.

## See also

* [Reading link tracking analytics](/guides/link-tracking-analytics) — the per-link drill-down this rollup sits on top of.
* [SMS click-through parity guide](/guides/sms-click-through-parity) — reconciliation math, mint switches, unattributed-bucket fixes, and email-parity reading.
* [Short links and click tracking](/guides/short-links-and-click-tracking) — how links get minted, scored, and attributed.
* [SMS click-through API reference](/api-reference/sms-click-through) — the endpoint behind every tile.
* [Insights hub orientation](/insights/overview) — the tile grid and RBAC visibility for the Insights section.
