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

# Read WhatsApp analytics

> Read message engagement, response operations, call outcomes and activity intervals, then export metrics to your collector.

Use `Client.analytics` to read aggregate WhatsApp activity for a team, project
or Number. The resource includes message engagement, response times, connection
problems and recorded call outcomes.

## Before you start

* Install SDK version `0.1.0-dev.20261004011426`, which includes the typed
  `analytics.get` and `analytics.metrics` methods.
* Use a server credential with `sessions:read`. Browser client tokens cannot
  read Platform analytics.
* Ask a team owner or admin to enable **Analytics** in the Console. Collection
  starts after enabling; earlier message activity is not reconstructed.

```bash theme={null}
npm install --save-exact @polymorfa/sdk@0.1.0-dev.20261004011426
```

The methods require an API environment that exposes Analytics. Installing the
SDK does not enable collection or grant access. See [installation](/sdks/typescript/installation)
for runtime requirements and [create a client](/sdks/typescript/client) for credentials.

## Read the last 24 hours

```typescript theme={null}
import { Client } from "@polymorfa/sdk";

const platform = new Client({
  credential: {
    type: "organizationApiKey",
    value: process.env.POLYMORFA_KEY!,
  },
  apiVersion: "2026-09-22",
});

const end = Date.now();
const { data } = await platform.analytics.get({
  start: end - 24 * 60 * 60 * 1_000,
  end,
});

if (!data.enabled) {
  console.log("Analytics is off");
} else {
  console.log(data.summary?.outgoingMessages);
  console.log(data.summary?.engagement.readRate);
  console.log(data.summary?.engagement.replyRate);
  console.log(data.summary?.averageBusinessResponseMs);
  console.log(data.summary?.calls.directions.inbound.missed);
}
```

`start` and `end` are Unix milliseconds. Omit them for the preceding 30 days.
The maximum range is 366 days. Recompute the timestamps on each read for a
rolling window.

`numbers` contains per-Number measurements; `series` contains message and
activity buckets; `callSeries` contains daily UTC call outcomes per Number.

## Filter a project or Number

An organization credential reads its own team. Add `projectId` to read one
project, or `sessionId` to read one Number:

```typescript theme={null}
const result = await platform.analytics.get({
  projectId: "22222222-2222-4222-8222-222222222222",
  sessionId: "33333333-3333-4333-8333-333333333333",
  start: end - 24 * 60 * 60 * 1_000,
  end,
});

console.log(result.data.numbers);
```

Both identifiers are record UUIDs. `sessionId` is the Number's record ID, not
its phone number or display name.

For a project credential, bind the client to that project:

```typescript theme={null}
const project = new Client({
  credential: { type: "projectToken", value: process.env.POLYMORFA_PROJECT_KEY! },
  projectId: "22222222-2222-4222-8222-222222222222",
  apiVersion: "2026-09-22",
});

const projectAnalytics = await project.analytics.get({ start: end - 86_400_000, end });
console.log(projectAnalytics.data.summary);
```

A project-bound client uses the project route and rejects a different
`projectId`. The API also enforces credential scope. Invalid UUIDs and date
ranges raise `PolymorfaValidationError` before a request. Handle authentication,
permission and service failures through [errors and retries](/sdks/typescript/errors).

## Keep coverage with the measurement

Read and reply rates use completed 24-hour direct conversations. A read rate
counts observed WhatsApp read receipts, not app opens. Missing receipts do not
prove a message was unread.

Preserve `null` rates and averages. A missing denominator or incomplete coverage
does not mean zero engagement. Check `measured`, `engagement.complete` and
`messageAnalysis.complete` alongside their values. Check `responseQueue.complete`
and `responseQueue.observedAt` before presenting the waiting-reply snapshot.

`messageAnalysis.segments` compares message type, text-length band and send source.
Use `conversationBreakdown.rows` to intersect those categories with recipient
country and linked-device count ranges. Missing country or count fields on older
rows stay Unknown. The linked count excludes the primary device. These shares
count conversations, not unique people, and do not establish causes of conversion.

`accountActivity` includes completed phone activity spans and quiet gaps, their
duration sums, sample counts and nullable averages. Series rows include sums
and counts for weighted comparisons. These signals do not measure phone power
state or verified online/offline time.

`calls` includes incoming and outgoing outcomes, observed pickup and talk times,
nullable quality measurements and missed-call follow-up windows. Call records
have their own retention policy. See [measurement definitions](/console/analytics)
before interpreting these fields.

## Export metrics

`analytics.metrics` returns metrics text in `data` and HTTP details in `metadata`:

```typescript theme={null}
const metrics = await platform.analytics.metrics({
  projectId: "22222222-2222-4222-8222-222222222222",
  windowHours: 24,
  segments: true,
  format: "openmetrics",
});

console.log(metrics.data);
console.log(metrics.metadata.status);
```

`windowHours` is an integer from 1 to 168, defaulting to 24. The window covers
completed UTC hours. `segments` defaults to `false`; `format` defaults to
`"prometheus"`. Both team and project clients support the method and the same
Number filter.

These are windowed gauges. Do not apply `rate()` or `increase()`. Disabled
Analytics returns enablement and window metadata without business metrics.

To collect continuously, use the [OpenTelemetry and Prometheus setup guide](/console/analytics-collectors).
To receive hourly JSON or NDJSON snapshots at your endpoint, create a drain in
**Project settings → Drains**; see [analytics drains](/console/analytics-collectors#send-hourly-json-snapshots).

## Recipient activity

`summary.recipientActivity` and each number's `recipientActivity` expose optional
hourly recipient observations. Use `recipientCountry`, `recipientDeviceCount` and
`deviceSource` to select the rows to aggregate. Message metadata is collected
jointly in `conversationBreakdown`; do not infer message-type intersections from
independent recipient activity totals.

Delivery, read, incoming messages and presence remain separate quantities.
Check coverage before calculating rates or timing means. See [device activity](/sdks/typescript/devices#read-recipient-device-activity)
and [business-hour definitions](/console/analytics#recipient-activity-and-business-hours).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.