Five strings, one minute. They separate a counter that implements X’s rule from one that counts characters and hopes.
X does not count characters. It assigns each character a weight and allows 280 weight per post — and two rules catch almost everyone. A complete emoji is one unit at weight 2, however many code points it is built from. And every URL costs a flat 23, including a bare domain with no https:// in front of it.
Miss the first and you over-count, and refuse posts X would have accepted. Miss the second and you under-count, and promise that a post fits which X then rejects on send. The second is the expensive one.
Paste each string into the counter you are checking, on its own, and put its answer in the box. Nothing is sent anywhere — the comparison happens in your browser.
| Paste this | Why it is hard | X charges | Yours | |
|---|---|---|---|---|
| 👨ZWJ👩ZWJ👧ZWJ👦 | Four people joined by three ZWJs — seven code points, one emoji, 2. Per code point it is (200*4 + 100*3)/100 = 11. If you get 11, you fell through to the per-code-point path. If you get 7, you counted code points and forgot the weights. If you get 11 in Python, `len()` gave you 7 and something else went wrong too. | 2 | ||
| example.com | THE ONE THAT UNDERCOUNTS. No scheme, no www., still a link, still 23. A matcher requiring http(s):// or www. reports 11 and tells the author a post fits that the API will reject. | 23 | ||
| こんにちは | Five kana at U+3053 upward, all above 0x10FF, so 2 each. | 10 | ||
| 🇨🇴 | Two regional indicators forming one flag: 2, not 4. A per-code-point counter reports 4. | 2 | ||
| ❤️ | U+2764 plus U+FE0F. Two code points, ONE emoji, so 2 — not 1+1 and not 2+1. | 2 |
Enter what your counter reports to see how it does.
Six counters, measured 3 September 2026. Three got all five right. Three did not.
Three of the six charged 11 for a bare domain where X charges 23 — the under-counting direction, the one that gets a post rejected. One was not doing weighted counting at all: it reported 5 for five Japanese characters, where X charges 10.
The tools are not named here, and that is deliberate. A comparison table published by one of the tools in it is marketing, whatever the method was — and the point of this page is to be the thing you can check us with, not a thing you have to trust. Run the five cases on whatever you use. If it passes, good; nothing here asks you to switch.
Every counter in this category claims to be accurate, and not one of them publishes anything you can test it against. That includes the ones that are correct. Correct-and-unverifiable looks identical, from the outside, to wrong-and-confident.
So ours is published: 49 conformance vectors with the arithmetic written out for each, as JSON with CORS enabled so your test suite can fetch it directly. MIT licensed.
const { vectors } = await (await fetch(
'https://postsiete.com/tools/x-vectors.json'
)).json();
for (const v of vectors) {
const got = yourWeightedLength(v.text);
if (got !== v.expected) console.log(v.name, 'expected', v.expected, 'got', got);
}
We publish them because we were wrong. Our counter charged 11 for a joined emoji for weeks, and the test that should have caught it compared our browser copy against our server copy and passed every run — because both copies were wrong in the same way. Two implementations agreeing with each other is evidence of consistency, not of correctness.
emojiParsingEnabled — the weighted length “considers all emoji as a single code point … including longer grapheme clusters combined by zero-width joiners.”