How to Measure Bluesky Post Performance Without a Built-In Analytics Export
TL;DR: If Bluesky does not offer an analytics export, you can still measure post performance by using the per-post metrics TimeToPost records for posts it publishes, then tracking the same metrics in a simple sheet. Compare only published posts with matching IDs, statuses, timestamps, and metrics, and stop if the source data is incomplete.
What you can measure without a Bluesky analytics export
If Bluesky does not provide an export, you can still measure post performance by combining the per-post metrics TimeToPost records for posts it publishes with the results you can verify on each post. Keep the scope narrow. This is about post performance only, not every metric in the universe.
The practical move is simple: keep the post-level data TimeToPost gives you, add the visible results you can verify on the post itself, and compare like with like over time.
What TimeToPost can show for published posts
TimeToPost’s docs say the platform records metrics for posts it publishes, and the MCP server includes a get_post_metrics tool that reads per-post metrics such as impressions, likes, comments, clicks, and engagement rate. The REST API docs also document an engagement summary endpoint for aggregate likes, comments, shares, and views.
So the rule of thumb is:
- use per-post metrics when you compare individual Bluesky posts,
- use aggregate summaries when you need the bigger rollup,
- and only trust metrics for posts TimeToPost actually published.
That last bit matters. No publish, no published-post metrics.
Pull the post-level data you actually have
Collect the fields that give you a stable source of truth after export is unavailable. From the docs, the useful post fields are:
- post ID
- content
- status
- scheduledAt
- publishedAt
- platform or platforms
- media URLs, if relevant
- per-post metrics, where available
Also check:
- whether TimeToPost actually published the post
- whether the status is
published,partial,failed, or still scheduled - whether the timestamp fields are present and sane
- whether the metrics belong to the same post ID you are analyzing
That gives you one record per post, which is less glamorous than a mystery novel but far more useful.
If you want agent-readable post data and analytics tools without building raw API calls, use the TimeToPost MCP. It is the cleanest way to let a client read post data under your account permissions.
Build a simple manual tracking sheet
Turn the fields into one spreadsheet row per post. Keep the columns boring and consistent. Boring is good. Boring survives audits.
Suggested columns:
- post ID
- publish time
- content theme
- format
- platform
- status
- scheduledAt
- publishedAt
- likes
- comments
- shares
- views or impressions, whichever you have for that post
- clicks
- engagement rate
- notes
For content theme, use a short label like product update, question post, meme, or feature tip. For format, use something like plain text, image, link, or thread if that is relevant to the post.
Once the sheet is set up, compare posts by the same metric across the same platform and timing window. That is the whole trick. No export required, no spreadsheet wizardry required.
If you want a quick way to standardize the comparison once the raw counts are gathered, use the engagement rate calculator. It helps keep the math consistent when you compare posts by rate instead of raw totals.
Worked example: compare two Bluesky posts by the same metric set
This example is hypothetical.
Assume TimeToPost published both Bluesky posts, and you pulled the metrics from the per-post record:
| Field | Post A | Post B |
|---|---|---|
| post ID | post_101 | post_102 |
| status | published | published |
| scheduledAt | 2026-10-20T14:00:00Z | 2026-10-22T18:00:00Z |
| publishedAt | 2026-10-20T14:00:03Z | 2026-10-22T18:00:02Z |
| platform | Bluesky | Bluesky |
| content theme | product tip | behind-the-scenes |
| format | text + image | plain text |
| likes | 42 | 28 |
| comments | 6 | 9 |
| shares | 4 | 2 |
| views or impressions | 1,200 impressions | 980 impressions |
| clicks | 15 | 11 |
| engagement rate | 5.2% | 4.7% |
How to read it:
- Use the same metric across both posts, not likes on one post and impressions on the other.
- Here, Post A leads on likes, shares, impressions, clicks, and engagement rate.
- Post B leads on comments, which may matter if comments are your goal, but it does not beat Post A on the same metric set.
That is enough to make a decision without pretending the data is larger or cleaner than it is.
Use the result to decide what to test next
Once you compare the posts, turn the result into the next experiment:
- repeat the better-performing format
- repeat the better-performing publish time
- keep the same platform and metric set so the next comparison is still apples to apples, not apples to a very confident potato
If your best post was a text-plus-image post at a particular time, test that again with a similar theme. If the plain-text post got more comments, test whether that pattern holds across a few more posts before you crown it king.
When to stop and review the data instead of guessing
Stop and hand the analysis to a human when:
- the available metrics are incomplete
- the source data is insufficient
- the post was not published by TimeToPost
- the post ID does not match the metrics you are looking at
- the status is not clearly a published post
If the data cannot support the conclusion, do not invent one.
For reference, TimeToPost’s site says its MCP server exposes 76 tools for drafting, scheduling, publishing, approvals, analytics, AutoSEO and scheduler health. That is useful context if you want to keep this workflow inside the same system instead of stitching it together by hand.