X (Twitter) Character Counter
Introduction
X counts posts with a system most people have never heard of: weighted characters. Links collapse to exactly 23 characters no matter how long they are, Chinese/Japanese/Korean glyphs and emoji weigh twice as much as English letters, and a handful of Unicode ranges get special treatment. The result is a limit that regularly surprises – a draft that looks safely under 280 gets rejected, and nobody can see why.
The Toollect X (Twitter) Character Counter applies the real rules, not a naive string length. Paste a draft and six counters update as you type – weighted total, hashtag count, mention count, URL count, line breaks and paragraph breaks – alongside lists of every hashtag, mention and link the platform-style parser detects. The detection boundaries were verified case by case against live x.com behavior, including the odd corners: ##Japan extracts but #Japan# does not, .@alice detects while !@alice does not, and handles keep matching up to 20 characters even though new accounts stop at 15.
Everything runs locally in your browser. There is no API key, no sign-up, and no request of any kind – your draft never leaves your device, and the numbers stay instant because nothing waits on a network.
Use Cases
Social media managers checking scheduled posts
Scheduling tools frequently miscount X drafts because they use plain length. Run the copy through this counter before queueing – the weighted total and the URL list tell you exactly what X will accept, and the over-limit warning appears the moment the draft crosses the line.
CJK writers fighting silent truncation
Japanese, Chinese and Korean posts fit roughly 140 glyphs into the same budget an English post uses for 280. Seeing the weighted number next to your draft turns the invisible doubling into something you can plan around instead of discovering after publishing.
Developers building bots and automation
If your bot composes tweets programmatically, this counter doubles as a specification reference: the weight ranges, the fixed URL cost, and the hashtag/mention boundary tables document the exact rules the parser implements, case by case.
Cross-platform writers
Adapting one message across platforms means respecting different limits and different math. Pair this tool with its sibling, the Instagram Caption Analyzer, and you can check both destinations without guessing which platform weighs what.
How It Works
The counter runs four steps entirely in your browser, updating live on every keystroke:
- Normalize the text. The input is converted to Unicode NFC form first, so a decomposed
é(letter plus combining accent) counts once instead of twice – matching how X itself normalizes before counting. - Extract and flatten URLs. Every link X recognizes is pulled out and replaced with a flat cost of 23 characters – both
https:///http://addresses and protocol-less domains such astwitch.tvwhose ending sits on the official top-level-domain lists. Trailing punctuation such as a sentence-ending period stays with the surrounding text rather than the link. - Segment into grapheme clusters. The remaining text is split by
Intl.Segmenterinto user-perceived characters – so an emoji family built from seven code points, a flag built from two, and a skin-toned thumbs-up each form exactly one unit. - Weigh each cluster. Clusters containing emoji weigh 2. Everything else sums its code points against the official light ranges – 1 if inside, 2 if outside. Hashtags and mentions are extracted separately from the link-free text using the x.com boundary rules documented below.
Changing any option re-runs the whole chain instantly. Nothing is sent anywhere and nothing is cached between sessions.
The Weighted Counting Rules
This is the complete weight table the counter applies, matching the public twitter-text configuration X builds on.
| Characters | Examples | Weight |
|---|---|---|
| U+0000 – U+10FF | Latin, Greek, Cyrillic, Hebrew, Arabic, Hindi, Thai, punctuation, digits | 1 |
| U+2000 – U+200D | General punctuation and the zero-width joiner | 1 |
| U+2010 – U+201F | Dashes and typographic quotes | 1 |
| U+2032 – U+2037 | Prime marks | 1 |
| Everything else | Chinese/Japanese/Korean, Hangul, emoji, most other scripts | 2 |
Three special rules sit on top of the table:
- Every link costs 23. Any address the parser recognizes flattens to exactly 23 characters regardless of its true length –
https://andhttp://URLs plus protocol-less domains liketwitch.tv. A lookalike whose ending is not a real top-level domain (foo.zzz) stays ordinary text. - Emoji clusters are atomic. Detection works on grapheme clusters, so 👨👩👧👦 counts as one cluster (weight 2), flags count as one, and skin-tone modifiers merge into their base emoji. Without clustering, that family would wrongly add eleven code points.
- Accents collapse before counting. Text is normalized to NFC, so
cafétyped with a decomposed accent counts as 4 characters, not 5.
A worked example – the draft Read more about the mission 🚀 https://x.com/a/long/path:
| Part | Computation | Cost |
|---|---|---|
Read more about the mission |
27 light characters | 27 |
| 🚀 | one emoji cluster | 2 |
| space | 1 | 1 |
https://x.com/a/long/path |
flattened URL | 23 |
| Total | 53 |
Hashtag and Mention Boundaries
Detection follows the boundaries observed on live x.com across 36 verified test cases – including several that contradict common assumptions. The tables below list the decisive ones.
Hashtags
| Input | Result | Rule |
|---|---|---|
#Japan at start, after a space |
✓ | Standard case |
🇯🇵#Japan, !#Japan, .#Japan, ,#Japan, -#Japan |
✓ | Emoji and these punctuation marks do not block the hash |
abc#Japan, 123#Japan |
✗ | A letter or digit glued in front cancels it |
_#Japan |
✗ | Underscore blocks too |
&@mention, &#Japan |
✗ | Ampersand blocks (HTML-entity safety) |
@#Japan |
✓ | An at-sign directly before the hash does not block |
##Japan, ##Japan, #Japan |
✓ | Extra hashes – halfwidth or fullwidth – do not block |
#Japan#, #Japan#Japan, #Ja#pan |
✗ | A hash immediately after the tag kills it, and no partial retry happens |
#123, #123, #🇯🇵 |
✗ | Tags need at least one letter or the run never forms |
#1Direction, #日本語, #foo_bar |
✓ | Digits mixed with letters, Unicode tags and underscores all work |
The #Japan# family surprises most people: the tag text itself is fine, but X discards the entire candidate when another hash sits directly against its end, and the parser never falls back to a shorter match.
Mentions
| Input | Result | Rule |
|---|---|---|
.@alice, ,@alice, ?@alice, :@alice, (@alice, /@alice, -@alice |
✓ | These punctuation marks allow the mention |
🇯🇵@alice |
✓ | Emoji allows it too |
!@alice |
✗ | An exclamation mark blocks mentions – stricter than hashtags |
@@alice, #@alice, &@alice, abc@alice, 123@alice |
✗ | At/hash/ampersand/word characters all block |
@alice@bob |
✗ both | Handles followed directly by another at are discarded |
@alice's post |
✓ alice | The possessive stays outside the handle |
@15chars_max_0000 (16 chars) |
✓ full handle | The parser matches up to 20 characters – account creation stops at 15, detection does not |
@12345678901234567890123 (23 digits) |
✓ first 20 | Beyond the cap the remainder becomes plain text |
Mentions are deliberately stricter than hashtags on the left side (! blocks here but not there) and looser on the right (@alice# keeps its mention where #Japan# loses its tag). Both behaviors were confirmed on live x.com before being encoded.
Character Limit Myths
Four beliefs survive from old documentation or plain assumption. Each fails against current x.com.
"Replies don't count leading mentions." True in 2017, false today. Typing or pasting handles at the head of a reply reduces your available characters exactly like body text – verified on live x.com while building this tool. Guides repeating the exemption are describing a retired rule.
"All non-English text weighs double." The doubling starts above a specific Unicode point. Arabic, Hebrew, Hindi and Thai all sit inside the single-weight zone, so an Arabic post carries nearly as much text as an English one. The heavy weight belongs to CJK, Hangul, emoji and scripts beyond that range.
"Shorten your links before posting." Pointless since 2010. X replaces every link with its own shortener and charges a flat 23 whether you hand it 13 characters or 300. Pre-shortening changes nothing except hiding where the link points.
"Images and quote posts eat characters." Attachments cost nothing – up to four photos ride along free – and a quoted post's text is not added to yours. Only the text you actually type counts.
Premium and Long Posts
An X Premium subscription raises the ceiling from 280 to 25,000 characters on every paid tier, turning a post into something closer to an article. Two caveats matter more than the headline number.
First, X documents the weighted rules for the 280 limit but has never published how the 25,000 cap treats links, emoji or CJK text. Any third-party counter claiming exact parity with the long-form limit is guessing. This tool deliberately models only the well-documented 280 rules instead of inventing unverifiable ones.
Second, timelines fold long posts after roughly the first 280 characters behind a Show more link. Whatever you write beyond that, the opening competes for attention under the same weighted rules as everyone else's post. For anything that must be read without an extra click, 280 remains the number that matters – which is why this counter stays useful even for Premium accounts.
Usage
- Type or paste your draft into the text area. All six counters update on every keystroke.
- Watch the Characters card – it turns red the moment the weighted total passes 280, and the message above explains the overrun.
- Read the breakdown lists – every hashtag, mention and link the parser detected appears below, with duplicates collapsed into a single chip marked ×N.
- Copy the draft when it fits – the button selects the text and puts it on your clipboard, ready for x.com or your scheduling tool.
- Clear resets the text and every counter in one step.
There are no options to configure and no modes to choose – the tool always applies the same live-x.com rules.
Tutorial
Follow one realistic draft through the whole pipeline.
Step 1 – Paste a mixed draft.
Training complete ✅ Full report https://x.com More details soon
A generic character counter reports 63. The Characters card reports 74. The gap is the invisible arithmetic at work: the checkmark emoji weighs 2 as its own cluster (+1 over a plain count), and the link flattens from 13 characters up to 23 (+10).
Step 2 – Watch the URL flatten. Replace the short address with a much longer one:
Training complete ✅ Full report https://defense.example.gov/news/2026/exercise-report More details soon
The link grew by 40 characters, yet the Characters card does not move from 74 – the Detected URLs list confirms the new address costs the same flat 23. A plain counter would jump to 103; this is why pre-shortening links saves nothing on X.
Step 3 – Add hashtags the way x.com parses them. Append #Japan #Training. Both extract cleanly and add 6 and 9 weighted characters respectively, plus the two separating spaces – the card reads 91.
Step 4 – Break a hashtag on purpose. Type #Ja#pan. Neither fragment appears in the list – a hash against the end of a tag invalidates the whole candidate. Undo back to the working version.
Step 5 – Cross the line. Duplicate the CJK opening until the card turns red and the over-limit message appears. Trim until it clears – watching the number fall makes the 2-per-glyph arithmetic instinctive.
Step 6 – Copy and ship. Hit Copy, paste into x.com, and the composer accepts the draft first try – same rules, same number.
Pro Tips
- Budget links at 23 each, before writing. One link leaves 257 characters; three leave 211. Reserve the budget first and the draft never needs surgery later.
- Treat complex emoji as luxury spending. Every emoji cluster costs 2, and reaction strings add up fast – three party poppers outweigh the word wow.
- Front-load the hook. Timelines truncate around the fold; whatever sits past the weighted midpoint rarely earns clicks. Put the payoff early.
- Keep hashtags to a clean handful. X imposes no hard hashtag penalty, but tags mid-word never parse – leave a space or start-of-line before every hash.
- Paste from Word without fear. Smart quotes and dashes sit in the single-weight punctuation ranges, and NFC normalization folds decomposed accents down to one.
- Pair with the Instagram Caption Analyzer for cross-posting. Same draft, different platform math – X weighs and flattens links, IG tracks tallies against a lenient 2200 with a five-hashtag guideline.
- Trust the red card over your eyes. If Characters says over, the post is over – the weighted arithmetic sees costs plain counters cannot.
Alternatives
| Option | Weighted rules | Boundary-exact detection | Live stats breakdown | Private/offline |
|---|---|---|---|---|
| This counter | Yes – verified on live x.com | Yes – 36 tested cases | Six counters + item lists | Yes |
| x.com composer counter | Yes | Yes | Total only, no breakdown | N/A (on platform) |
| Generic character counters | No – plain length | No | Partial | Usually |
| Scheduler built-in checks | Rarely – most use plain length | No | Varies | No |
| twitter-text library | Yes – reference implementation | Yes | Build it yourself | Depends on host |
The composer inside x.com is authoritative but offers a single number with no diagnosis. Generic counters are the reason drafts get rejected – they ignore weighting entirely. Schedulers inherit the same flaw. The twitter-text library is the source of truth if you want to embed the full engine, at the cost of a dependency. This tool occupies the practical middle – reference-grade rules with zero setup.
Against the twitter-text Library
X publishes an open-source library, twitter-text, that defines the canonical counting and extraction rules – this counter implements the same public specification rather than calling any API.
| Capability | twitter-text library | This counter |
|---|---|---|
| Weighted length | Exact – reference implementation | Same weights and ranges |
| Link detection | Exhaustive grammar with hundreds of valid top-level domains | Bare domains checked against the same official suffix lists – https links skip that check |
| Emoji clustering | Config-driven parsing | Grapheme segmentation with the standard emoji-block heuristic |
| Hashtag/mention boundaries | Reference regexes | Boundaries transcribed from live x.com tests (36 cases) |
| Integration | A bundled dependency for your build | None – open the page and type |
Bare-domain detection now shares the library's foundation: this counter embeds the same official gTLD/ccTLD suffix lists, so twitch.tv counts as a link while foo.zzz stays text, exactly as the library decides. Two honest gaps remain – https:// links are accepted in any plausible shape without the suffix check, and the embedded lists freeze at the open-source release, so a top-level domain introduced after it could be missed. For ordinary posts the numbers agree; everything else – weights, clustering, boundaries – follows the same spec, and the boundary tables came from live-platform testing rather than library transcription.
Counter vs. Caption Analyzer
Toollect ships sibling analyzers for the two biggest social platforms, and their differences illustrate why one counter never fits all:
| Question | Caption Analyzer (Instagram) | This counter (X) |
|---|---|---|
| Limit | 2,200 characters | 280 weighted characters |
| Counting basis | UTF-16 length | Weighted grapheme clusters |
| Simple emoji | 2 (astral units) | 2 (cluster rule) |
| Complex emoji families | Weighs each code unit – a family costs more than 2 | Always exactly 2 per cluster |
| Links | Ordinary text – no flattening | Flat 23 each |
| Platform-specific limits | Five-hashtag guideline | Reply mentions count; boundary rules per the tables above |
Neither approach is wrong – each mirrors its platform. Instagram's longer limit tolerates simpler counting, while X's tight budget demands the weighted precision. One honest note on the sibling: a ZWJ emoji family pasted into the caption analyzer counts its raw code units (a family costs more than 2), because Instagram has never documented its exact method and UTF-16 was the pragmatic choice. If you post the same family on both platforms, expect X to charge it 2 and the analyzer to report more.
What It Doesn't Do
- It does not model Premium long posts. The 25,000-character tier exists, but X has never documented how it counts – inventing rules would break the accuracy guarantee. See Premium and Long Posts above.
- It does not split threads. Over the limit means trim or thread manually; the tool reports, it does not rewrite.
- It does not guarantee bit-for-bit parity with X servers. Bare domains are checked against the official suffix lists, but https links skip that check and the embedded lists freeze at the open-source release – pathological addresses could in theory be classified differently. Ordinary posts agree.
- It does not verify that handles exist.
@nonexistent_account_12345still parses as a mention – validity is a platform lookup, not a grammar question. - It does not check bio, DM or name limits. Those fields use different caps (160, 10,000 and 50 respectively) outside this counter's single-purpose scope.
- It does not post, schedule or store anything. The output is knowledge, not actions.
- It is not affiliated with X. Rules were transcribed from public documentation and live observation, with no endorsement implied.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| My draft looks shorter than 280 but the card is red | Weighted costs – links at 23, CJK/emoji at 2 | Check the breakdown lists; replace the link or trim doubled-weight text until it clears |
| The URL list shows a link I did not intend to post | Recognized links count – including protocol-less domains like twitch.tv | Reword so the address is not part of the draft, or accept its 23-character cost |
#123 does not appear under Hashtags |
Purely numeric tags are not hashtags on X | Add a letter to the tag, or drop it |
| A hashtag after an emoji is missing | Should not happen – emoji prefixes are valid | Confirm no letter/digit/underscore sits directly before the hash; report the exact input if it still fails |
| The count differs slightly from another website's counter | Most competitors use plain length | This counter applies the official weights; trust the red card over generic totals |
| Accented words seem to count differently elsewhere | Other tools skip NFC normalization | This counter normalizes first – its number matches X |
| Copy did nothing | Clipboard permission denied by the browser | Grant clipboard access or select the textarea manually and copy with Ctrl/Cmd+C |
Privacy and Data Handling
This tool is a member of the site's zero-request family – the strictest privacy class Toollect ships.
- Nothing leaves your device. Drafts, hashtags, mentions and counts exist only in your browser tab. No Toollect server, no third-party endpoint, no analytics touch the text you type.
- No account, no storage, no cookies for tracking. Close the tab and every trace disappears – there is no history to clear because none was written.
- The checker works offline. Once the page has loaded you can sever the connection entirely and keep counting.
- Clipboard use is explicit. Text reaches the clipboard only when you press Copy – never automatically.
If you need the same privacy philosophy applied to link analysis, the X (Twitter) URL Parser on this site runs its entire workflow with zero requests as well.
Technical Specs
Details:
- Limit – 280 weighted characters; each link flattens to 23; every other unit weighs 1 or 2 per the range table
- Light ranges – U+0000–U+10FF, U+2000–U+200D, U+2010–U+201F, U+2032–U+2037 (weight 1); all other code points weigh 2
- Normalization – input converted to Unicode NFC before counting
- Segmentation –
Intl.Segmentergrapheme mode; clusters containing emoji markers (VS16, ZWJ, keycap, U+1F000+, U+2600–27BF) weigh 2 atomically; fallback to code-point iteration where Segmenter is unavailable - Link grammar – an
https:///http://address (leading boundary at start/space/open bracket) or a protocol-less domain whose TLD matches the official gTLD/ccTLD lists; a domain glued directly after dash/underscore/dot/slash does not parse; trailing punctuation excluded from the link and weighed as text - Hashtag grammar –
#/#plus at least one letter within[\p{L}\p{N}_]+; preceding character must not be a letter, digit, underscore, ampersand; following character must not be a hash symbol; fullwidth symbols accepted - Mention grammar –
@/@plus 1–20 characters of[A-Za-z0-9_]; preceding character must not be a word character, exclamation mark, at, hash, ampersand (fullwidth equivalents included); following at-sign discards the candidate - Statistics – weighted total, hashtag count, mention count, URL count, line-break count, paragraph-break count (blank-line separated), plus deduplicated item tallies with ×N badges
- Network traffic – zero; all computation is local JavaScript
- Browser support – all modern browsers with
Intl.Segmenter(Chrome 87+, Safari 14.1+, Firefox 125+) and the Clipboard API
Features
- Counts against the real X weighted limit – URLs cost exactly 23 characters, CJK and emoji weigh 2, verified against live x.com
- Boundary-exact hashtag and mention detection – 36 edge cases verified on real x.com, covering emoji prefixes, doubled hashes, glued fragments and numeric-only tags
- Six live statistics as you type – characters, hashtags, mentions, URLs, line breaks and paragraph breaks
- Unicode-correct by design – emoji families count as one cluster, decomposed accents normalize before counting, Arabic weighs 1
- Reflects today's X, not 2017 folklore – leading reply mentions count toward the limit, exactly as the platform behaves now
- Free, private and instant – everything runs in your browser with zero requests, no API key, no sign-up