Bluesky character limit: 300 graphemes, links, media

    Bluesky counts 300 graphemes, not characters or bytes. Links, mentions, four pictures or one video, alt text and what the rate limits mean for a scheduler.

    Updated · 8 min read · Prices and limits checked against the vendors' own pages and APIs on that date.

    A Bluesky post can have 300 graphemes of text, and no more than 3,000 bytes of it. A grapheme is one character as a person sees it, so a flag, a family emoji and a letter with an accent each count as one, whatever they weigh in code. Both limits are in the post schema itself, so they apply to every app and every tool that writes to Bluesky.

    That one sentence is the whole answer for most posts. The rest of this page is for the cases where it is not: emoji-heavy text, long links, pictures that are too large and a video the documents disagree about. Figures checked against Bluesky's own schemas and documents on 8 October 2026.

    The limits at a glance

    RuleLimitNotes
    Text300 graphemesmaxGraphemes in the post schema; spaces and line breaks count
    Text, bytes3,000 bytes (UTF-8)maxLength in the same schema; only long emoji runs reach it
    Pictures per post4the images embed holds at most 4
    Picture size2,000,000 bytes eachthe schema says "up to 2 MB, formerly limited to 1 MB"
    Video1 per post, MP4Preflight allows 100 MB and 3 minutes; the schema says more, see below
    Pictures with a videoNot possiblea post has one embed
    Alt textPer picture or videothe schema sets no length limit
    LinksCount as the text you typethe full address stays in the post unless a client shortened it
    MentionsCount as the text you typethe handle, with its @
    HashtagsCount as the text you typewith the #
    ThreadNo length cap foundeach part is its own post of 300 graphemes
    EditingNoa post is a record; delete it and post again

    Longer pieces go in a thread. Threads, the Meta network, has a different shape: 500 characters, with emoji counted by the byte.

    What a grapheme is, and why it is not a character

    A grapheme is what you would circle with a pen if asked to mark one character on a printed page. Computers store text in layers, and the layers disagree about what one character is:

    • Code points are the Unicode numbers, one per building block.
    • UTF-16 units are what JavaScript's .length counts.
    • UTF-8 bytes are what is stored and sent.
    • Graphemes are the building blocks glued together into what you see.

    Bluesky's 300 is counted in the last of these. These are measured with Intl.Segmenter in Node, the same call the app and our counter use:

    TextGraphemesCode pointsUTF-16 unitsUTF-8 bytes
    hello5555
    é as one code point1112
    é as "e" plus a combining accent1223
    😀1124
    ❤️ (heart plus variation selector)1226
    👍🏽 (thumbs up, skin tone)1248
    🇨🇿 (a flag is two regional indicators)1248
    👨‍👩‍👧‍👦 (family, joined with invisible joiners)171125
    日本語3339
    Příliš žluťoučký kůň úpěl ďábelské ódy38383853

    Three things follow. A counter built on .length calls the family emoji eleven characters, where Bluesky counts one, so it tells you to cut a post that is fine. A counter that counts emoji as two characters, as several pages on this subject do, is wrong the other way for every flag and every joined emoji. And Czech is cheap: a caption of 300 Czech letters is about 340 to 450 bytes, nowhere near the byte limit, even though every accented letter costs two bytes.

    The second limit, 3,000 bytes, is the one that is almost never mentioned. It only matters when the average grapheme weighs more than 10 bytes, which is true of long joined emoji and little else. A row of 120 family emoji is exactly 3,000 bytes and 120 graphemes; the 121st is refused for its bytes although the post is nowhere near 300 graphemes. A post of 300 ordinary letters, accents and CJK included, never gets there.

    The character counter counts a caption this way in your browser, per network.

    Bluesky stores text as plain text. A link, a mention or a hashtag is clickable only when the post also carries a facet: a byte range of the text plus what it points to. The range counts UTF-8 bytes, not string positions, which is why the schema warns developers whose language indexes text in UTF-16. A tool that measures with the wrong unit will underline the wrong words as soon as a post contains an accent or an emoji before the link.

    What each costs against the 300:

    • A link counts as the text in the post. The schema says the visible URL "may have been simplified or truncated" while the facet keeps the complete address, so a client can store a short display form and link it to the long one. Preflight does not shorten anything: the address you type is the address in the text, at full length. A 75-character link counts as 75.
    • A mention counts as the handle with its @. The facet names the account's permanent identifier rather than the handle, so Preflight looks the handle up first; one that does not resolve stays plain text and the post still goes out.
    • A hashtag counts as the # and the word. The facet carries the tag; the schema caps a tag at 64 graphemes, and Preflight skips a tag that is longer or that is only digits.

    Pages that give a fixed number for links (22 or 23 characters) disagree with each other, and neither figure appears in the schema, which is the thing that actually refuses a post. We found no rule in the lexicon that gives a link a fixed cost, and we do not claim one.

    Preflight does not send a link preview card. The link is clickable and has no image under it.

    What the API takes and what it refuses

    Access. Preflight connects with an app password and your handle, not with OAuth. An app password is created under Settings, App Passwords, and can be revoked without touching your login. It opens a session; the session and refresh tokens are stored, not the password. The details are on the Bluesky integration.

    Rate limits. From Bluesky's rate-limit guide:

    LimitValue
    Writes per account5,000 points an hour and 35,000 a day
    Cost of a writecreate 3, update 2, delete 1
    So, in postsabout 1,666 an hour and 11,666 a day
    New sessions per account30 per 5 minutes, 300 a day
    Requests per IP, all PDS endpoints3,000 per 5 minutes

    The API is free to call and the guide lists no price. A schedule never approaches these; a bulk import can. The one that bites is the login limit: log in once and reuse the session. Preflight renews it rather than logging in again. A request over a limit gets a 429, and Preflight tries again later rather than at once.

    What it refuses.

    • Text over 300 graphemes or 3,000 bytes. The error comes from the server; Preflight stops the post before it gets there and names the number.
    • A picture over 2,000,000 bytes. Bluesky refuses the upload itself. Preflight resizes to a JPEG copy up to 2,000 pixels on the long side and says so; your original is not changed.
    • A fifth picture, or a picture next to a video. The post has one embed, so Preflight warns and sends what fits.
    • An empty post. The schema allows empty text only when there are embeds.

    The video figures disagree. Preflight accepts one MP4 up to 100 MB and 3 minutes, the limit Bluesky's app has had since March 2025. We have not found that limit in a Bluesky document we could open. The video schema now says 300,000,000 bytes, "formerly limited to 100mb", and the rate-limit guide gives 50 MB (52,428,800 bytes) as the blob size on a server. We have not tested what a 50 to 100 MB file does through a server, so we enforce the smaller of our own checks and show Bluesky's message if its server says no. If you need a rule you can rely on, keep video under 50 MB.

    Scheduling. A post record has a createdAt field the client fills in, described as the time the post was originally created. It is not a publish time and nothing on the network holds a post until a date. A scheduled post is held by the tool and written when the time arrives; how scheduling works walks through it.

    How Preflight checks a Bluesky post

    Before a post leaves, on every plan including the free one at pricing, Preflight runs these checks and shows the result under the box, as you type:

    • Text measured in graphemes against 300, with the same function in the composer and on the server, so the number you see is the number that decides.
    • Text measured in bytes against 3,000, checked when the grapheme count is within bounds.
    • Each thread part measured on its own against 300, with the error naming which part.
    • Pictures: JPEG, PNG or WebP, at most four, each held to 2,000,000 bytes.
    • Video: MP4 only, one, 100 MB and 3 minutes.
    • Alt text per picture, sent with the post. No length is enforced because the schema sets none.

    The same checks run through the API and, for the fields, the post reference. The connection steps are on the integration page and the scheduling walkthrough is here. Other networks, side by side, are on the limits page; for comparison, Instagram allows 2,200 characters and LinkedIn 3,000.

    Bluesky's rules for automated posting

    A short summary of what the platform's documents say, not legal advice:

    • Scheduled posting is welcome. The bot guide says automated accounts that post at a regular interval are welcome.
    • Label automated accounts. The guide says bot accounts should identify themselves with a self-label on the profile. A brand account that posts only through a tool should consider adding it.
    • Respect the rate limits. The guide says bots must, and singles out logging in repeatedly as the way to trip them.
    • Do not interact unprompted. The guide asks bots to like, repost or reply only to people who tagged them, and warns that unsolicited interaction may be treated as spam.
    • Spam. The community guidelines are the final word on flooding people with unwanted posts and repeating posts in disruptive ways. Do not schedule the same post many times over.

    Sources: post schema, rate limits and the bots guide. The wider list of what the platform asks is under "The platform's rules in short" on the integration page.

    Verified 8 October 2026 against the schemas and documents above and the limits Preflight enforces. All networks: the limits page.

    Questions people ask

    What is the Bluesky character limit?
    300 graphemes of text per post, and no more than 3,000 bytes of UTF-8 as a second ceiling. Both are set in the post schema. A grapheme is one visible character, so an emoji, a flag or an accented letter counts as one. Longer thoughts go in a thread of posts, each up to 300.
    Does Bluesky count spaces?
    Yes. Spaces and line breaks are part of the text, and each is a grapheme. Nothing is excluded from the 300, so a counter that offers a count without spaces is not measuring what Bluesky enforces.
    How does Bluesky count links?
    The limit applies to the text stored in the post. Preflight keeps the address you type at its full length, so a 75-character link costs 75. The schema allows a client to store a shortened display text while the link points to the full address. Pages that quote a fixed cost of 22 or 23 characters per link disagree with each other, and the schema has no such rule.
    Why does an emoji count as one character on Bluesky?
    Because the limit is counted in graphemes, the unit a person sees as one character, not in code points or bytes. A family emoji is seven code points and 25 bytes underneath and still one grapheme. The separate limit of 3,000 bytes is the safeguard for the rare run of long emoji that would otherwise be heavy.
    Is the Bluesky API free and what are its rate limits?
    Bluesky's rate-limit guide lists no price for calling it. Each account may spend 5,000 write points an hour and 35,000 a day, where a post costs 3, an edit 2 and a delete 1, about 1,666 posts an hour. Creating sessions is limited to 30 per five minutes and 300 a day per account, and each IP address gets 3,000 requests per five minutes on the server API.

    Write it once. Let the rules be our problem.

    Preflight checks every post against each network's rules before it leaves, then publishes it to twelve networks. Free plan, no card.