Glossary

Why the Threads Character Limit Counts Emoji as UTF-8 Bytes

Taras Shynkarenko
Taras Shynkarenko
β€’Updated: β€’8 min read
Why the Threads character limit counts emoji as UTF-8 bytesWhy the Threads character limit counts emoji as UTF-8 bytes

TL;DR, Quick Answer

8 min read

Threads text posts are capped at 500 characters, and Meta counts each emoji as its number of UTF-8 bytes rather than as one character. A grinning face costs 4, a skin-toned pointing hand costs 8, and a four-person family emoji costs 25. That is why a post your character counter calls 475 characters can be rejected by Threads at 517.

What is the Threads character limit?

Meta sets the Threads character limit at 500 characters for text posts, and counts each emoji as its number of UTF-8 bytes instead of as a single character. Both rules sit in the Threads API documentation under Single thread posts, in a two-bullet list Meta labels Limitations. For scale, Bluesky caps a post at 300 graphemes and Mastodon documents a 500-character default, so the raw number is unremarkable and the counting method is where Threads differs.

The 500 figure shows up in two places in Meta's docs. The emoji rule shows up in only one of them. Anyone who reads the overview page and stops there walks away with half the spec.

LimitDocumented valueMeta's page
Text post length500 charactersPosts, Overview
Emoji countingNumber of UTF-8 bytesPosts
Carousel childrenMinimum 2, maximum 20Posts, Overview
Links per post5 or fewerPosts
Topic tag length1 to 50 charactersPosts
Published posts250 per 24-hour moving periodOverview
Replies1,000 per 24-hour moving periodOverview
Deletions100 per 24-hour moving periodOverview
Location searches500 per 24-hour moving periodOverview

Why do character counters disagree with Threads?

Character counters disagree with Threads because they count an emoji as one character and Threads counts it as several. Meta's sentence is short enough to quote in full: "Emojis are counted as the number of UTF-8 bytes." The same note is repeated on the text parameter row of the POST /{threads-user-id}/threads endpoint, worded as "For the post character limit, emojis are counted as the number of UTF-8 bytes."

That is the whole explanation Meta gives, and it is where the documentation starts arguing with itself. The phrase "number of UTF-8 bytes" is a hyperlink, and it points at the npm package grapheme-splitter. A grapheme splitter groups code points into what a reader sees as one character. It has nothing to do with byte lengths. So the docs tell you to count bytes and then link to a tool that counts the opposite unit, with no sentence connecting the two.

The reconciliation is left to you. Split the string into graphemes first, which is what the linked package does, then charge each emoji grapheme its UTF-8 byte length rather than 1. Meta never spells that out. Every counter that skips the second half reports a number that is too small, and every counter that applies the byte rule to the whole string reports a number that is too large for accented or non-Latin copy.

A person typing on a phone, choosing emoji for a social post.

How many characters does one emoji cost on Threads?

An emoji costs between 3 and 25 against the Threads character limit, depending on how many code points it is built from. Emoji outside the Basic Multilingual Plane take 4 bytes each. The variation selector U+FE0F that turns a symbol into color emoji takes 3. The zero width joiner U+200D that welds parts together takes 3. Skin tone modifiers take 4.

EmojiCode pointsCounters sayThreads counts
✨U+272813
βœ…U+270513
πŸ˜€U+1F60014
πŸ”₯U+1F52514
❀️U+2764 U+FE0F16
πŸ‘‰πŸ½U+1F449 U+1F3FD18
πŸ³οΈβ€πŸŒˆU+1F3F3 U+FE0F U+200D U+1F308114
πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦U+1F469 U+200D U+1F469 U+200D U+1F467 U+200D U+1F466125

The family emoji is the one that ruins schedules. It reads as a single glyph, it sits in the same emoji picker as the rest, and it eats 5 percent of the post on its own. A rainbow flag costs more than a fourteen-letter word.

A post that passes your counter and fails Threads

Take 470 characters of plain copy and close it with five emoji: πŸŽ‰ ❀️ πŸ‘‰πŸ½ 🧡 πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦. A grapheme counter reports 475, comfortably inside the cap, so the post looks safe.

