Skip to content

Commit aa62d29

Browse files
AzymAzym
authored andcommitted
docs(analytics): per-platform metrics matrix in the guides and READMEs
The SDK/openapi surfaces already carried the new support fields; the prose did not, and the top-level README actively claimed analytics tracks "impressions, likes, comments, shares, and engagement across all platforms" — the exact false statement this work exists to correct. X reports no reach, saves, clicks or video views; Bluesky and Mastodon report no impressions; Pinterest reports no reach; YouTube reports no shares or reach; five platforms plus LinkedIn personal profiles report nothing at all. guides/platforms.md gains a "Metrics by Platform" section: the full support matrix, what each engagement response field means, the Facebook read_insights third state, and the two other legitimate zeroes (the 6-hourly snapshot not having run, and X's billed opt-in-per-channel sync). The four READMEs now point at it rather than repeating a partial version. No version bump: prose only, no code or contract change in this commit.
1 parent a43efd4 commit aa62d29

5 files changed

Lines changed: 68 additions & 4 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ More examples in [`examples/`](examples/) — including [Python automation scrip
218218
- **Scheduling** — Schedule posts for any future time with timezone support, or let queue slots pick optimal times
219219
- **Media uploads** — Images (JPEG, PNG, WebP, GIF) and videos (MP4, MOV, WebM) up to 100 MB
220220
- **Recurring schedules** — Repeat posts daily, weekly, biweekly, or monthly at a set time of day
221-
- **Analytics** — Track impressions, likes, comments, shares, and engagement across all platforms
221+
- **Analytics** — Track impressions, likes, comments, shares, and engagement. Each platform reports a different subset of metrics, and the response says which (`supportedMetrics` / `supportedTotals`) so a `0` is never mistaken for a measurement — see [Metrics by Platform](guides/platforms.md#metrics-by-platform)
222222
- **Labels** — Organize posts and media with color-coded labels
223223
- **Bulk operations** — Delete or retry multiple posts in a single request
224224
- **Threads** — Multi-part thread posts for X, Threads, Bluesky, and Mastodon

guides/platforms.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,70 @@ When publishing to multiple platforms, you may want different post types per pla
631631

632632
If no override is set for a platform, BulkPublish selects the default post type based on the attached media.
633633

634+
## Metrics by Platform
635+
636+
Every platform reports a **different subset** of the metric columns, and the
637+
columns that a platform has no API for are stored as `0`. That makes "not
638+
reported" and "measured zero" identical on the wire unless you read the support
639+
fields — so **never present a `0` as a measurement without checking them first.**
640+
641+
`GET /api/posts/{id}/metrics` returns, per platform entry:
642+
643+
- `metricsSupported``false` when the platform exposes no per-post statistics API at all.
644+
- `supportedMetrics` — the metric keys that platform can populate. Anything absent is a stored `0`.
645+
646+
`GET /api/analytics/engagement` returns the same information for a date range:
647+
648+
| Field | Meaning |
649+
|---|---|
650+
| `metricSupport` | platform → the metric keys it can report |
651+
| `supportedTotals` | union across the window; a `total*` field whose key is missing here should render as "not available", never `0` |
652+
| `partialTotals` | supported key → platforms in the window that do **not** report it, so the total covers fewer posts than it appears to |
653+
| `conditionalMetrics` | supported but permission-gated (see the Facebook note below) |
654+
| `unmeasuredPlatforms` | platforms present that report nothing at all |
655+
| `metricsDisabledChannels` | channels whose metrics sync is switched off (see X below) |
656+
657+
### Support matrix
658+
659+
| Platform | Reports | Never reports |
660+
|---|---|---|
661+
| X | impressions, likes, comments, shares | reach, saves, clicks, video views |
662+
| YouTube | impressions, video views, likes, comments | reach, shares, saves, clicks |
663+
| Instagram | impressions, reach, likes, comments, shares, saves | clicks, video views |
664+
| Facebook | likes, comments, shares + impressions, reach, clicks¹ | saves, video views |
665+
| LinkedIn (company pages) | impressions, reach, likes, comments, shares, clicks | saves, video views |
666+
| TikTok | impressions, video views, likes, comments, shares | reach, saves, clicks |
667+
| Threads | impressions, likes, comments, shares | reach, saves, clicks, video views |
668+
| Pinterest | impressions, clicks, saves, likes, comments, video views | reach |
669+
| Bluesky | likes, comments, shares, saves (bookmarks) | impressions, reach, clicks, video views |
670+
| Mastodon | likes, comments, shares | everything else |
671+
| Google Business, Reddit, Discord, Telegram, Tumblr | *nothing* ||
672+
| LinkedIn personal profiles | *nothing* ||
673+
674+
¹ Facebook's `impressions`, `reach` and `clicks` come from the Page Insights
675+
edge and require the `read_insights` permission. Without it they stay `0` even
676+
though the metric is listed as supported — that is "may not be readable", a
677+
third state distinct from both a dash and a trustworthy figure. These are the
678+
keys reported in `conditionalMetrics`.
679+
680+
`engagementRate` is derived as engagements ÷ impressions, so it exists exactly
681+
where `impressions` does — it is permanently `0` for Bluesky and Mastodon.
682+
683+
**LinkedIn is account-type-gated.** Share statistics are exposed only for
684+
**organization** pages. A personal/profile channel reports nothing, which is why
685+
LinkedIn can appear in both the matrix above and in `unmeasuredPlatforms`
686+
depending on the channel.
687+
688+
### Two other reasons a figure is legitimately 0
689+
690+
- **The snapshot has not run.** All figures come from a stored snapshot refreshed
691+
every 6 hours (or on demand via `POST /api/analytics/refresh`) — never a live
692+
read. A just-published post appears immediately with zeros.
693+
- **Metrics sync is switched off for the channel.** X bills every read, so its
694+
per-post sync is **opt-in per channel** and runs at most once every 7 days.
695+
Until it is enabled, every X figure stays `0` and `POST /api/analytics/refresh`
696+
cannot change that. Affected channels are listed in `metricsDisabledChannels`.
697+
634698
## Character Limits
635699

636700
Each platform enforces its own character limit on the `content` field:

mcp-server/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ Once deployed, add it to **claude.ai → Settings → Connectors → Add custom
129129
| `retry_post` | Retry a failed post |
130130
| `approve_post` | Approve a post awaiting team approval (roles with post:approve) |
131131
| `reject_post` | Reject a pending post back to draft, with an optional reason |
132-
| `get_post_metrics` | Get engagement metrics (impressions, likes, comments, shares) |
132+
| `get_post_metrics` | Get engagement metrics (impressions, likes, comments, shares). Each platform entry carries `supportedMetrics` — a key not in that list is a stored `0`, not a measurement |
133133
| `publish_story` | Publish as a story to Facebook or Instagram |
134134
| `bulk_posts` | Bulk delete or retry multiple posts |
135135
| `get_queue_slot` | Get the next optimal time slot for a channel |

node/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ BulkPublish is designed for programmatic social media management — no browser
5656
- **AI agents** — Use with Claude (MCP server), GPT (function calling), LangChain, or any LLM with tool use
5757
- **Server-side scripts** — Cron jobs, CI/CD pipelines, content syndication
5858
- **Bulk operations** — Iterate over data and schedule hundreds of posts programmatically
59-
- **Analytics pipelines** — Pull engagement data into your own dashboards or AI analysis
59+
- **Analytics pipelines** — Pull engagement data into your own dashboards or AI analysis (check `supportedMetrics` before treating a `0` as a measurement — platforms report different subsets)
6060

6161
## Full TypeScript Types
6262

python/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ BulkPublish is designed for programmatic social media management — no browser
5656
- **AI agents** — Use with Claude (MCP server), GPT (function calling), LangChain, or any LLM that supports tool use
5757
- **Cron jobs & scripts** — Schedule content pipelines, RSS-to-social, blog-to-social workflows
5858
- **Bulk operations** — Upload a CSV, iterate, and schedule hundreds of posts programmatically
59-
- **Analytics extraction** — Pull engagement data into your own dashboards or AI analysis pipelines
59+
- **Analytics extraction** — Pull engagement data into your own dashboards or AI analysis pipelines (check `supportedMetrics` before treating a `0` as a measurement — platforms report different subsets)
6060

6161
## Async Support
6262

0 commit comments

Comments
 (0)