Saltar al contenido
nvíame
Capítulo 4 de 510 min14 oct 2026

Codificación GSM vs UCS-2 y caracteres

Por qué una tilde puede duplicar el costo de tu campaña y cómo evitarlo.

Un SMS transporta 140 bytes de carga útil. Cuántos caracteres caben en esos bytes depende de la codificación, y es la razón por la que dos mensajes de apariencia idéntica pueden costar distinto.

Dos alfabetos

  • GSM-7: 7 bits por carácter → 160 caracteres por segmento. Incluye letras latinas básicas y algunas acentuadas.
  • UCS-2: 16 bits por carácter → 70 caracteres por segmento. Soporta cualquier carácter Unicode del plano básico, incluidos emojis simples.

Basta un carácter fuera del alfabeto GSM —una á, una comilla tipográfica “, un emoji— para que el mensaje completo se codifique en UCS-2.

Mensajes concatenados

Cuando el texto excede un segmento, se divide en partes con una cabecera UDH de 6 bytes que permite reensamblarlo. Eso reduce la capacidad: 153 caracteres por parte en GSM-7 y 67 en UCS-2. Cada parte se cobra como un SMS.

Normalizar antes de enviar
+const normalize = (s) => s
+ .replace(/[“”]/g, '"')
+ .replace(/[—–]/g, "-")
+ .normalize("NFD").replace(/[\u0300-\u036f]/g, "");
+
await mx.sms.send({
to,
− text: "Tu código es 4821 — válido por 5 minutos “no lo compartas”",
+ text: normalize("Tu código es 4821 — válido por 5 minutos “no lo compartas”"),
});
Mostrando: antes · haz clic para alternar

Calcula antes de enviar

Implementa una función segments(text) que detecte la codificación y devuelva el número de partes. Muéstrala en el editor de plantillas de tu equipo: es la forma más barata de evitar sorpresas en la factura.

Calcula segmentos antes de enviar

Este playground cuenta segmentos con la misma regla que aplican los operadores: si el texto cabe en el alfabeto GSM-7, cada segmento admite 160 caracteres (153 si el mensaje se divide); si contiene un solo carácter fuera de él, todo pasa a UCS-2 con 70 caracteres (67 concatenados). Cambia el texto y mira cómo un emoji duplica el costo.

// Count SMS segments the way carriers do
const GSM = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";

function segments(text) {
  const gsm = [...text].every((ch) => GSM.includes(ch));
  const len = [...text].length;
  const single = gsm ? 160 : 70;
  const multi = gsm ? 153 : 67;
  const n = len <= single ? 1 : Math.ceil(len / multi);
  return { encoding: gsm ? "GSM-7" : "UCS-2", len, n };
}

const texto = "Tu despacho llegará mañana entre 9 y 13 h. Gracias por comprar 🙌";
const s = segments(texto);
console.log(s.encoding, "·", s.len, "caracteres ·", s.n, "segmento(s)");

const limpio = texto.replace(" 🙌", "").replace("á", "a");
console.log("Sin emoji:", JSON.stringify(segments(limpio)));
await mx.sms.send({ to: "+56912345678", text: limpio });

Fíjate en que la ñ sí pertenece a GSM-7, pero la á no: el alfabeto se diseñó en Europa y cubre solo algunas vocales acentuadas. Por eso muchos equipos normalizan tildes en mensajes transaccionales y las conservan solo cuando la marca lo exige.

Se completa automáticamente al leer el 80%.

Comentarios (3)

Matías Herrera14 oct 2026

¿La ñ y las vocales con tilde fuerzan UCS-2?

Equipo nvíameAutor14 oct 2026

Depende: el alfabeto GSM 03.38 incluye é, ñ, Ñ, ü, à, ò y algunas más, pero no á, í, ó ni ú. Un solo carácter fuera del alfabeto pasa todo el mensaje a UCS-2.

Camila Rojas14 oct 2026

Lo apliqué en el proyecto del trabajo. La sección «Codificación GSM vs UCS-2 y caracteres» me ahorró una discusión larga con el equipo: ahora tenemos un criterio compartido.

Sofía Castillo14 oct 2026

¿Hay alguna diferencia importante si lo implemento en un servicio con varias instancias detrás de un balanceador?

Equipo nvíameAutor14 oct 2026

Sí: todo estado que hoy vive en memoria (contadores, sesiones, claves vistas) debe moverse a un almacén compartido con TTL, como Redis. Si no, cada instancia ve solo una parte de la historia.

Los comentarios se guardan solo en este navegador.