Analytics

The Bluesky post metrics and account stats returned by the analytics endpoints, and the errors they report.

Read likes, replies, reposts, quotes and bookmarks for any Bluesky post, and follower counts for a connected account. No extra permission is needed beyond the App Password.

Metrics

FieldBluesky metricNotes
impressionsNoneAlways null
reachNoneAlways null
playsNoneAlways null
likeslikeCount
commentsreplyCount
sharesrepostCount + quoteCountReposts and quotes together
savesbookmarkCount
engagementCalculatedlikes + comments + shares + saves

A metric Bluesky does not return for a post is null, not 0.

Read Post Analytics

Pass the Onepostly post id, or the post's at:// URI plus accountId for a post published outside Onepostly. See Targeting Posts.

import { Configuration, AnalyticsApi } from "@onepostly/sdk";

const analyticsApi = new AnalyticsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await analyticsApi.getAnalytics({
  post: "1699f415-7fb6-43f4-9d2a-c447491f32a8",
  metrics: "views,reach,profile_views",
  period: "day",
});
console.log(response);
{
  "analytics": {
    "post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
    "status": "ready",
    "fetchedAt": "2026-08-25T10:00:00.000Z",
    "subjects": [
      {
        "scope": "destination",
        "subjectId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
        "platform": "bluesky",
        "externalPostId": "17895695668004550",
        "status": "ready",
        "metrics": {
          "impressions": null,
          "reach": null,
          "likes": 123,
          "comments": 12,
          "shares": 4,
          "saves": 2,
          "plays": null,
          "engagement": 0.14
        },
        "fetchedAt": "2026-08-25T10:00:00.000Z",
        "expiresAt": "2026-09-01T10:00:00.000Z",
        "error": null,
        "externalUrl": "https://bsky.app/profile/you/post/17895695668004550"
      }
    ]
  }
}

For day-by-day values, use the Daily Timeline.

Account Stats

Returns live counts for a connected account. On Bluesky, followerCount is the follower count, followingCount is the number of accounts it follows, and videoCount is the account's total number of posts. likesCount is always null.

import { Configuration, ConnectionsApi } from "@onepostly/sdk";

const connectionsApi = new ConnectionsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await connectionsApi.getConnectionStats({
  id: "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
  include: "messenger-profile,reviews",
  limit: 20,
});
console.log(response);
{
  "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
  "platform": "bluesky",
  "status": "ready",
  "stats": {
    "followerCount": 1234,
    "followingCount": 56,
    "likesCount": null,
    "videoCount": 12
  },
  "fetchedAt": "2026-08-25T10:00:00.000Z"
}

Recent Posts

GET /v1/connections/{id}/media lists the account's recent posts that carry images or video, with likes, replies and reposts for each. Reposts the account made are included, and the first page also includes posts the account published through Onepostly. views is always null. Pass the returned nextCursor as cursor to read the next page.

import { Configuration, ConnectionsApi } from "@onepostly/sdk";

const connectionsApi = new ConnectionsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await connectionsApi.listConnectionMedia({
  id: "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
  limit: 20,
  kind: "media",
  audioType: "music",
});
console.log(response);
{
  "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
  "platform": "bluesky",
  "items": [
    {
      "id": "7412345678901234567",
      "title": "My trip",
      "description": "Weekend recap #travel",
      "coverUrl": "https://cdn.onepostly.com/media/cover.jpg",
      "shareUrl": "https://www.tiktok.com/@you/video/7412345678901234567",
      "createdAt": "2026-08-20T10:00:00.000Z",
      "durationSec": 42,
      "metrics": {
        "likes": 123,
        "comments": 12,
        "shares": 4,
        "views": 4567
      }
    }
  ],
  "nextCursor": "20"
}

Analytics Status

A post that Bluesky has not indexed yet reports pending with POST_NOT_FOUND until its counts appear. A post that was deleted on Bluesky reports the same code. The meaning of every status is in Analytics Status.

Errors

Post analytics codes appear in subjects[].error.code. Account stats and recent posts return failures in the error envelope.

CodeCauseFix
NOT_PUBLISHEDThe Bluesky destination is not published yetRead analytics after post.platform.published
INVALID_EXTERNAL_IDThe post id is not an at:// URIPass the post's at:// URI
POST_NOT_FOUNDBluesky has not indexed the post yet, or it was deletedRead analytics again in a few minutes; if the code stays, check that the post still exists
ANALYTICS_PERMISSIONThe App Password was revoked or deletedCreate a new App Password and reconnect the account
TOKEN_INVALIDThe App Password was revoked or deleted (account stats and recent posts)Create a new App Password and reconnect the account
RATE_LIMITEDBluesky throttled the requestCall again later
PLATFORM_UNAVAILABLEBluesky was unavailableCall again later
ANALYTICS_FAILEDBluesky returned an error for this postRead error.message for the Bluesky reason
STATS_FAILEDBluesky did not return the account profileCall again; read the error message if it repeats
LIST_FAILEDBluesky did not return the account's postsCall again; read the error message if it repeats