Api Analytics
Analytics
Every route here is arithmetic over posts we have already stored. None of them calls a model, none of them costs anything, and all of them work with a read-only key.
GET /analytics/summary/
Best and worst performing posts, best and worst by engagement, total likes, post count, and when the history was last refreshed or analysed.
GET /analytics/best-time-to-post/
Ranked posting slots, best first:
{"status": "success", "data": {
"handle": "alice.bsky.social",
"weeks": 1,
"slots": [{"slot": "Tuesday 14:00", "score": 0.93, "post_count": 4}]
}}
| Parameter | Default | Notes |
|---|---|---|
weeks |
1 | How far back to look, 1–52 |
limit |
10 | How many slots, 1–50 |
detail |
top |
full returns the whole grid with the posts in each slot |
The parameter is detail, not format — format is reserved for content
negotiation and would return a 404.
Slots are bucketed in the account's own timezone, the same one GET /me/
reports, so this matches what you see in the web app.
GET /analytics/posts/
The stored post history, newest first.
| Parameter | Default | Notes |
|---|---|---|
limit |
50 | Capped at 100 |
offset |
0 | |
order |
posted_at |
or engagement, or likes |
Each post carries uri, text, posted_at, likes, reposts, replies,
quotes and engagement (the sum of the last four). The response includes
pagination with total, limit and offset.
GET /analytics/insights/
The stored profile insight blob, or {} if nothing has been generated yet. This
never triggers generation — if it is empty, the message tells you which route
would fill it.
POST /analytics/sync/
Refreshes the post history from Bluesky. Write scope, because it makes outbound calls on your behalf.
There is a fifteen-minute freshness window; send {"force": true} to bypass it.
Analytics read whatever was last synced, so call this first if you want
up-to-the-minute numbers.