> ## Documentation Index
> Fetch the complete documentation index at: https://api.smartlead.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# How Analytics Metrics Are Calculated

> The shared rules behind every Global Analytics endpoint — date boundaries, time axes, unique vs raw counts, and rate formulas

This page explains the rules that apply across **all** Global Analytics endpoints. Each endpoint page also has its own per-field breakdown, but the concepts below are the same everywhere — read this once and the individual endpoints make a lot more sense.

## Two kinds of numbers

The fields in an analytics response are not all the same kind of metric. This is the single most important thing to understand, and it's the usual cause of "the numbers don't add up".

* **Raw event counts** — `sent`, `opened`, `replied`, `bounced`, `unsubscribed`. These count events. They are **additive**: the value for a date range equals the sum of the per-day values.
* **Unique counts** — `unique_lead_count`, `unique_open_count`, `positive_replied`. These count **distinct leads** over the requested range (`COUNT(DISTINCT lead)`, deduplicated per campaign by email address). They are **not additive**.

A lead emailed on two different days counts **once** in a range query, but once in **each** single-day query. So if you pull each day separately and add them up, the unique counts (and every rate derived from them) come out inflated.

<Warning>
  You cannot reconstruct a multi-day range by summing per-day responses. The raw counts will match, but the unique counts and all rates will not. To get an accurate figure for any period, **query that period directly** rather than summing individual days.
</Warning>

## Date range behaviour

`start_date` and `end_date` are **inclusive on both ends**. Internally the window runs from `start_date 00:00:00` to `end_date 23:59:59`:

```text theme={null}
sent_time >= 'start_date 00:00:00' AND sent_time <= 'end_date 23:59:59'
```

* Passing the **same date** for start and end returns that one full day (`00:00:00`–`23:59:59`), not an empty result.
* When a `timezone` is supplied, the day boundaries are calculated in that timezone; otherwise UTC is used.

## Time axes: send date vs reply date

Every record is anchored to a point in time. Endpoints differ in **which timestamp** they filter and group by:

* **Send date** (`sent_time`) — the day the email went out. This is the axis for `sent`, `opened`, `replied`, and `bounced`. The `*-by-sent-time` endpoints make this explicit, including for positive replies.
* **Reply date** (`reply_time`) — the day the reply came in. This is the default axis for **positive replies** on the `overall-stats-v2` tile and `day-wise-positive-reply-stats` (see [How positive replies are counted](#how-positive-replies-are-counted) below).
* **Event date** — some day-wise breakdowns bucket opens by open time and replies by reply time, so each metric lands on the day the event happened.

When comparing two endpoints that look similar, check which axis each uses — a reply that arrives days after the send lands on a different day depending on the axis.

## Rate formulas

All rates are percentages computed against the **unique** counts, not raw sends:

| Rate                  | Formula                                                                                                                              |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `open_rate`           | `unique_open_count / unique_lead_count`                                                                                              |
| `reply_rate`          | `replied / unique_open_count` — falls back to `unique_lead_count` when open tracking is off (plain-text sends, or tracking disabled) |
| `positive_reply_rate` | `positive_replied / replied`                                                                                                         |
| `bounce_rate`         | `bounced / unique_lead_count`                                                                                                        |
| `client_health`       | `positive_replied / unique_lead_count`                                                                                               |

<Note>
  `bounce_rate` is calculated per **unique lead** (`bounced / unique_lead_count`), not per email sent. If you want the deliverability-style figure (`bounced / sent`), the raw `bounced` and `sent` counts are both in the response and you can compute it yourself.
</Note>

## How positive replies are counted

A **positive reply** is a lead whose lead-category sentiment is **positive** (`lead_categories.sentiment_type = 'positive'`), tied to a **genuine reply** — one that actually replied, is not marked ignored, and did not bounce.

Three things vary by endpoint, and getting them mixed up is the usual reason two positive-reply numbers don't agree:

* **Reply-date vs send-date attribution.** Most surfaces (the `overall-stats-v2` tile and `day-wise-positive-reply-stats`) attribute a positive to the **date the reply was received**. The `*-by-sent-time` variant instead attributes it to the **date the email was sent**. A reply that arrives days after the send lands on a different day depending on which you use.
* **Unique leads vs response events.** Most positive counts are **distinct leads** (a lead is counted once no matter how many times it replied). `campaign/response-stats` is the exception — it counts **response events**, so a lead replying twice counts twice. This is why its `total_positive_response` can be *higher* than the tile's `positive_replied`.
* **Deduplication across the range.** Distinct-lead counts are deduplicated over the whole requested range, so they are **not additive** — summing single-day calls over-counts. Always query the exact date range you want.

<Note>
  The lead category is **mutable**: re-categorising a lead (marking it positive, or changing it later) changes historical counts, because the number reflects each lead's *current* category, not what it was on the reply date.
</Note>

See each endpoint's own page for its exact attribution — they are deliberately not all the same.
