01What is UCS-2 encoding?
UCS-2 encoding (Universal Coded Character Set, 2-byte) is the 16-bit character encoding an SMS falls back to whenever its text contains anything outside the GSM-7 alphabet. Every character takes 2 bytes of the 140-byte SMS payload, so one SMS holds 70 characters instead of 160. When a message is longer, it becomes a concatenated SMS and each part holds 67 characters, because 6 bytes of every part go to the User Data Header that tells the phone how to reassemble them. On SMPP the encoding is signalled with data_coding 0x08.
UCS-2 is what makes Hindi, Tamil, Bengali, Marathi and every other Indian script possible over SMS, along with emoji and typographic characters such as curly quotes (’ “ ”), en and em dashes, the ellipsis, the non-breaking space and the rupee sign (₹). Strictly, UCS-2 covers only the Basic Multilingual Plane (U+0000 to U+FFFF). Most emoji sit above it and travel as UTF-16 surrogate pairs, so each costs two of the 70 units; in practice phones and gateways send UTF-16 and still call it UCS-2.
The switch is all-or-nothing. If a single character is outside GSM-7, the gateway encodes the entire message as UCS-2, so a 150-character English alert that fitted in one SMS becomes three parts after a curly apostrophe is pasted in from a document, tripling its cost. 3GPP also defines national language shift tables for Indian scripts, but support across handsets and routes is uneven, so Indian-language SMS normally go as UCS-2. GSM-7 encoding is the cheap default alphabet; UCS-2 is the expensive fallback; concatenated SMS covers how the parts are split and billed.
Key takeaways
- UCS-2 is the 16-bit encoding SMS uses for any text outside the GSM-7 alphabet: Indian scripts, emoji, curly quotes and dashes.
- A UCS-2 SMS holds 70 characters, and each part of a longer message holds 67, against 160 and 153 for GSM-7.
- One stray character converts the whole message, so a 150-character English text with one curly apostrophe goes as 3 parts instead of 1.
- Emoji outside the Basic Multilingual Plane take two of the 70 units each, because they travel as UTF-16 surrogate pairs.
- Use UCS-2 deliberately for regional-language SMS, and strip accidental Unicode from English templates and variables before sending.
02Example: A Coimbatore retailer's two kinds of Unicode
A Coimbatore textile chain sends a Pongal offer in Tamil to 60,000 customers: 128 characters, so 2 UCS-2 parts each, a cost it accepts because Tamil lifts response. Its English reminder a week later should have been one part, but the copy was written in a word processor and contains "it’s" and an en dash. Every reminder goes as 3 UCS-2 parts. The team adds a pre-send check that swaps smart punctuation for plain ASCII and flags any non-GSM character in English templates, and the next reminder costs a third as much.
03 · How it works, step by step
How does UCS-2 encoding work?
- Step 1
Every character is checked against GSM-7
The gateway or handset scans the text. Characters in the GSM-7 basic set cost one septet, extension characters such as € or [ cost two, and anything else is outside the alphabet.
- Step 2
One outsider converts the whole message
If even one character is outside GSM-7, the message is encoded as UCS-2 and flagged with
data_coding0x08. There is no partial switch. - Step 3
Each character becomes 2 bytes
Text is written as 16-bit units (big-endian UTF-16). Most Indian-script letters and punctuation take one unit; emoji above U+FFFF take two, as a surrogate pair.
- Step 4
Up to 70 units fit one SMS
A message of 70 units or fewer goes as a single SMS. Longer text is split into parts of up to 67 units, each carrying a 6-byte header with a reference, a part count and a sequence number.
- Step 5
Each part is billed
Operators and gateways charge per part, and the phone reassembles them into one message. A 200-character Hindi text is 3 parts; the same length in plain English would be 2.
04UCS-2 encoding: key facts and limits
- Bytes per character
- 2 (16-bit units)
- One SMS
- 70 characters (140-byte payload)
- Per part when split
- 67 characters (6-byte header per part)
- SMPP data_coding
- 0x08
- Emoji above U+FFFF
- 2 units each (surrogate pair)
- Common accidental triggers
- ’ “ ” – — … ₹, non-breaking space, emoji
- GSM-7 for comparison
- 160 per SMS, 153 per part
05UCS-2 encoding in code
// GSM 03.38 basic set and extension table (extension characters cost 2 septets).const GSM7 = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?" +"¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";const GSM7_EXT = "^{}\\[~]|€\f";export function smsParts(text) {let septets = 0;for (const ch of text) {if (GSM7.includes(ch)) septets += 1;else if (GSM7_EXT.includes(ch)) septets += 2;else {const units = text.length; // UTF-16 code units: an emoji above U+FFFF counts 2return { encoding: "UCS-2", units, parts: units <= 70 ? 1 : Math.ceil(units / 67) };}}return { encoding: "GSM-7", units: septets, parts: septets <= 160 ? 1 : Math.ceil(septets / 153) };}smsParts("Your order has shipped."); // { encoding: "GSM-7", units: 23, parts: 1 }smsParts("Your order’s shipped."); // { encoding: "UCS-2", units: 21, parts: 1 }smsParts("ऑर्डर भेज दिया गया है 🎉"); // UCS-2, the emoji counts as 2 units
In JavaScript, string length already counts UTF-16 units, which is exactly what UCS-2 bills. Gateways never split a surrogate pair or an extension character across parts, so real counts can be one higher at a boundary.
06 · Common mistakes, and the fix
Common mistakes with UCS-2 encoding
Pasting copy from documents
Word processors and chat apps turn quotes into curly quotes and hyphens into dashes. Normalise English templates before registering and sending them, and check the encoding your gateway reports.
Unicode arriving through variables
A GSM-7 template becomes UCS-2 when a variable inserts a Devanagari name, an accented letter outside GSM-7 or an emoji from a product title. Sanitise or transliterate variable values, or budget for the Unicode case.
Counting emoji as one character
Most emoji take 2 of the 70 units, and some combined emoji take far more. Count UTF-16 code units, not visible characters, when estimating parts.
Splitting messages yourself
Cutting text into 67-character chunks in your own code can split a surrogate pair or a conjunct and garble it. Send the full text and let the gateway build the concatenated parts.
07Why does UCS-2 encoding matter?
Encoding is the hidden multiplier on every SMS bill. A marketer who writes a 100-character offer with one emoji pays for two parts per recipient instead of one, and a team sending a lakh of alerts with an accidental curly quote pays for two or three times the segments it budgeted. For OTPs it also breaks Android autofill, which needs the text under 140 bytes. Knowing which characters force UCS-2 lets you choose regional-language SMS on purpose, and stop paying for Unicode nobody meant to send.
08 · Tips from the bench
Best practices for UCS-2 encoding
- Decide per campaign whether a regional language is worth the extra parts, rather than discovering it on the invoice.
- Write the rupee amount as Rs. or INR in English SMS; the ₹ sign alone switches the message to UCS-2.
- Keep OTP and alert templates in plain GSM-7 English and localise the app screens instead.
- Add an encoding check to your template review: flag any non-GSM character in a template meant to be English.
- Use language detection on customer replies to decide when a regional-language SMS is worth its extra parts.