Every send produces a carrier delivery receipt. Bird turns those receipts into delivery, failure, and latency metrics, broken down by country, carrier, and sender, in the dashboard and through a stats API you can query from your own code.
import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const code = generateOtp();
const { data, error } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your Bird verification code is ${code}. Reply STOP to opt out.`,
}).safe();
if (error) throw error;
console.log(data.id);
// → "sms_4kT01Lq2m..."Today at 2:14 PM
The reporting side of the same API.
Nothing new to instrument.
Analytics is the reporting side of the Bird SMS API. You already send through it and already receive a delivery webhook on every state change; analytics is Bird keeping the count for you, so you can ask how a campaign delivered without standing up a warehouse to hold the events first.
What a delivery receipt tells you.
Measured from the carrier, not inferred.
- 01
Delivery rate.
The share of sends the carrier confirmed delivered, against what was submitted. Track it per country and per sender, not just as one site-wide number that hides the route that's quietly dropping.
- 02
Failure reasons by carrier.
Failed sends carry the carrier's reason code, grouped by destination carrier (MCC/MNC). A spike is usually one operator rejecting one sender ID, which is a registration fix, not a platform outage.
- 03
Segments and cost.
Each message reports its encoding and segment count, so volume rolls up into the segments you were actually billed for. A run that went Unicode and doubled its segments shows up here, not on the invoice.
- 04
Latency to delivery.
The time from submission to the delivery receipt, as a distribution rather than an average. Globally about 95% of messages confirm in under 2.5 seconds; the tail is where a degraded route announces itself.
Query the numbers from your own code.
The stats API takes a time range and a groupBy, and returns the rolled-up counts. Group by country and carrier to find the route that's underperforming, by sender to see which of your IDs a carrier trusts. The same aggregation backs the dashboard charts, so a number you screenshot matches a number you can pull on a schedule.
const { data, error } = await bird.sms.stats
.query({
from: "2026-06-01",
to: "2026-06-26",
groupBy: ["country", "carrier"],
metrics: ["sent", "delivered", "failed", "p95_latency_ms"],
})
.safe();
if (error) throw error;
console.log(data.rows[0]);
// → {
// country: "BR",
// carrier: "Vivo", // MCC/MNC 724/06
// sent: 48213,
// delivered: 47190,
// failed: 1023,
// p95_latency_ms: 2310,
// }Pull the timeline for one message.
Aggregates answer how a campaign did; a support ticket asks about one text. Pass a single message ID to the events endpoint and you get its whole life in order — queued, sent, the carrier delivery receipt or the failure, each stamped with a time and, when it failed, the carrier's own reason code.
const { data } = await bird.sms
.events("sms_4kT01Lq2m...")
.safe();
console.log(data.events);
// → [
// { type: "sms.queued", at: "2026-06-26T10:00:00.110Z" },
// { type: "sms.sent", at: "2026-06-26T10:00:00.640Z" },
// { type: "sms.delivered", at: "2026-06-26T10:00:02.300Z" },
// ]Slice the same sends however the question is shaped.
Every breakdown reads from the same delivery receipts; the groupBy just changes the lens.
| Dimension | What it tells you |
|---|---|
| Country | Where delivery holds and where a destination is dragging the global rate down. |
| Carrier (MCC/MNC) | Which operator inside a country is rejecting traffic, down to the network code. |
| Sender | How each of your sender IDs or numbers is trusted, since reputation is per-sender. |
| Time bucket | When a rate moved, so a drop lines up against a deploy, a registration change, or an outage. |
Go deeper in the docs.
Build your own store from the delivery webhooks, read the deliverability guide for what the failure codes mean, and reconcile counts against billing and usage.
The receipts come from the routing layer.
A delivery receipt is only as good as the path that produced it: routing chooses the carrier link each message takes and hands back the DLR these metrics are built from. If you run two-way numbers, inbound messages are counted here too, so a reply volume sits next to the delivery rate that earned it.
SMS analytics FAQ
Where do the delivery numbers come from?+
Can I break a report down by carrier?+
Do I have to poll the API, or can I stream events?+
Can I look up what happened to one specific message?+
The rest of the SMS platform
One API, one set of keys. Explore the other capabilities.
The metrics ship with the API that produces them.
Analytics isn't a separate product to buy. Send through the Bird SMS API and the delivery, failure, and latency reporting is already there, on infrastructure that carries about 40% of the world's commercial SMS.