Bluesky post analyzer

Enter a Bluesky handle and this reads up to 300 items from its public feed, drops the reposts, and works out which of its own posts travelled and what those posts had in common. Length, media, alt text, links, hashtags, mentions, quotes, threads and time of day, each compared against the account’s own median post.

A Bluesky handle is a domain, so alice.bsky.social rather than alice. A bare name is completed to .bsky.social, and a pasted bsky.app profile link or a did:plc: identifier both work.

Try:

The 300-grapheme limit, and why your character counter is wrong

Bluesky caps a post at 300 graphemes and 3000 bytes, per the app.bsky.feed.post lexicon. A grapheme is what a reader would call one character: one letter, one emoji, one accented glyph. It is not what String.length returns in JavaScript, which counts UTF-16 code units.

The gap is large enough to break things. The family emoji is a single grapheme and eleven JavaScript characters, so a composer counting text.length shows 289 of 300 used for a post that is really at 279, and refuses input that Bluesky would have accepted. Every length number on this page is segmented with Intl.Segmenter, which is why the figures can differ from what another tool tells you about the same post.

The practical question the length table answers is different: for this specific account, do short posts or posts pressed against the ceiling get more engagement? The answer varies enormously by account, which is why the table is per-account rather than a piece of general advice, and why a band is only ever called best when at least 5 posts sit in it and at least one other band has 5 too.

Likes are approval, reposts are distribution

Bluesky’s default feed is chronological and its discovery feeds are opt-in, so the main mechanism that puts a post in front of someone who does not already follow the author is a repost or a quote. That makes the split of engagement more informative here than it is on an algorithmic network: an account whose engagement is 90% likes is being approved of by the people who already follow it, and an account with a quarter of its engagement in reposts and quotes is being carried outward.

The result page breaks the split out and names it amplification. It is not a score and there is no target number: a news account and a personal account should look different. It is there because it is the ratio that tells you which of the two things a post did.

Bookmarks are shown beside it and deliberately kept out of the engagement total. The field is a recent addition to the AppView and reads 0 on most older posts, so folding it in would make an account’s older posts look worse for a reason that has nothing to do with how those posts performed.

What this cannot tell you

It cannot tell you why a specific post spread. It can tell you what that post had in common with the account’s other strong posts, which is a different and weaker claim, and the recommendations are written to make that difference visible rather than hide it behind confident phrasing.

A feature comparison is a correlation across one account’s history, not a causal finding. An account whose image posts do better may simply put more effort into the posts it makes images for. The honest use is as a hypothesis to test on your next twenty posts.

It reads only public data and only what the AppView serves: no impressions, no follower-level detail, no private accounts, and nothing at all about who saw a post without engaging with it.

Frequently asked questions

What does it actually compare?

Every post is scored against the account's own median post, not against a global benchmark. Then the posts are split by feature - with images against without, with alt text against without, with a link against without, hashtags, mentions, quote posts, thread posts - and the two medians are compared. A comparison is only reported when at least 5 posts sit on each side of it.

Why do some comparisons say 'not measured'?

Because a side was too small. "Posts with images do 40% better" computed from three image posts is not a measurement, it is a coincidence with a percent sign. When either group is under 5 posts the row says not measured and gives the counts, rather than printing a number that would be acted on.

Is Bluesky's post limit 300 characters?

It is 300 GRAPHEMES, which is not the same thing. The app.bsky.feed.post lexicon caps text at 300 graphemes and 3000 bytes. A family emoji counts as one grapheme and eleven JavaScript characters, so a composer that counts text.length will refuse posts that are inside the limit. Every length figure in this tool is segmented with Intl.Segmenter, never counted with .length.

Why are all the figures medians instead of averages?

Because one post that escapes into a large feed can be fifty times an account's normal engagement. That moves an average by an order of magnitude and a median barely at all, so an average-based comparison would mostly report which group happened to contain the outlier. The outliers are still shown, in their own overperformers section, where they belong.

Does it count reposts and replies?

Reposts are excluded entirely: an item in the author feed carrying a repost reason is somebody else's post with somebody else's numbers. Replies to other people are counted but analyzed separately. Replies inside the account's own thread are treated as the account's own content, because they are.

Why is there no reach or impression figure?

The AT Protocol publishes no view count anywhere. Bluesky does not expose impressions to anyone, including account owners, so a Bluesky tool that shows you reach is generating it. This page reports engagement counts and comparisons between groups of the same account's posts, and nothing else.

Why does alt text matter for engagement?

It is an accessibility obligation first: alt text is what a screen reader announces, and Bluesky surfaces it in its own settings. It also matters practically, because a visible part of the Bluesky network mutes or skips media posted without it. This tool reports coverage across every image and video in the sample, and reports a null rather than a zero when an account posted no media at all.

Does it need a login?

No. It reads public.api.bsky.app, the AT Protocol's unauthenticated public AppView. It needs at least 12 original posts to run, and it marks the sample thin below 40.

PlayerSells is not affiliated with Bluesky or Bluesky Social PBC. Every figure on a result is read live from the AT Protocol’s public AppView at the moment you run the tool, from the account’s own public posts. Endpoint and lexicon behaviour described on this page was verified against public.api.bsky.app on 2 September 2026.