# Analytics API

Read post metrics, follower growth and account insights for every connected social account, including posts made outside Zernio, in one response shape.

import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

The Analytics API returns how posts and accounts perform: impressions, reach, likes, comments, shares, views and follower growth. One response shape covers every platform, and it includes posts made outside Zernio.

## What you can build

- **A performance dashboard per customer.** `GET /v1/analytics/dashboard` returns totals, a daily series and top posts for one profile in one call ([multi-tenant analytics](/multi-tenant/analytics)).
- **Top post reports.** `GET /v1/analytics` with `sortBy` ranks posts by engagement, views or any other metric over a date range.
- **Follower growth charts.** `GET /v1/accounts/follower-stats` returns each account's follower count per day, week or month.
- **Smarter scheduling.** `GET /v1/analytics/best-time` returns the days and hours your posts do best, to set [queue](/products/scheduler) slots.
- **Warehouse sync.** The `analytics.synced` webhook fires after each sync, and `GET /v1/analytics/delta` returns only what changed since your cursor.

## Platforms

<ProductPlatforms product="analytics" />

Each network exposes different metrics, so what you get differs by platform. Each platform's analytics page has the full list.

| Platform | Post metrics | Account-level reads |
|---|---|---|
| <PlatformName slug="instagram" page="analytics" /> | Impressions, reach, likes, comments, shares, saves, views | Account insights, demographics, follower history, online followers |
| <PlatformName slug="facebook" page="analytics" /> | Impressions, likes, comments, shares, clicks, views | Page insights, demographics, post earnings |
| <PlatformName slug="linkedin" page="analytics" /> | Impressions, reach, likes, comments, shares, plus clicks or saves by account type | Organization analytics, demographics |
| <PlatformName slug="tiktok" page="analytics" /> | Likes, comments, shares, views; more on Business app connections | Account insights, demographics |
| <PlatformName slug="youtube" page="analytics" /> | Likes, comments, views | Channel insights, daily views, demographics, video retention |
| <PlatformName slug="twitter" page="analytics" /> | Impressions, likes, comments, shares, saves, clicks; views on media posts | |
| <PlatformName slug="pinterest" page="analytics" /> | Impressions, saves, clicks | Account insights |
| <PlatformName slug="threads" page="analytics" /> | Likes, comments, shares, views | |
| <PlatformName slug="bluesky" page="analytics" /> | Likes, comments, reposts | |
| <PlatformName slug="snapchat" page="analytics" /> | Views, reach, shares | |
| <PlatformName slug="reddit" page="analytics" /> | Upvotes and comments, frozen at the last sync while Reddit blocks API access | |
| <PlatformName slug="google-business" page="analytics" /> | None: Google retired per-post insights | Location performance, search keywords |
| <PlatformName slug="google-analytics" page="reports" /> | Not a post platform | GA4 reports and realtime reports for a website |

Ad spend and results are in the [Ads API](/products/ads).

## How it works

Zernio syncs metrics from each platform in the background, roughly every hour per account, and stores them. Your requests read that store, so they are fast and do not spend the platform's quota.

- **Posts.** `GET /v1/analytics` lists posts with their metrics. `source` picks posts made through Zernio (`late`), posts made elsewhere (`external`) or both (`all`, the default).
- **One post.** Send `postId` with a Zernio post id, an external post id or the platform's own id.
- **Accounts.** Follower counts refresh once a day. Platform-specific reads, such as `GET /v1/analytics/instagram/account-insights`, ask the platform directly.
- **Scoping.** Filter by `profileId`, `accountId` or `platform`, so each of your customers sees only their own numbers.

Analytics needs the Analytics add-on on legacy plans. Usage-based plans include it.

## Your first request

You need an API key and a profile id. This lists the profile's posts since October 1 with their metrics.

<Tabs items={['Node.js', 'Python', 'curl']}>
<Tab value="Node.js">
```typescript
import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data } = await zernio.analytics.getAnalytics({
  query: {
    profileId: '66a1f0c2a4b9d3e8f1a2b3c4',
    fromDate: '2026-10-01',
    limit: 50
  }
});

console.log(data.posts[0].analytics);
```
</Tab>
<Tab value="Python">
```python
from zernio import Zernio

client = Zernio()

analytics = client.analytics.get_analytics(
    profile_id="66a1f0c2a4b9d3e8f1a2b3c4",
    from_date="2026-10-01",
    limit=50,
)

print(analytics["posts"][0]["analytics"])
```
</Tab>
<Tab value="curl">
```bash
curl "https://zernio.com/api/v1/analytics?profileId=66a1f0c2a4b9d3e8f1a2b3c4&fromDate=2026-10-01&limit=50" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"
```
</Tab>
</Tabs>

Response (`200`):

```json
{
  "overview": {
    "totalPosts": 156,
    "publishedPosts": 156,
    "scheduledPosts": 0,
    "lastSync": "2026-11-10T08:30:00Z"
  },
  "posts": [
    {
      "_id": "65f1c0a9e2b5af0012ab34cd",
      "content": "Check out our new product launch!",
      "publishedAt": "2026-11-01T10:00:05Z",
      "platform": "instagram",
      "platformPostUrl": "https://www.instagram.com/reel/ABC123xyz/",
      "isExternal": true,
      "analytics": {
        "impressions": 15420,
        "reach": 12350,
        "likes": 342,
        "comments": 28,
        "shares": 45,
        "saves": 0,
        "clicks": 189,
        "views": 0,
        "engagementRate": 2.78,
        "lastUpdated": "2026-11-10T08:30:00Z"
      }
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 156 }
}
```

