> For the complete documentation index, see [llms.txt](https://docs.powerfulform.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.powerfulform.com/public-api/metrics.md).

# APIs for Metrics

Read form views, submissions and conversion rate — as a total, a daily series, or broken down by audience.

Three read-only endpoints, all requiring the `metrics:read` scope.

These numbers cannot be derived from the submission endpoints. A view is not a submission, and conversion rate only exists when you have both. They come from the same rollup tables that power the analytics screen in the app, so the API and the app never disagree.

## Shared parameters

<table><thead><tr><th width="180">Parameter</th><th width="110">Type</th><th>Notes</th></tr></thead><tbody><tr><td><code>start_date</code></td><td>date</td><td><code>YYYY-MM-DD</code>. Must not be after <code>end_date</code>.</td></tr><tr><td><code>end_date</code></td><td>date</td><td><code>YYYY-MM-DD</code>. Inclusive — the whole day is counted.</td></tr><tr><td><code>form_ids</code></td><td>string</td><td>Comma-separated form ids: <code>form_ids=10,11</code>. Omit for the whole store. Up to 100 ids.</td></tr></tbody></table>

{% hint style="info" %}
The parameter is `form_ids` here, but `form_id` on [`GET /submissions`](/public-api/submissions.md#query-parameters). Dates are interpreted in your **store's timezone**, unlike the UTC filters on submissions.
{% endhint %}

Dates are **required** on `/metrics/daily` and `/metrics/breakdown`. On `/metrics` they are optional, and leaving them off covers roughly the last six months.

## Summary

```
GET /metrics
```

Totals for the range, with the conversion rate worked out for you.

```bash
curl "https://app.powerfulform.com/api/public/v1/metrics?start_date=2026-09-01&end_date=2026-09-17" \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

```json
{
  "data": {
    "views": 1240,
    "views_by_device": { "desktop": 812, "mobile": 428 },
    "submissions": 87,
    "conversion_rate": 0.0702
  }
}
```

<table><thead><tr><th width="220">Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>views</code></td><td>Total form views in the range.</td></tr><tr><td><code>views_by_device</code></td><td>Views split into <code>desktop</code>, <code>mobile</code> and <code>other</code>. A device with no views is simply absent.</td></tr><tr><td><code>submissions</code></td><td>Submissions received in the range.</td></tr><tr><td><code>conversion_rate</code></td><td>Submissions ÷ views, to four decimal places. <code>null</code> when there were no views.</td></tr></tbody></table>

`0.0702` is 7.02%. It is calculated server-side so that every integration reporting on the same store reports the same figure.

## Daily series

```
GET /metrics/daily
```

One row per day, plus the same length of time immediately before the range so you can show a change.

```bash
curl "https://app.powerfulform.com/api/public/v1/metrics/daily?start_date=2026-09-11&end_date=2026-09-17" \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

```json
{
  "data": {
    "days": [
      { "day": "2026-09-11", "view": 180, "submission": 12, "unique_visitors": 164, "unique_respondents": 12 },
      { "day": "2026-09-12", "view": 205, "submission": 15, "unique_visitors": 188, "unique_respondents": 14 }
    ],
    "previous_period": [
      { "day": "2026-09-04", "view": 151, "submission": 9, "unique_visitors": 140, "unique_respondents": 9 }
    ]
  }
}
```

<table><thead><tr><th width="220">Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>day</code></td><td>The date, in your store's timezone.</td></tr><tr><td><code>view</code></td><td>Form views that day.</td></tr><tr><td><code>submission</code></td><td>Submissions that day.</td></tr><tr><td><code>unique_visitors</code></td><td>Distinct visitors who saw a form.</td></tr><tr><td><code>unique_respondents</code></td><td>Distinct visitors who submitted one.</td></tr></tbody></table>

`previous_period` covers the stretch of the same length ending where your range starts — ask for 7 days and you get the 7 days before them, ready to compare without a second request.

{% hint style="info" %}
Days with no activity are not padded in. If you are drawing a chart, fill the gaps yourself rather than assuming one row per calendar day.
{% endhint %}

## Breakdown

```
GET /metrics/breakdown
```

The same range split by audience dimension.

```bash
curl "https://app.powerfulform.com/api/public/v1/metrics/breakdown?start_date=2026-09-01&end_date=2026-09-17" \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

```json
{
  "data": {
    "countries":    [ { "country": "VN", "total": 300 }, { "country": "US", "total": 142 } ],
    "device_types": [ { "device_type": "desktop", "total": 812 } ],
    "browsers":     [ { "browser": "Chrome", "total": 690 } ],
    "platforms":    [ { "platform": "Windows", "total": 402 } ],
    "time_zones":   [ { "time_zone": "Asia/Ho_Chi_Minh", "total": 288 } ],
    "utm_sources":  [ { "utm_source": "facebook", "total": 120 } ],
    "locales":      [ { "locale": "en", "total": 1105 } ]
  }
}
```

Seven lists come back — `browsers`, `platforms`, `device_types`, `time_zones`, `countries`, `utm_sources`, `locales`. Each entry names the value and how many tracked events fall into it, sorted highest first. A list with nothing recorded comes back empty.

An entry whose value was never captured has `null` in the name field — an unknown country, or traffic that arrived without a UTM tag.

## Errors

<table><thead><tr><th width="120">Status</th><th width="230">Code</th><th>Cause</th></tr></thead><tbody><tr><td>403</td><td><code>insufficient_scope</code></td><td>The key is missing <code>metrics:read</code>.</td></tr><tr><td>422</td><td><code>validation_failed</code></td><td>A missing date on <code>/daily</code> or <code>/breakdown</code>, a <code>start_date</code> after <code>end_date</code>, or more than 100 entries in <code>form_ids</code>.</td></tr><tr><td>429</td><td><code>rate_limited</code></td><td>The <strong>read</strong> bucket is spent — 120 per minute.</td></tr></tbody></table>

<br>

## Next steps

* [Form insights](/submissions/form-insights.md) — the same numbers on screen, in the app.
* [Submissions](/public-api/submissions.md) — the records behind the submission counts.
* [Errors](/public-api/errors.md) — how to handle each status.