SegmentCounterThreads
Body copy470470
πŸŽ‰ U+1F38914
❀️ U+2764 U+FE0F16
πŸ‘‰πŸ½ U+1F449 U+1F3FD18
🧡 U+1F9F514
πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦125
Total475517

Threads sees 517 and refuses the post. The gap is 42, and 21 of those come from a single emoji. Swap the four-person family for πŸ‘ͺ U+1F46A, which is one code point and 4 bytes, and the same post drops to 496 and publishes. Nothing about the wording changed.

This is also why three different counters give three different answers for the same string. JavaScript's String.prototype.length reports 491 for that post, because it counts UTF-16 code units. Array.from(post).length reports 483, because it counts code points. A grapheme splitter reports 475. Threads wants 517, and none of the three built-in methods produces it.

A programmer reads code on a monitor, the kind of counting logic a length check requires.

How do you count a Threads post the way Threads does?

Count a Threads post by splitting it into graphemes, charging 1 for each ordinary grapheme and the UTF-8 byte length for each emoji grapheme. Intl.Segmenter handles the splitting in the browser and in Node without a dependency.

const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
const encoder = new TextEncoder();
const EMOJI = /\p{Extended_Pictographic}/u;
 
function threadsLength(text) {
  let total = 0;
  for (const { segment } of segmenter.segment(text)) {
    total += EMOJI.test(segment) ? encoder.encode(segment).length : 1;
  }
  return total;
}
 
threadsLength(post); // 517

Do not reach for Buffer.byteLength(text, 'utf8') as a shortcut. It happens to return 517 for the example above, but only because the body copy is pure ASCII. Run it over "cafΓ©" and it returns 5 where a reader counts 4. Run it over Japanese copy and it triples the count, because each kana is 3 bytes. Meta states the byte rule for emoji and for nothing else.

Which raises the gap Meta has not filled. The docs never define what a character is for the other 500 slots. There is no sentence saying whether "こんにけは" counts as 5 or 15, whether a combining accent counts as 1 or 2, or whether an ordinary non-ASCII character is measured in code points, graphemes or bytes. If you publish in a language that is not ASCII, the only honest position is that the limit is undocumented at the margin, so leave headroom rather than aiming for exactly 500.

AdaptlyPost
AdaptlyPost

Start 7-Day FREE Trial

All-platform analytics

Social Inbox

AI-powered assistant

Four ways to count the same post
String.prototype.length491
Array.from(post).length483
Grapheme splitter475
Threads count517
String length, code points, graphemes and Threads' own count, for the same 500-character example post.

What else rejects a Threads post besides length?

Links reject a post before length does. Threads restricts a post to 5 links or fewer, and since December 22, 2025 a post carrying more fails at the media creation step, POST /{threads-user-id}/threads, with the error code THREADS_API__LINK_LIMIT_EXCEEDED. Meta counts unique URLs, so a link_attachment that repeats a URL already in text counts once, while a link_attachment pointing somewhere new adds one to the tally.

Topic tags have their own rule. A tag must be 1 to 50 characters, cannot contain a period or an ampersand, and only the first valid tag in a post is used. In-text tags also terminate at spaces, at signs, exclamation marks, question marks, commas, semicolons and colons, which means a tag written mid-sentence often ends earlier than the author intended.

Carousels are capped at 20 children with a minimum of 2, and Meta is explicit that "Publishing a carousel counts as a single post" against the 250-post quota. You can read your own remaining quota from GET /{threads-user-id}/threads_publishing_limit, which returns quota_usage alongside a config object holding quota_total of 250 and quota_duration of 86400 seconds.

One thing Meta does not publish is a named error for going over 500. There is a documented code for too many links and none for too much text. Since you cannot catch a specific error string, the check has to happen in your own code before the request goes out.

Where adaptlypost fits

adaptlypost publishes to Threads through the API, so the same 500-character rule and the same emoji arithmetic apply to a scheduled post and a hand-typed one. Platform limits belong to Threads. What a scheduler changes is when you find out about them, because a post drafted in a content calendar is checked long before its send time rather than at the moment it fails.