Every post has the same `analytics` fields. A metric the platform does not report reads `0`. `fromDate` defaults to 90 days ago.

## Examples

### Top posts of the last 30 days

Sort by `engagement` and keep the first 10. `sortBy` also takes `impressions`, `reach`, `views`, `likes` and other metrics.

<Tabs items={['Node.js', 'Python', 'curl']}>
<Tab value="Node.js">
```typescript
const { data } = await zernio.analytics.getAnalytics({
  query: {
    profileId: '66a1f0c2a4b9d3e8f1a2b3c4',
    fromDate: '2026-10-11',
    toDate: '2026-11-10',
    sortBy: 'engagement',
    order: 'desc',
    limit: 10
  }
});

for (const post of data.posts) {
  console.log(post.platform, post.analytics.engagementRate, post.platformPostUrl);
}
```
</Tab>
<Tab value="Python">
```python
top = client.analytics.get_analytics(
    profile_id="66a1f0c2a4b9d3e8f1a2b3c4",
    from_date="2026-10-11",
    to_date="2026-11-10",
    sort_by="engagement",
    order="desc",
    limit=10,
)

for post in top["posts"]:
    print(post["platform"], post["analytics"]["engagementRate"], post["platformPostUrl"])
```
</Tab>
<Tab value="curl">
```bash
curl "https://zernio.com/api/v1/analytics?profileId=66a1f0c2a4b9d3e8f1a2b3c4&fromDate=2026-10-11&toDate=2026-11-10&sortBy=engagement&order=desc&limit=10" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"
```
</Tab>
</Tabs>

### Follower growth for one account

`GET /v1/accounts/follower-stats` returns the current count, the growth over the range and one data point per period. Up to 25 accounts per request.

<Tabs items={['Node.js', 'Python', 'curl']}>
<Tab value="Node.js">
```typescript
const { data } = await zernio.accounts.getFollowerStats({
  query: {
    accountIds: '66b2e19d8c3f5a7e9d0b1c2d',
    fromDate: '2026-08-01',
    toDate: '2026-11-10',
    granularity: 'weekly'
  }
});

console.log(data.accounts[0].growth, data.accounts[0].growthPercentage);
```
</Tab>
<Tab value="Python">
```python
stats = client.accounts.get_follower_stats(
    account_ids="66b2e19d8c3f5a7e9d0b1c2d",
    from_date="2026-08-01",
    to_date="2026-11-10",
    granularity="weekly",
)

print(stats["accounts"][0]["growth"], stats["accounts"][0]["growthPercentage"])
```
</Tab>
<Tab value="curl">
```bash
curl "https://zernio.com/api/v1/accounts/follower-stats?accountIds=66b2e19d8c3f5a7e9d0b1c2d&fromDate=2026-08-01&toDate=2026-11-10&granularity=weekly" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"
```
</Tab>
</Tabs>

Response (`200`):

```json
{
  "accounts": [
    {
      "_id": "66b2e19d8c3f5a7e9d0b1c2d",
      "platform": "twitter",
      "username": "@acme",
      "currentFollowers": 1250,
      "growth": 50,
      "growthPercentage": 4.17,
      "dataPoints": 15
    }
  ],
  "stats": {
    "66b2e19d8c3f5a7e9d0b1c2d": [
      { "date": "2026-08-03", "followers": 1200 },
      { "date": "2026-11-09", "followers": 1250 }
    ]
  },
  "granularity": "weekly"
}
```

## How it behaves

- **Cached for an hour.** Post analytics are cached for 60 minutes, and a stale read starts a background refresh.
- **At most 366 days per request** on `GET /v1/analytics`, and one year on follower stats.
- **A per-second rate limit.** Analytics endpoints use a 1-second window, and stored-analytics reads share a team cap ([rate limits](/guides/rate-limits#per-second-limits-for-analytics-endpoints)).
- **LinkedIn personal accounts** report only posts published through Zernio. Company pages report every post.

## If it fails

| Error | Cause | Fix |
|---|---|---|
| `402` on `GET /v1/analytics` | No analytics access | Add the Analytics add-on, or move to a usage-based plan |
| `403` on `GET /v1/accounts/follower-stats` | No analytics access | The same fix |
| `202` on one post | Metrics are still syncing | Retry later |
| `424` on one post | The post failed on every platform, so it has no metrics | Nothing to read |
| `429` | A rate limit or the team cap was hit | Wait for `Retry-After`, then retry |

## Related

- [Get post analytics reference](/analytics/get-analytics)
- [Follower stats reference](/analytics/get-follower-stats)
- [Multi-tenant analytics](/multi-tenant/analytics)
- [analytics.synced webhook](/webhooks/social/analytics-synced)
- [Rate limits](/guides/rate-limits)
- [Posting API](/products/posting)