SMS 160-Character Limit: Why Going Over Costs You Money (2026)
The SMS 160-character limit comes from a 140-byte cap. One emoji or smart quote can drop it to 70 and double your bill — here's exactly why.
SMS 160-Character Limit: Why Going Over Costs You Money
Every SMS carries exactly 140 bytes. That single constraint is where the famous 160-character limit comes from — and why one emoji or one curly quote can silently cut that ceiling to 70 and double what you pay. If you send transactional texts, marketing blasts, or 2FA codes, understanding this math is the difference between one billed segment and three. Here's how the numbers actually work.
TL;DR
- One SMS holds 140 bytes; GSM-7 packs characters into 7 bits, giving 160.
- Any character outside GSM-7 (emoji, smart quote) forces UCS-2 — limit drops to 70.
- Split messages reserve 6 bytes per part, leaving 153 (GSM-7) or 67 (UCS-2).
- Providers bill per segment, so going over 160 usually doubles the cost.
- Count characters before sending and avoid one stray Unicode character.
Why is an SMS limited to 160 characters?
The 160-character number isn't arbitrary and it isn't a UI choice — it falls straight out of a byte budget set decades ago.
The 140-byte envelope explained
SMS was designed to piggyback on the control channels GSM networks already used for signalling, so it had to be small. Per 3GPP TS 23.038 (the standard formerly known as GSM 03.38), a single short message payload is capped at 140 bytes. That's the whole envelope — every visible character has to fit inside it. There is no "extend the byte count" option; the ceiling is baked into the protocol.
How 140 bytes becomes 160 characters
Bytes are 8 bits each, so 140 bytes is 1,120 bits of usable space. The trick is that plain text doesn't need a full 8 bits per character. The default SMS alphabet uses only 7 bits, and the network packs those septets tightly across byte boundaries.
140 bytes × 8 bits = 1120 bits
1120 bits ÷ 7 bits = 160 characters
That division is the entire origin of "160." Nothing about it is a marketing round number — it's what 1,120 bits buys you at 7 bits apiece.
The GSM-7 default alphabet
The 7-bit set is called GSM-7. It contains 128 characters: the Latin letters, digits, common punctuation, a handful of accented vowels for Western European languages, and a few symbols. It is not the same as ASCII — GSM-7 includes characters like £, §, and Ø that ASCII lacks, and omits several that ASCII has. If every character in your message lives in this table, you get the full 160.
What characters count as two in an SMS?
Some characters look harmless but quietly eat two slots instead of one. Knowing which ones prevents a message that "looks like 158 characters" from spilling into a second segment.
The GSM-7 extension table
GSM-7's basic table only has room for 128 entries, so a second "extension" table holds a few extra symbols: the euro sign (€), curly braces { }, square brackets [ ], the backslash \, the caret ^, the tilde ~, and the vertical bar |. To encode one of these, the phone first sends an escape code (0x1B), which itself takes a full 7-bit slot, and then the character.
Why € and { cost two characters each
Because the escape byte consumes a septet of its own, every extension-table character costs two of your 160 slots, not one. A message with five euro signs isn't 5 characters of overhead — it's 10. This catches people writing prices ("€19.99") or code-like snippets full of braces. The characters still render fine; they just quietly halve your remaining budget faster than you'd expect.
Here's a quick way to reason about which characters are "safe" in JavaScript:
// Does this string force UCS-2 (Unicode) SMS?
const GSM7 =
"@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ ÆæßÉ" +
" !\"#¤%&'()*+,-./0123456789:;<=>?" +
"¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ" +
"¿abcdefghijklmnopqrstuvwxyzäöñüà";
function forcesUnicode(text) {
return [...text].some(c => !GSM7.includes(c));
}
forcesUnicode("Order shipped!"); // false
forcesUnicode("Order shipped \u{1F389}"); // true
If forcesUnicode returns true, the whole message is about to become far more expensive.
Why does one emoji drop the limit to 70 characters?
This is the single most common billing surprise, and it happens because of an all-or-nothing encoding rule.
UCS-2 and Unicode encoding
The moment your text contains any character that isn't in GSM-7 — an emoji, a Chinese hanzi, an em dash, a bullet — SMS abandons 7-bit encoding entirely and re-encodes the whole message in UCS-2, which stores every character in 2 bytes. Per Twilio's messaging documentation, that halves capacity: 140 bytes ÷ 2 bytes per character = 70 characters.
140 bytes ÷ 2 bytes = 70 UCS-2 characters
The critical detail is that it's not just the emoji that becomes 2 bytes — every letter in the message does. One 🎉 at the end of a 90-character text turns a comfortable single segment into a two-part message.
Smart quotes are the silent bill-doubler
The nastiest version of this isn't emoji — it's punctuation you didn't type on purpose. Word processors and phone keyboards auto-"correct" straight quotes (") into curly ones (" and "), turn hyphens into em dashes (—), and add ellipsis characters (…). None of those are in GSM-7. Paste marketing copy from a document and a single invisible curly apostrophe can silently switch a 120-character message to UCS-2, splitting it into two 67-character segments. Drafting in a plain-text editor like the iKit Markdown Editor avoids the auto-substitution entirely, because it never rewrites your straight quotes into "smart" ones.
How SMS splits long messages into segments
You can send more than 160 characters — the network just chops the text into pieces and rebuilds it on the other end. But the pieces are smaller than the whole.
Concatenated SMS and the User Data Header
Longer messages use concatenation: the text is split into segments that the receiving phone stitches back together. To do that reassembly, each segment carries a small User Data Header (UDH) — reference number, total count, and sequence index — that eats 6 bytes (48 bits) out of the 140-byte payload.
153 and 67: the multi-segment numbers
Because the UDH steals space from every part, segmented messages hold less than a standalone one:
| Encoding | Single message | Per segment (concatenated) |
|---|---|---|
| GSM-7 | 160 | 153 |
| UCS-2 | 70 | 67 |
So a 300-character GSM-7 message isn't 300 ÷ 160 = 2 segments — it's 300 ÷ 153 = 3 segments. The overhead compounds: the longer the message, the more of your budget the headers consume. Twilio's platform caps a concatenated SMS at 1,600 characters (about ten GSM-7 segments) before it stops accepting more.
A worked billing example
Consider a shipping notification. In pure GSM-7 it's 158 characters — one segment, one charge. Add a friendly emoji and a curly apostrophe from a copy-paste, and:
- Encoding flips to UCS-2 (limit 70, or 67 per segment).
- 158 characters ÷ 67 = 3 segments.
- Most carriers bill per segment, so you now pay 3× for the same notification.
Multiply that across 50,000 recipients and a single emoji is a very expensive design decision.
How to keep your SMS under one segment
The fix is boring and reliable: know your character count and your encoding before you hit send.
Count characters before you send
Eyeballing length doesn't work when extension characters count double and one emoji rewrites the whole budget. Paste your draft into a live counter like the iKit Word & Character Counter to see the exact character count as you type, then check it against the limit that applies to your encoding (160, 70, 153, or 67). If you're close to a boundary, trimming a few words is free; letting it spill is not.
Smart Encoding and GSM-safe substitutions
Many providers offer a "Smart Encoding" feature that automatically swaps common non-GSM characters for GSM-safe equivalents — curly quotes become straight quotes, em dashes become hyphens — so the message stays in GSM-7 instead of flipping to UCS-2. You can do the same by hand:
- Replace
"and"with"and'with'. - Replace em dashes (—) and en dashes (–) with a hyphen
-. - Replace the ellipsis character
…with three periods.... - Drop decorative emoji from transactional messages that don't need them.
- Spell out symbols where practical (write "euros" instead of a doubled €).
If you genuinely need to move text between charsets — say, encoding characters safely for a webhook payload or an HTML confirmation page — a tool like the iKit HTML Encoder / Decoder makes the substitutions explicit rather than leaving them to a silent auto-correct.
References
- 3GPP TS 23.038 — Alphabets and language-specific information — the standard that fixes the 140-byte payload, the GSM-7 default alphabet, and the escape-code extension table.
- How long can a message be? — Twilio Docs — source for the 160/70 and 153/67 limits, the UCS-2 switch, and the 1,600-character concatenation cap.
- What The Heck Is A Segment? — Twilio — explains per-segment billing and how encoding choices multiply message cost.
Related on iKit
- Twitter / X's 280-character limit works the same way — plan every character — another hard character ceiling where counting before you post saves you from a truncated or split message.
- See live word and character counts as you draft an SMS — the counting workflow that tells you instantly whether you're under 160 (or 70).
- How many words per minute people actually read — useful when you're deciding how much of that 160-character budget your recipient will really absorb.
Related posts
UUID Regex: Why 8-4-4-4-12 Isn't Enough to Validate (2026)
A UUID regex that only checks the 8-4-4-4-12 shape accepts garbage. Here's how to validate the version and variant nibbles the way RFC 9562 defines them.
5 Common Regex Mistakes That Match Too Much (2026)
Five regex mistakes that make a pattern match too much — greedy .*, unescaped dots, missing anchors, loose alternation, nested quantifiers — with the fix for each.
Word-Level Diff vs Line-Level Diff: When to Use Each (2026)
Line-level diff shines for code review; word-level diff catches the one edited word inside a long paragraph. Here's when to reach for each in 2026.