Encoding / Decoding

URL Encode / Decode

Percent-encode or decode URLs.

Encode type:
Original Text/URL
URL Encoded Result
Result will be shown here

What is URL Encoding?

URL encoding (percent-encoding) converts special characters to %XX format. Since URLs can only use ASCII characters, non-ASCII characters and reserved characters must be encoded for safe transmission.

Encoding Methods

  • encodeURIComponent: Encodes URL parameter values, encodes most special characters (recommended for values)
  • encodeURI: Encodes entire URL, preserves URL structure characters (: / ? # @)
  • Full Encode: Encodes all non-alphanumeric characters, strictest encoding

Use Cases

  • Query Parameters: Ensure values don't break URL structure
  • API Requests: Encode special characters in parameters
  • Cross-system Transfer: Ensure data passes correctly between systems
  • Debugging: Decode encoded URLs to see original content

A percent-encoder that rewrites every UTF-8 byte outside the unreserved set as a %XX triplet and decodes such triplets back. Three modes follow the ECMAScript escape rules, and decode mode also splits an absolute URL into protocol, host, path, fragment and query pairs, which helps when assembling query strings, reading encoded links in logs, or repairing double-encoded URLs.

What each mode leaves unescaped

Percent-encoding escapes bytes, not characters: one CJK character becomes three %XX triplets, one four-byte emoji becomes twelve. ECMA-262 fixes the escape set of each function. encodeURIComponent preserves only A–Z, a–z, 0–9 and the nine marks ' ( ) * - . _ ! ~; encodeURI additionally preserves ; / ? : @ & = + $ , #, so a whole URL keeps its structure after encoding. The third mode, labelled Encode all, checks each character against A–Z, a–z, 0–9 and hands everything else to encodeURIComponent — which already leaves those marks alone. Its output is therefore identical to the first mode for every possible input, punctuation included, and it is not stricter in any way.

Why decoding errors out instead of returning mojibake

Decoding applies decodeURIComponent to the entire string. It accepts upper- and lower-case hex digits, then interprets the resulting bytes as UTF-8, so %E5%A4%A9 and %e5%a4%a9 both produce the same character. Any sequence that is not complete valid UTF-8 raises URIError: a trailing %, %zz, a truncated lead byte such as %E4, or a bare %FF. JavaScript throws rather than substituting U+FFFD, which is why the panel shows an error message and not garbage text. Two consequences follow: + stays a plus sign, because only form decoding maps it to a space, and one stray percent sign in ordinary prose such as "50% off" makes the whole string undecodable.

When the URL parse panel appears

The parse panel renders only in decode mode, and only when the input satisfies the absolute-URL grammar accepted by the browser URL constructor. A bare query string like q=%E5%A4%A9 or a relative path throws a TypeError, leaving the panel empty; adding a scheme fixes it. On success it lists protocol, host, path, fragment and each query pair, but never userinfo, and the port stays glued to host. The constructor also normalises what it displays: . and .. segments are resolved, and %7E inside the path is kept encoded. Query pairs come from URLSearchParams, where + becomes a space, even though the main output area keeps it as a plus.

Worked example

Encoding a query value holding CJK text, a space and reserved characters

Input
搜索 天气&lang=zh
Output
%E6%90%9C%E7%B4%A2%20%E5%A4%A9%E6%B0%94%26lang%3Dzh

The input is 21 UTF-8 bytes, so the output is 51 characters: four CJK characters take 3 triplets each (36 characters), the space becomes %20 rather than +, and the literal & and = become %26 and %3D because both are reserved. Encoding the same string with encodeURI would leave those two characters literal, which is exactly how a value encoded that way gets split into two parameters.

Limits and pitfalls

  • The third mode is not stricter than the first: it forwards every non-alphanumeric character to encodeURIComponent, so - _ . ! ~ * ' ( ) still come out unescaped and the result matches mode one byte for byte. If a signer expects RFC 3986 unreserved characters only, escape ! * ' ( ) yourself afterwards.
  • Decode mode always runs decodeURIComponent, so + is never converted to a space; form-encoded strings (a+b) must be normalised before pasting.
  • A single malformed triplet — a stray %, odd hex, or bytes that are not valid UTF-8 — rejects the whole string, and the tool reports only a generic failure with no offset pointing at the bad position.
  • Encoding throws URIError on an unpaired surrogate, which appears when the input was sliced by code unit or came from broken clipboard data; no %XX output is produced at all.
  • The parse panel needs an absolute URL; a bare query string or relative path is rejected by the URL constructor, even though those are the shapes people paste most often.

Related tools

Which mode, and when to leave this page

Your situationThis URL Encode toolWhere to go instead
The value itself contains &, = or ?The default encodeURIComponent mode writes %26, %3D and %3F, so the server still sees one value. The encodeURI mode on the same string leaves those three characters literal, and the value quietly splits into extra parameters at the other end.new URLSearchParams({ q: value }).toString() escapes values and nothing else while you assemble the query. Use it when the string is built from several fields; encode a single finished value here.
The receiving side is a form decoder that expects + for a spaceAll three modes call the encodeURI family, so a space always leaves as %20 and never as + — which is exactly what a raw decoder needs and exactly what a form decoder tolerates, since %20 is valid in both readings.A form encoder writes +: URLSearchParams, application/x-www-form-urlencoded bodies, PHP http_build_query. Choose it when the whole payload is a form; keep %20 whenever the receiver might decode raw.
You want the URL broken into parts, not just turned into readable textThe parse panel is read-only: it lays out protocol, host, path, hash and query pairs as text, keeps the port inside host and drops userinfo, so any correction has to be reassembled by hand outside the page.URL Parser edits the query table and hands a URL back. Read a string here; repair a string there.
The string came from a system that still uses GBK or Shift-JISDecoding always reads the percent bytes as UTF-8. %C4%E3 (你 in GBK) fails that check, so the whole string returns "Invalid URL encoded string"; a byte pair that happens to be valid UTF-8 comes back as the wrong character with no warning at all.python3 -c "import urllib.parse;print(urllib.parse.unquote(s, encoding="gbk"))", or iconv -f gbk -t utf-8. Reach for it as soon as the source predates UTF-8: this page has no encoding selector and cannot guess.
Hundreds of log lines need the same treatmentOne paste per round trip, computed in the tab, with no batch input and no record of what you converted.jq -sRr @uri encodes line by line and leaves only A–Z a–z 0–9 - _ . ~ untouched; python3 -c "import urllib.parse;print(urllib.parse.quote(s, safe=""))" needs that explicit safe="", because quote keeps slashes by default. Verify one line here, then batch.
The destination is an HTML attribute or a JSON string, not part of a URIA < leaves this page as %3C. HTML renders that as the literal text %3C and the parser never sees an angle bracket, so the escaping is real but aimed at the wrong consumer.HTML Entity Encode for &amp; style escaping, JSON String Escape for \" and \n. Percent-encoding wins only when the string ends up in a URI component.

One concrete scenario

Encoding a CJK search term inside a link you are about to paste

The link you are sending is https://example.com/s?q=前端调试工具: 30 characters, but 42 UTF-8 bytes, because the six Han characters cost three bytes each while the 24-character skeleton stays at one byte per character. Encoding only the value with the default encodeURIComponent mode produces 78 characters — the 54 characters of the encoded value plus the untouched skeleton. Sending the whole URL through Encode all produces 90, since :, three /, ? and = each grow from one character to three, and the address bar then treats the result as a search string rather than a URL. So: build the skeleton yourself and encode one value, or paste the finished URL and use the encodeURI mode. Before sending, flip to decode mode and confirm the panel shows a single q pair holding 前端调试工具.

Frequently Asked Questions

encodeURIComponent or encodeURI — which one?
Use encodeURIComponent for parameter values — it encodes =, &, ?, and / so the value cannot break the URL structure. Use encodeURI for a complete URL, since it preserves structural characters (: / ? #). The classic mistake is encoding a value with encodeURI, letting a bare & split it into two parameters.
Should a space be %20 or +?
It depends on the context: inside application/x-www-form-urlencoded (HTML forms and most backend query parsers) a space is +; in RFC 3986 URLs it must be %20, which is what encodeURIComponent produces. When parameters break across systems, + versus %20 confusion is usually the culprit.
Why does decoding produce the � replacement character?
The byte sequence is not valid UTF-8: the content was encoded as GBK but decoded as UTF-8, or the % sequences got double-processed (%2520 → %20 → space). Audit the encoding assumptions along the whole chain; the tool’s strict encoding modes help pinpoint where it breaks.

Content reviewed: