Blog

SMS Character Encoding: GSM-7, Unicode and Message Segments Explained

18 October 2026

Every SMS you send is billed and delivered in segments, not in characters. Two messages that look the same length in your editor can cost one segment or three, depending on which characters you typed. Understanding the encoding rules is the cheapest optimisation available to anyone sending transactional, OTP or bulk traffic.

The two encodings that matter

The SMS standard (3GPP TS 23.038) defines several alphabets, but in practice you will only deal with two:

  • GSM-7 — a 7-bit alphabet containing Latin letters, digits, basic punctuation and a handful of extras such as £, ¥, § and a few accented vowels. Because each character uses 7 bits instead of 8, a single SMS payload (140 bytes) holds 160 characters.
  • UCS-2 / Unicode — a 16-bit encoding used as soon as your text contains even one character outside GSM-7. Each character takes 2 bytes, so a single message holds only 70 characters.

The switch is all-or-nothing. One emoji, one Chinese character, one Turkish ğ or Russian д in an otherwise plain English message and the whole body is re-encoded as Unicode.

How segments are counted

When a message exceeds a single part, it is split into concatenated segments. Each segment carries a small User Data Header (UDH) that tells the handset how to reassemble the pieces, and that header eats into the payload:

  • GSM-7: 160 characters for a single message, then 153 characters per segment once concatenation kicks in.
  • Unicode: 70 characters for a single message, then 67 characters per segment.

This produces the classic surprise: a 161-character GSM-7 message is not "160 + 1". It becomes two segments of up to 153 characters each — and you are charged for two messages. The same happens at 71 characters in Unicode.

Extended GSM characters count double

A small set of symbols is not in the basic GSM-7 table but is reachable through an escape sequence, so each one consumes two character slots:

^ { } [ ] ~ \ | €

A message with five square brackets and a euro sign silently loses several characters of budget. Line breaks also count as one character each, and some systems convert a single newline into carriage return + line feed, costing two.

Emoji can count as two Unicode units

Characters outside the Basic Multilingual Plane — most modern emoji, including skin-tone and flag sequences — are stored as surrogate pairs in UCS-2. A single visible emoji may therefore occupy 4 bytes, i.e. two of your 70 slots. Composite emoji built from several code points can cost even more.

The Turkish (and other national) shift tables

TS 23.038 also defines national language shift tables, including one for Turkish, which allows characters such as ğ, İ, ş to be sent in a 7-bit message instead of forcing Unicode. In theory this keeps a Turkish text at up to 155 characters per segment rather than 70.

In practice, support depends on the operator route and the receiving handset, and behaviour varies from one network to another. Many senders therefore take one of two safer paths:

  • Write the message without special characters (gunaydin instead of günaydın) and stay firmly in GSM-7.
  • Accept Unicode, keep the message short, and budget for 70/67-character segments.

If correct rendering of diacritics matters for your brand, test on real devices across the operators you care about before assuming shift tables will work end to end.

Hidden characters that break GSM-7

Most unexpected Unicode conversions come from copy-pasting text out of word processors, design tools or web pages. The usual suspects:

  • Curly quotes and apostrophes (’ “ ”) instead of the straight ' ".
  • En and em dashes (– —) instead of the hyphen -.
  • Ellipsis (…) instead of three dots.
  • Non-breaking spaces and zero-width characters, which are invisible but very much counted.

A simple normalisation step in your backend — replacing these with ASCII equivalents before sending — often turns a two-segment Unicode message back into one GSM-7 segment.

Practical rules for transactional and OTP traffic

  1. Design OTP texts to fit one segment. A sender name, a short sentence and a 4–6 digit code fit comfortably in 160 GSM-7 characters. Avoid emoji entirely in one-time password messages.
  2. Count on the server, not by eye. Implement the GSM-7 table lookup in your code, or use the segment preview in your sending panel before a campaign goes out.
  3. Watch personalisation fields. A template that fits in 160 characters with the name "Ana" may spill into a second segment with a longer name. Test with your longest realistic values.
  4. Keep links short. Long tracking parameters are the most common cause of accidental second segments.
  5. Remember that pricing follows segments. Message costs vary by destination country and operator, but the multiplier is always the segment count — so the encoding decision is a direct cost decision at scale.

Where this shows up in practice

On the UIPAPP panel and REST API, message length and segment count are calculated from the text you submit, which is why the same campaign body can produce different totals after a small copy edit. If you build messages programmatically, normalising text and validating segment counts before the API call keeps delivery reports and billing predictable.

Encoding is not glamorous, but it is deterministic: once your templates respect the 160/153 and 70/67 boundaries, your SMS volumes stop surprising you.

Create your free account today

Start sending within minutes. Reach us on WhatsApp or Telegram — real humans answer.