Guide · By PostBoost team · · Markdown
Short answer: a Bluesky post holds 300 characters. Bluesky counts graphemes, what a reader sees as one character, so every emoji counts as 1. Links are cheaper than they look: Bluesky keeps only a short form of the link in the text (domain plus 13 characters and "..."), so an 80-character tracking link costs 27. Paste a draft into the free social media character counter to see the Bluesky count next to X, Threads and the others.
Every Bluesky limit in one table
Bluesky is open source, so its limits are written down in two public places: the protocol schema (the "lexicon" every app must follow) and the code of the official app. The table says which one each number comes from.
| where | limit | source |
|---|---|---|
| Post text | 300 graphemes and 3,000 bytes | Protocol: app.bsky.feed.post |
| Images per post | 4, up to 2 MB each | Protocol: app.bsky.embed.images |
| Video per post | 1, up to 10 minutes and 300 MB in the official app | App code: constants.ts |
| Alt text per image | 2,000 characters | App code: constants.ts |
| Display name | 64 graphemes | Protocol: app.bsky.actor.profile |
| Bio (profile description) | 256 graphemes | Protocol: app.bsky.actor.profile |
| One hashtag | 64 graphemes | Protocol: app.bsky.richtext.facet |
The numbers above were read from the source on 15 October 2026. Video is the one that has moved: it launched at 60 seconds in 2024, went to 3 minutes in March 2025 (TechCrunch), and the official app's code now allows 10 minutes. Guides that say 60 seconds or 3 minutes are out of date. The post limit is 300 in both the protocol and the app.
How Bluesky counts the 300
Graphemes, not bytes or code points. A grapheme is what you would call one character when reading. "é" is 1, a flag is 1, and a family emoji made of four people and three invisible joiners is still 1. X counts each emoji as 2, so an emoji-heavy post can fit on Bluesky and fail on X.
There is also a 3,000-byte ceiling. It almost never matters: 300 characters of English take about 300 bytes, and 300 Japanese characters take 900. It only bites on posts made mostly of complex emoji. That family emoji is 25 bytes, so 120 of them hit the byte limit while the counter still shows 120 of 300.
Links count as their short form. When the Bluesky app publishes a post, it replaces each link in the text with a short version and keeps the full address as a clickable link behind it. The short version is the domain, then the first 13 characters of the rest, then "...". The full rule is a few lines in the app's url-helpers.ts:
| you write | Bluesky shows and counts | characters |
|---|---|---|
https://example.com/about |
example.com/about |
17 |
https://example.com/blog/how-we-ship-weekly?utm_source=bluesky&utm_medium=social (80) |
example.com/blog/how-we-... |
27 |
So long UTM-tagged links are fine on Bluesky: the tracking parameters still reach your analytics, and they do not eat into the 300. The reader sees the domain, so a recognisable domain matters more than a short path.
Mentions and hashtags count in full. @yourname.bsky.social is 21 characters of your 300. Unlike Mastodon, Bluesky does not drop the server part of a handle. A custom-domain handle such as @example.com is shorter and easier to read.
When 300 is not enough: write a thread
A Bluesky post cannot be longer than 300 characters, so a longer idea becomes a thread of replies, each with its own 300. Three habits make a thread read well:
- Make the first post stand alone. The feed usually shows the first post on its own. Put the point there and the detail below.
- Split at sentences, not at the limit. A post that stops mid-sentence at character 300 reads like a mistake.
- Put the link where it is useful. On Bluesky a link costs only its short form, so it can sit in the first post. If the same thread also goes to X, keep the link in the last post there: in PostBoost a part with a link counts as an X link post (why one link in the last post is cheapest).
The free thread maker splits long text into numbered posts for Bluesky (pick Bluesky as the network) at paragraph and sentence breaks, and never cuts a word or a link.
How PostBoost handles Bluesky limits
PostBoost checks Bluesky's rules in the composer, before the post is scheduled.
- Same counting as Bluesky. The counter for a Bluesky account counts an emoji as 1 and a link as the short form Bluesky will show, so
https://example.com/blog/how-we-ship-weekly?utm_source=bluesky&utm_medium=socialcounts as 27, not 80. When PostBoost publishes, it shortens the link in the text the same way and keeps the full address as the clickable link. - Hard limit. A Bluesky post over 300 characters shows "Maximum of 300 characters allowed." for that account, and the post cannot be scheduled until it is shorter. The same check allows up to 4 photos, or 1 video, or 1 GIF, and says "Combining different media types (videos, photos, GIFs) is not allowed." if you mix them.
- Threads. Click Add Post to add the next post of the thread. Each post is checked against the 300 on its own (an error reads "Post #2 - Maximum of 300 characters allowed."), and PostBoost publishes them as replies, in order. If the same post also goes to a Facebook, Instagram or LinkedIn account, the button reads Add first comment instead; create a version for the Bluesky account and add the thread posts there.
- Link cards. When a post has no image or video, PostBoost attaches a link card for the first link in it, with the title, description and image the linked page provides.
- Suggestions, not blocks. The composer flags images without alt text and suggests adding a hashtag, because people find posts on Bluesky by hashtag. Mentions of existing handles such as
@name.bsky.socialand hashtags become working links on Bluesky. You can ignore any suggestion and still schedule.
To check one draft against Bluesky and every other network you post to, paste it into the free social media post checker: it applies the same length and media rules and shows what each network will reject.
Check a thread with the API before you schedule it
The REST API runs the same rules. POST /posts/validate is a dry run: it checks length, media and the other network rules for each account and creates nothing. On Bluesky, each item after the first in content is the next post of the thread:
curl -X POST "https://postboost.co/app/api/$WORKSPACE_UUID/posts/validate" \
-H "Authorization: Bearer $POSTBOOST_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accounts": [15],
"schedule": true,
"date": "2026-10-20",
"time": "15:00",
"timezone": "Europe/Berlin",
"versions": [{
"account_id": 0,
"is_original": true,
"content": [
{ "body": "We now ship every Friday. Here is what changed in our release process, and what broke on the way." },
{ "body": "The write-up, with the checklist we use: https://example.com/blog/how-we-ship-weekly?utm_source=bluesky&utm_medium=social" }
]
}]
}'
The endpoint answers 200 either way; read valid. If one post of the thread is over 300 characters for the Bluesky account, valid is false and errors holds the length error for that account. Send the same body to POST /posts to schedule it for real (validatePost, createPost).
When you want to plan Bluesky posts and threads with the limits checked for you, start free and connect your Bluesky account.
Do this in PostBoost
Free tools for this guide
Free tool
Social media character counter
Free character counter for X, Threads, Bluesky, Instagram, LinkedIn, TikTok and more. Counts as each network does, live in your browser.
Free tool
X thread maker: split long text into numbered posts
Split long text into numbered posts for X, Threads, Bluesky or Mastodon. Never cuts a word or a link. Free, no signup, runs in your browser.
Free tool
Social media post checker: check your post before you publish
Check a post before posting: character limits, hashtags, media count, video length and see-more cut-offs for X, Instagram, LinkedIn, TikTok and more.
FAQ
What is the Bluesky character limit?
300 characters per post. Bluesky counts graphemes, meaning what a reader sees as one character, so an emoji counts as 1 even when it is built from several code points. The protocol also caps a post's text at 3,000 bytes, which only matters for posts made mostly of complex emoji.
Do links count toward the 300 characters on Bluesky?
Only their short form. Bluesky stores and shows a link as the domain plus the first 13 characters of the rest, followed by three dots, and keeps the full address behind it. An 80-character link with UTM parameters costs 27 characters of the 300.
Do emoji count as 1 or 2 characters on Bluesky?
1. Bluesky counts graphemes, so a single emoji, a flag or a family emoji built from several code points each count as one character. X counts the same emoji as 2.
What is the Bluesky alt text limit?
2,000 characters per image in the official Bluesky app. Write what the image shows and why it is in the post; a sentence or two is enough for most images.
How long can a Bluesky bio and display name be?
The profile description (bio) holds 256 characters and the display name 64, both counted as graphemes. These limits are set in Bluesky's protocol schema.
Can I write a longer post on Bluesky?
Not in one post. Split the text into a thread: each reply has its own 300 characters. In PostBoost, click Add Post in the composer to add the next post of the thread, and PostBoost publishes them as replies in order.
What happens in PostBoost if a Bluesky post is too long?
The composer shows "Maximum of 300 characters allowed." for the Bluesky account and will not schedule the post until you shorten it. A REST API call is rejected the same way, and the validate endpoint reports it without creating anything.
Sources
- Bluesky (AT Protocol) lexicon: app.bsky.feed.post, text maxGraphemes 300 and maxLength 3000
- Bluesky (AT Protocol) lexicon: app.bsky.embed.images, 4 images, 2 MB each
- Bluesky (AT Protocol) lexicon: app.bsky.actor.profile, display name 64 and description 256
- Bluesky app source: constants (post 300, alt text 2,000, video 10 minutes and 300 MB)
- Bluesky app source: how links are shortened (toShortUrl)
- TechCrunch: Bluesky now lets users upload videos that are up to 3 minutes long (March 2025)
- PostBoost API reference: validatePost