La codificación de URL escribe cada byte no seguro como % y dos dígitos hexadecimales
Una URL puede llevar tal cual letras, dígitos y unos pocos símbolos. Cualquier otro carácter se convierte primero en bytes, y cada byte se escribe como % seguido de dos dígitos hexadecimales. Es la codificación porcentual (percent-encoding), o simplemente codificación de URL. En UTF-8 la letra ñ ocupa dos bytes, así que pasa a %C3%B1, y un espacio pasa a %20 (o a + en el envío de un formulario). Decodificar es el camino inverso: cada %XX vuelve a ser un byte y los bytes se leen como texto.
El mismo texto se codifica distinto según el lugar de la URL donde vaya. Un término de búsqueda que va en un solo valor de la consulta debe codificar también &, =, / y ?, mientras que un texto que ya es una URL completa debe conservar esos separadores o el enlace deja de funcionar. Esta herramienta convierte el cuadro que edites, divide la URL en sus partes y decodifica cada una, y reconoce los valores de sitios antiguos en Windows-1252 y los que se codificaron dos veces. Codificar una URL no es cifrar: cualquiera puede revertirlo.
Cuándo hace falta codificar o decodificar una URL
- Un enlace pegado está lleno de códigos %: un enlace como
/buscar?q=a%C3%B1o+nuevoes difícil de leer en un chat o en un documento. Pégalo en el cuadro codificado y el término de búsqueda y la ruta aparecen como texto normal. - Poner un término de búsqueda o el nombre de un producto en un enlace: si 'Pérez & Hijos' no se codifica, todo lo que sigue a
&se lee como otro parámetro, y el+de 'C++' se lee como un espacio. Codifícalo con la regla «Valor» para que llegue tal como lo escribiste. - Pasar la URL de retorno tras un inicio de sesión o un pago: la URL de
redirect_urioreturnUrldebe codificarse entera; si no, sus propios?y&se mezclan con los de la URL exterior. - Construir la firma de una API: OAuth 1.0 y AWS Signature Version 4 conservan solo los caracteres no reservados de RFC 3986 y escriben el espacio como
%20. Con un solo carácter distinto, la firma no se valida. - Leer registros del servidor y herramientas de analítica: las rutas de las peticiones y las URL de referencia se guardan codificadas. Para saber con qué término de búsqueda llegó una visita hay que decodificarlo.
- Formularios PHP y tiendas antiguas: las páginas servidas en Windows-1252 (a menudo declaradas como ISO-8859-1) codifican 'año' como
a%F1o, y un decodificador UTF-8 no puede leerlo.
Cómo se usa
- Decodificar: pega una URL o un valor con códigos % en el cuadro codificado de la derecha. La herramienta elige una regla según la forma de lo que pegaste (una URL usa «URL entera», un + visible usa «Formulario +») y el texto decodificado aparece en el cuadro de texto original.
- Codificar: escribe el texto en el cuadro de texto original y elige la regla que corresponda al lugar donde irá. Usa «Valor» para un valor de consulta, un nombre de archivo o un destino de redirección; «URL entera» para una URL entera; «Formulario +» para obtener lo mismo que un formulario HTML; y «Estricta» para firmas.
- Mirar el desglose de la URL: si el texto es una URL o una cadena de consulta, la herramienta la divide en esquema, host, ruta, valores de consulta y fragmento, y decodifica cada parte. Si un valor contiene otra URL, «Decodificar esta URL» la abre. Con varias líneas, desglosa la línea donde está el cursor.
- Codificación de caracteres: por defecto es la detección automática. Si los bytes no son UTF-8 válido, la herramienta los lee como EUC-KR, Shift_JIS o Windows-1252, el que encaje, e indica cuál usó. Para codificar para un sitio antiguo, elige tú la codificación.
- Mapa de símbolos y resultados por función: pulsa un símbolo para ver cómo lo cambian las cuatro reglas y por qué. Los resultados por lenguaje y función muestran tu texto procesado con funciones de JavaScript, PHP y Python y marcan los caracteres que difieren de la regla actual. Pulsa una fila para copiar ese resultado.
Cuatro reglas: qué conserva cada una
Cada regla conserva un conjunto distinto de símbolos además de letras y dígitos. Cuando otra herramienta o tu código dan un resultado diferente, casi siempre es por esto.
| Regla | Se conserva (además de letras y dígitos) | Espacio | % existente | Uso · función equivalente |
|---|---|---|---|---|
| Valor | - _ . ! ~ * ' ( ) | %20 | Pasa a %25 | Valores de consulta, segmentos de ruta · encodeURIComponent() de JavaScript |
| URL entera | Separadores : / ? # [ ] @ ! $ & ' ( ) * + , ; = y - . _ ~ (unos pocos cambian según la posición) | %20 | Se conserva | Barra de direcciones, enlaces · el URL Standard del navegador |
| Formulario + | * - . _ | + | Pasa a %25 | Envío de formularios HTML · URLSearchParams, URLEncoder de Java |
| Estricta | - . _ ~ | %20 | Pasa a %25 | OAuth 1.0, firmas de AWS · rawurlencode() de PHP |
Los cuatro caracteres que conserva «Estricta» son los no reservados de RFC 3986, así que codificarlos o no da la misma URL. «Valor» conserva además ! ' ( ) * porque JavaScript sigue el conjunto de no reservados de la norma anterior, RFC 2396; el URL Standard define ese mismo conjunto por separado como su conjunto component.
La regla «Formulario +» coincide con URLSearchParams. Cuando el navegador envía de verdad un formulario HTML, los saltos de línea de un campo de varias líneas se envían como %0D%0A; esta herramienta y URLSearchParams los dejan como %0A (comprobado en Chromium 151).
Símbolo por símbolo
Aquí están los símbolos que más se confunden y cómo los cambia cada regla. La columna «URL entera» muestra la posición de la consulta de una URL http o https. En el mapa de símbolos que está sobre la herramienta puedes pulsar los 35 símbolos.
| Símbolo | Valor | URL entera (consulta) | Formulario + | Estricta | encodeURI() |
|---|---|---|---|---|---|
| Espacio | %20 | %20 | + | %20 | %20 |
| & | %26 | & | %26 | %26 | & |
| = | %3D | = | %3D | %3D | = |
| + | %2B | + | %2B | %2B | + |
| / | %2F | / | %2F | %2F | / |
| ? | %3F | ? | %3F | %3F | ? |
| # | %23 | # | %23 | %23 | # |
| % | %25 | % | %25 | %25 | %25 |
| ~ | ~ | ~ | %7E | ~ | ~ |
| * | * | * | * | %2A | * |
| ' | ' | %27 | %27 | %27 | ' |
| ! | ! | ! | %21 | %21 | ! |
| ñ | %C3%B1 | %C3%B1 | %C3%B1 | %C3%B1 | %C3%B1 |
La regla «URL entera» conserva % para que sobrevivan los códigos %XX que ya existen. A cambio, hay que comprobar que tras un % literal vengan dos dígitos hexadecimales, y por eso la herramienta indica cuántos % de ese tipo encontró. urlencode() de PHP se parece a la regla de formulario pero también cambia * a %2A, y quote() de Python es la regla «Estricta» más / conservada.
%20 y +: cómo se lee un espacio
Escribir el espacio como + es la regla del envío de formularios HTML (application/x-www-form-urlencoded). En una ruta, + es simplemente un signo más. En una consulta puede convertirse en espacio o seguir siendo un más, según la función con la que decodifique quien recibe la URL. Si escribes un más de verdad como %2B y un espacio como %20, el significado es el mismo en todas partes.
| Función | Resultado | + leído como espacio |
|---|---|---|
JavaScript decodeURIComponent() | a+b c+ | No |
JavaScript URLSearchParams | a b c+ | Sí |
PHP urldecode() | a b c+ | Sí |
PHP rawurldecode() | a+b c+ | No |
Python unquote() | a+b c+ | No |
Python unquote_plus() | a b c+ | Sí |
Esta herramienta lee + como espacio solo con la regla «Formulario +». Si decodificas con «Valor» o «Estricta» y queda un +, la línea de estado ofrece el botón «Leer con la regla Formulario +». La regla «URL entera» conserva + para proteger la estructura, y el desglose de la URL decodifica los valores de la consulta con la regla de formulario.
Codificar una URL completa: encodeURI() frente al navegador
encodeURI(), la opción habitual para una URL entera, conserva los separadores pero también codifica % y no trata el dominio de forma especial. La barra de direcciones de un navegador sigue el URL Standard: usa un conjunto distinto para la ruta, la consulta y el fragmento, deja en paz los %XX existentes y convierte un dominio internacional a Punycode. La regla «URL entera» de esta herramienta sigue al navegador.
| Entrada | encodeURI() | URL entera (URL Standard) |
|---|---|---|
https://example.com/a%20b | https://example.com/a%2520b | https://example.com/a%20b |
https://españa.es/ | https://espa%C3%B1a.es/ | https://xn--espaa-rta.es/ |
https://example.com/?q=[1] | https://example.com/?q=%5B1%5D | https://example.com/?q=[1] |
https://example.com/?q=it's | https://example.com/?q=it's | https://example.com/?q=it%27s |
https://example.com/?next=https://b.com/?x=1&y=2 | https://example.com/?next=https://b.com/?x=1&y=2 | https://example.com/?next=https://b.com/?x=1&y=2 |
Como muestra la última fila, ningún método arregla una URL que va sin codificar dentro de un valor, porque la URL exterior lee y=2 como un parámetro propio. Codifica la URL interior por separado con «Valor» y añádela como next=https%3A%2F%2Fb.com%2F%3Fx%3D1%26y%3D2. Cuando la regla «URL entera» encuentra un valor así, la línea de estado te avisa.
Codificación doble y cómo quitar una capa
Si codificas un texto que ya está codificado, % pasa a %25. Así, %20 pasa a %2520; al decodificar una vez vuelve %20, y hay que decodificar una segunda vez para obtener el espacio. Suele ocurrir cuando un framework o una biblioteca HTTP codifica los valores por ti y el código los codifica una vez más. RFC 3986, sección 2.4, también indica que no se debe codificar ni decodificar dos veces el mismo texto.
| Veces | Resultado | Longitud |
|---|---|---|
| 1 | a%C3%B1o%20nuevo | 16 caracteres |
| 2 | a%25C3%25B1o%2520nuevo | 22 caracteres |
| 3 | a%2525C3%2525B1o%252520nuevo | 28 caracteres |
Cuando el cuadro codificado contiene %25 seguido de dos dígitos hexadecimales, la herramienta supone una codificación doble y muestra el botón «Decodificar una capa más». El botón cambia solo %25XX por %XX y no toca los demás separadores. Si el texto original contenía de verdad los caracteres «%20», decodificar otra capa cambia el significado, así que conviene comprobar de dónde viene el valor.
URL antiguas codificadas en Windows-1252
Las URL actuales usan UTF-8 por defecto (RFC 3986, sección 2.5), pero los sitios antiguos de Europa occidental, sobre todo formularios PHP y ASP servidos como ISO-8859-1, envían los valores del formulario con un solo byte. Entonces 'ñ' es %F1 y no %C3%B1. Los navegadores tratan la etiqueta ISO-8859-1 como Windows-1252 (Encoding Standard), que se diferencia sobre todo en el rango 0x80 a 0x9F, como el € en %80. El URL Standard también establece que la consulta de una URL http o https se codifica con la codificación de caracteres de la página, mientras que la ruta es siempre UTF-8.
| Carácter | UTF-8 | Windows-1252 |
|---|---|---|
| ñ | %C3%B1 | %F1 |
| á | %C3%A1 | %E1 |
| é | %C3%A9 | %E9 |
| ¿ | %C2%BF | %BF |
| A | A | A |
Decodificar un valor en Windows-1252 como UTF-8 falla porque un %F1 suelto no es una secuencia UTF-8 válida, y aparece �. La detección automática de esta herramienta prueba primero UTF-8 y, si falla, lee los bytes como EUC-KR, Shift_JIS y Windows-1252 y se queda con la lectura que tenga más caracteres comunes. Para crear un valor para un sitio antiguo, elige tú Windows-1252. Un carácter que no existe en la codificación elegida (un emoji, por ejemplo) se escribe como lo hace un formulario del navegador: como &#número; codificado a %26%23número%3B.
Los nombres de dominio internacionales pasan a Punycode
Un nombre de host nunca se codifica con porcentaje. Según las reglas de nombres de dominio internacionalizados (IDNA), un nombre con eñes, acentos o letras no latinas pasa a un nombre ASCII que empieza por xn-- (Punycode, RFC 3492). La regla «URL entera» convierte así solo el host, codifica la ruta y la consulta como %XX, y al decodificar un nombre xn-- vuelve a mostrar los caracteres originales.
| Dominio | Punycode |
|---|---|
| españa.es | xn--espaa-rta.es |
| café.fr | xn--caf-dma.fr |
| bücher.de | xn--bcher-kva.de |
| 例え.jp | xn--r8jz45g.jp |
En código
// JavaScript
encodeURIComponent('año nuevo & C++'); // a%C3%B1o%20nuevo%20%26%20C%2B%2B
decodeURIComponent('%C3%B1'); // ñ (URIError si hay un % incorrecto)
new URLSearchParams({ q: 'año nuevo' }).toString(); // q=a%C3%B1o+nuevo
new URL('https://españa.example/señal').href; // https://xn--espaa-rta.example/se%C3%B1al
# Python
from urllib.parse import quote, quote_plus, unquote, urlencode
quote('año nuevo', safe='') # a%C3%B1o%20nuevo
quote_plus('año nuevo') # a%C3%B1o+nuevo
unquote('%F1', encoding='cp1252') # ñ
urlencode({'q': 'año nuevo', 'page': 2}) # q=a%C3%B1o+nuevo&page=2
// PHP
rawurlencode('año nuevo'); // a%C3%B1o%20nuevo
urlencode('año nuevo'); // a%C3%B1o+nuevo
http_build_query(['q' => 'año nuevo', 'page' => 2]); // q=a%C3%B1o+nuevo&page=2
// Java
URLEncoder.encode("año nuevo", StandardCharsets.UTF_8); // a%C3%B1o+nuevo
URLDecoder.decode("a%C3%B1o+nuevo", StandardCharsets.UTF_8); // año nuevo
Las funciones de la regla de formulario (URLSearchParams, quote_plus() de Python, urlencode() de PHP, URLEncoder de Java) escriben el espacio como +; para un segmento de ruta o para una firma, usa una función que produzca %20.
Errores frecuentes
- Codificar una URL entera con la regla «Valor»: obtienes
https%3A%2F%2F…, que no se abre como enlace. Usa «URL entera» para arreglar la propia URL, y «Valor» solo cuando la URL va a ser el valor de otra URL. - Dejar & o # dentro de un valor: 'A&B' entrega solo A, y lo que sigue a # nunca llega al servidor. Codifica con «Valor» para obtener
A%26By%23. - C++ llega como 'C' y dos espacios: quien recibe decodifica con la regla de formulario y el
+se dejó sin codificar. EscribeC%2B%2B. - Un valor aparece como %2520: una biblioteca ya lo codificó y el código lo codificó otra vez. Decide en qué único punto se codifica.
- Decodificar un valor en Windows-1252 como UTF-8: el texto sale deformado o con �. Cambia la codificación de caracteres a Windows-1252 y vuelve a decodificar.
- decodeURIComponent se detiene con un error: un valor como '100%' no tiene dos dígitos hexadecimales tras el %, y eso lanza
URIError. Esta herramienta deja ese % como está y muestra su posición.
Límites
- La herramienta solo convierte caracteres. No comprueba que una URL se abra ni que sea segura, y nunca se conecta a la dirección.
- La regla «URL entera» aplica solo los conjuntos del URL Standard para cada componente. No hace el resto de la limpieza que realiza un navegador, como pasar a minúsculas el esquema y el host, resolver
../, quitar el puerto por defecto o añadir / a una ruta vacía. Además, los navegadores difieren en algunos símbolos; Chrome 151, por ejemplo, codifica|en una ruta como%7C. - Las URL que no son http ni https, como mailto:, también se codifican con el conjunto de ruta. El URL Standard tiene una regla propia para la ruta opaca de esas URL, así que el tratamiento del espacio puede diferir.
- La detección automática es una suposición. Los valores cortos y los caracteres poco habituales (caracteres extendidos de CP949, kana de ancho medio en páginas japonesas) pueden leerse con una codificación equivocada, así que elige tú una cuando el resultado parezca erróneo. Como codificaciones antiguas solo se admiten EUC-KR, Shift_JIS y Windows-1252, no EUC-JP ni Big5.
- El desglose de la URL solo lee y copia. Para editar o añadir parámetros de la consulta, usa la herramienta tabla de consulta URL ↔ parámetros. Los resultados por lenguaje y función comparan solo los primeros 4.000 caracteres.
Fecha de referencia: los conjuntos de codificación proceden del URL Standard (versión del 19 de octubre de 2026) y de RFC 3986, las reglas de firma de RFC 5849 y de la documentación de AWS, y el comportamiento de las funciones de la documentación de cada lenguaje, todo comprobado el 22 de octubre de 2026. Los valores de las tablas dieron el mismo resultado en esta herramienta, PHP 8.5, Python 3.14, Node.js 26 y Chromium 151.
Fuentes
- 01WHATWG: URL Standard, Percent-encoded bytesConjuntos fragment, query, special-query, path, userinfo, component y de formulario; codificaciones antiguas y tratamiento de &#número;
- 02WHATWG: application/x-www-form-urlencodedSerialización de formularios (espacio a +) y lectura (+ a espacio)
- 03RFC 3986: Uniform Resource Identifier (URI): Generic Syntax2.1 hexadecimal en mayúsculas, 2.2 reservados, 2.3 no reservados, 2.4 sin doble codificación, 2.5 UTF-8, apéndice B expresión regular
- 04ECMAScript: URI Handling FunctionsDefinición de encodeURI, encodeURIComponent y decodeURIComponent
- 05MDN: encodeURIComponent()Caracteres que se dejan tal cual, URIError con un surrogate suelto
- 06RFC 5849 3.6: OAuth 1.0 Percent EncodingSe conservan solo los no reservados; el resto, en hexadecimal en mayúsculas
- 07AWS: Create a signed AWS API requestUriEncode: solo no reservados, espacio como %20, hexadecimal en mayúsculas
- 08PHP: urlencodeCodifica todo salvo -_. y escribe el espacio como +; rawurlencode sigue RFC 3986
- 09Python: urllib.parse.quoteConserva _.-~, safe vale '/' por defecto, quote_plus escribe el espacio como +
- 10Java: URLEncoderConserva . - * _, espacio como +, se recomienda UTF-8
- 11RFC 3492: PunycodeLos nombres xn-- de los dominios internacionalizados
- 12WHATWG: Encoding StandardLectura de EUC-KR (con CP949), Shift_JIS y Windows-1252
Preguntas frecuentes
¿Qué son codificar y decodificar una URL?
Codificar una URL es escribir cada byte de un carácter que no puede aparecer en ella como % seguido de dos dígitos hexadecimales, y decodificar es volver de esa notación al carácter. En UTF-8, ñ ocupa 2 bytes, así que pasa a %C3%B1, y al decodificar vuelve a ser ñ. Es una notación, no un cifrado, así que cualquiera puede revertirla.
¿En qué se diferencian encodeURI y encodeURIComponent?
encodeURIComponent está pensada para un solo valor, así que también codifica separadores como & = / ? # :, mientras que encodeURI está pensada para una URL completa y los deja tal cual. Por eso, si codificas el término 'A&B' con encodeURI, el & se queda y el valor se parte en dos. encodeURI además convierte un %20 existente en %2520, así que para una URL completa es más seguro usar la regla «URL entera» de esta herramienta (URL Standard).
¿El espacio es %20 o +?
Se usan los dos. En rutas y en la mayoría de los valores es %20, mientras que el envío de formularios HTML y URLSearchParams escriben el espacio como +. Al decodificar también hay diferencias: decodeURIComponent, rawurldecode de PHP y unquote de Python dejan + como está, y URLSearchParams, urldecode de PHP y unquote_plus de Python lo leen como espacio. Si escribes un más real como %2B y el espacio como %20, no hay dudas.
¿Por qué % pasa a %25 y aparece como %2520?
Porque un texto que ya estaba codificado se codificó una vez más. % marca una codificación, así que un % literal pasa a %25 y %20 pasa a %2520. RFC 3986 también indica que no se debe codificar ni decodificar dos veces el mismo texto. Si un valor pegado en el cuadro codificado muestra %25, el botón «Decodificar una capa más» lo va quitando capa por capa.
El texto decodificado sale deformado o con �. ¿Por qué?
Lo más probable es que el valor se haya creado con una codificación de caracteres distinta de UTF-8. Los sitios antiguos de Europa occidental solían escribir ñ como %F1 en Windows-1252, y leerlo como UTF-8 da texto ilegible. Cuando el valor no es UTF-8 válido, esta herramienta lo lee como EUC-KR, Shift_JIS o Windows-1252, el que encaje, y también puedes elegir la codificación tú.
¿Los nombres de dominio internacionales también se codifican con %?
No. Un dominio no se codifica con porcentaje; se convierte a Punycode, un nombre ASCII que empieza por xn--. Por ejemplo, españa.es pasa a xn--espaa-rta.es. La regla «URL entera» convierte a Punycode solo el dominio y codifica como %XX los caracteres no ASCII de la ruta y de la consulta.
¿Cómo pongo una URL dentro de la consulta de otra?
Codifica la URL interior entera con la regla «Valor» y añádela. https://b.com/?x=1&y=2 pasa a https%3A%2F%2Fb.com%2F%3Fx%3D1%26y%3D2, así que, puesta detrás de redirect=, la URL exterior no lee sus & ? # como separadores. En el desglose de la URL puedes abrir con «Decodificar esta URL» una URL que esté dentro de un valor.
¿Se envía al servidor la URL que introduzco?
No. Codificar, decodificar, el desglose de la URL y la conversión de dominios se calculan dentro de este navegador. El texto que introduces no se envía ni se guarda, y tampoco queda en la dirección de la página. Aunque una URL contenga una contraseña o un token, no sale de esta página.