The counting problem gets sharper when one draft goes to several networks at once, which is the normal case in multi-platform posting. The same emoji costs a different amount on each network, so a caption sized for one is not automatically safe on another. If you write captions with the AI caption writer, treat emoji as budget rather than decoration and keep the final flourish short. For scheduling specifically, see the Threads scheduling tool, and for what those posts did afterwards, Threads analytics.

Frequently Asked Questions

Is the Threads character limit 500 characters?

Yes. Meta documents the Threads character limit as 500 characters for text posts, stated in the Limitations list on the Threads Posts page and repeated in the Other Limitations list on the Threads Overview page. The number has not changed in the documentation as of its April 14, 2026 update.

Why does my Threads post get rejected when the counter says I am under 500?

Your counter is charging 1 per emoji and Threads is charging the emoji's UTF-8 byte length. Five emoji can add 40 or more to the real count, so a post a counter calls 475 characters can reach 517 on Threads. Compound emoji built with zero width joiners are the largest offenders at up to 25 each.

How many characters does an emoji use on Threads?

Between 3 and 25. A symbol like ✨ costs 3, a standard emoji like πŸ˜€ costs 4, a heart with a variation selector costs 6, a skin-toned hand costs 8, and the four-person family emoji πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦ costs 25. The cost is the sum of the UTF-8 byte lengths of every code point in the emoji.

Meta documents the 500-character limit for text posts and applies the emoji byte rule to the text parameter on both single posts and carousel containers. Replies have their own separate quota of 1,000 per 24-hour moving period, which is a count of replies rather than a length limit.

What error does Threads return when a post is too long?

Meta does not publish an error code for exceeding 500 characters. The only documented publishing error of this kind is THREADS_API__LINK_LIMIT_EXCEEDED, returned by POST /{threads-user-id}/threads when a post carries more than 5 links. Validate length in your own code before you call the endpoint.

How many posts can a Threads profile publish per day?

  1. Meta limits a profile to 250 API-published posts within a 24-hour moving period, and a carousel of up to 20 images or videos counts as one post against that total. Query GET /{threads-user-id}/threads_publishing_limit to read quota_usage against a quota_total of 250.

How can I check my remaining Threads posting quota before I publish?

Call GET /{threads-user-id}/threads_publishing_limit and read quota_usage against the returned config. Meta's config object holds a quota_total of 250 and a quota_duration of 86400 seconds, matching the 24-hour moving window for published posts. Checking this endpoint before you send a batch tells you how much of the day's allowance is already spent.

What happens if a Threads post has more than 5 links?

The post fails at the media creation step, POST /{threads-user-id}/threads, with the error code THREADS_API__LINK_LIMIT_EXCEEDED. This rule has applied since December 22, 2025, and Meta counts unique URLs rather than every link mention, so a link_attachment repeating a URL already in the text counts once. There is no equivalent named error for exceeding the 500-character limit.

How long can a topic tag be on Threads?

A Threads topic tag must run 1 to 50 characters, and it cannot contain a period or an ampersand. Only the first valid tag in a post is used, and an in-text tag ends early if it hits a space, an at sign, or punctuation like an exclamation mark, comma, or colon.

A Threads carousel needs at least 2 children and allows at most 20. Meta counts the whole carousel as a single post against the 250-post daily quota, regardless of how many children it contains.

AdaptlyPost
AdaptlyPost

Start 7-Day FREE Trial

All-platform analytics

Social Inbox

AI-powered assistant

Was This Article Helpful?

Let us know what you think!

See us more often in Google

One click marks AdaptlyPost as a preferred source, so our articles sit higher in your Top Stories, AI Mode, and AI Overviews.

Before you go...

AdaptlyPost

AdaptlyPost

Schedule your content across all platforms

Manage all your social media accounts in one place with AdaptlyPost.

All-platform analytics

Social Inbox

AI-powered assistant

Related Glossary Terms

Related Articles