Guides
Analytics
Read how your posts performed, per post, or across every network at once, in one normalised response. Same metric names everywhere, so you (or an agent) can compare platforms without special-casing each one.
Per-post analytics
Fetch the metrics for a single post across all the accounts it went to:
curl https://api.postlake.dev/v1/posts/post_a1b2c3/analytics \
-H "Authorization: Bearer YOUR_API_KEY"The response includes measuredAt and one targets[] entry per destination. Each target has reports[], the metric names its adapter can expose, and metrics. A null metrics value means PostLake could not read that target's insights; it does not mean the post had zero engagement. In the dashboard, open a published post to see these figures beside its content. That view refreshes while open and also has a manual Refresh button. Networks may update their counts later than PostLake checks them.
Cross-platform analytics
Roll up performance across every connected account over a period (this is the differentiator. One call, every network):
curl "https://api.postlake.dev/v1/analytics?period=30d" \
-H "Authorization: Bearer YOUR_API_KEY"Reports cover all collected publishing destinations, without a recent-50-post sample or live provider calls. Totals, charts, comparisons and breakdowns use the same mode and filters.
mode=period(default): positive counter growth observed during the selected UTC dates, including older content.mode=content: latest lifetime counters for destinations published during those dates, not activity received in that period.period=7d,30dor90d: inclusive UTC calendar-day windows ending today.from=2026-09-01&to=2026-09-30: inclusive UTC dates, maximum 365 days.profile: profile username, using its current channels.channel: social account ID.network: platform name.agent: stable creator client ID.origin: recorded interface (dashboard,apioragent). Historical attribution is not guessed. Account-wide supplements are omitted with either identity filter.
Shared posts contribute only matching destinations. Moving a channel changes current profile attribution. posts counts distinct tracked posts with collected readings published in the range, not every published post. topPosts ranks up to 20 destinations across the complete matching population; one shared post can appear more than once. Rankings do not cap totals.
Refresh without waiting
POST /v1/analytics/refresh queues collection and returns immediately. GET /v1/analytics/refresh reads queued, running, complete or failed, with posts checked and errors. Active jobs are reused; new starts have a five-minute cooldown. Complete does not mean every provider returned every field. Previous valid readings survive provider failures.
Due work is checked every 15 minutes. Content up to seven days old is eligible every 15 minutes, 8-28 days hourly, 29-90 days daily, and older content weekly. Refresh respects eligibility and provider cooldowns. Reports have a 15-second cache, invalidated by job progress. The dashboard updates during collection without losing your filters. Provider reporting can lag.
MCP: call get_analytics with the same filters and refresh: true, then call again for progress. SDK: client.analytics.get(), client.analytics.refresh() and client.analytics.refreshStatus().
Engagement rate and metric definitions
Views are the network's reported view counter. Impressions count displays where a network exposes that metric. Neither is a unique-person count, and a video view is not interchangeable with an impression. PostLake does not estimate impressions from views or interactions.
Engagement is likes or reactions + comments or replies + shares, reposts or quotes + saves + clicks, using the counters available from each network. Missing counters are not measured zero. Clicks are not necessarily outbound link clicks. One person can perform several actions.
Per-network engagement rate is engagement divided by the audience counter, multiplied by 100. PostLake uses views when reported, otherwise impressions. The denominator is not followers or reach. Without a positive usable audience count, the rate is unavailable, not zero.
Across networks, PostLake divides the summed eligible engagement by the summed audience counts, then multiplies by 100. It does not average network percentages. Networks with no usable audience count contribute to neither side of the rate, although their measured engagement can still appear in the engagement total.
For example, 100 actions on 1,000 TikTok views and 10 actions on 200 Pinterest impressions give (100 + 10) / (1,000 + 200) × 100 = 9.2%, rounded to one decimal. This is a blended action rate across different measurement rules, not a unique-person rate or the native rate shown by either platform. Multiple actions per exposure can produce rates above 100%.
The selected mode applies to both sides: Period mode uses observed activity increments; Content mode uses lifetime readings for content published in the chosen dates. Different networks expose different actions, so compare trends within a network as well as the blended headline. Account-wide insights are never added to post totals.
The dashboard's metric information controls explain these definitions. Post Detail keeps network-specific impressions separate and labels unavailable readings N/A. A reported zero remains 0. API clients and agents can read the same rules through GET /v1/analytics/methodology.
Reconciliation methodology
- Identity includes workspace, PostLake post, connected channel and remote object ID. Channels on the same network do not collide.
- A first reading within 24 hours of publication counts from zero; a later first reading establishes a baseline.
- Period activity counts growth above the previous highest counter. Downward corrections stay visible in lifetime readings; recovery is not counted twice.
- Growth across gaps belongs to its observation date. Missing event dates and unidentified counter resets cannot be reconstructed.
- Previous periods use adjacent equal-length UTC date windows with the same filters. Today can be incomplete. Null means no usable observations, not zero.
- Account insights in
byChannel.accountare separate. Native extras are supplemental lifetime counters, labellednativeExtrasBasis: latest_lifetime, not period activity. - Raw evidence retains the latest daily observation. Atomic updates maintain rollups; duplicate timestamps and older readings cannot inflate them.
- Legacy readings migrate only when one destination is identifiable. Ambiguous evidence remains retained, not multiplied.
Call GET /v1/analytics/methodology for machine-readable definitions.
The metric shape
Every platform maps to the same Metrics object, so a chart or an agent reads one set of fields regardless of source:
| Field | Meaning |
|---|---|
impressions | Times the post was shown. |
views | Views or watches, where reported. |
reach | Unique accounts that saw it. |
likes | Likes / reactions. |
comments | Comments / replies. |
shares | Reposts / shares. |
saves | Saves / bookmarks. |
clicks | Link / profile clicks. |
followers | Follower count / growth for the account. |
Not every network exposes every metric. Target reports[] lists adapter capabilities; metrics.reported lists counters actually returned by that reading, including measured zero. An absent field is not measured zero. Incomplete readings preserve earlier valid lifetime values. Older evidence without reported has unknown coverage. Channel fieldCoverage counts fields present in latest observations, scoped by observation date in Period mode or publication date in Content mode, not historical daily coverage. Channel metadata and avatar bytes refresh in bounded background work and preserve previous valid images on failures. See the analytics methodology for machine-readable reconciliation rules.