Skip to content

Utility Tools guides

How to Encode and Decode URLs: Percent-Encoding Explained

By · Published · Updated · 5 min read

URL encoding replaces characters that aren’t allowed or have a special meaning in a URL with % and two hexadecimal digits per byte, so a space becomes %20 and & becomes %26. Encode each value you put into a URL, such as a search term, but not the whole address. Decoding reverses it.

A search link for “fish & chips” comes back with results for “fish”. An email link shows caf%C3%A9 where you expected “café”. A redirect URL gets mangled somewhere between two servers. All three come down to URL encoding, and to encoding the right part of the address.

Why do URLs need encoding?

A URL can only contain a limited set of characters, and some of those have jobs. / separates path segments, ? starts the query string, & separates parameters, = joins a name to its value and # starts a fragment. When a value contains one of these, or a space or a character outside ASCII, it has to be written in a form that can’t be confused with the URL’s structure.

Without encoding, ?q=fish & chips is read as a parameter q=fish followed by a second, empty parameter called chips.

How does percent-encoding work?

Each character to encode is turned into its bytes in UTF-8, and each byte is written as % followed by two hexadecimal digits. This is defined in RFC 3986.

  • A space is one byte, 0x20, so it becomes %20.
  • é is two bytes in UTF-8, so café becomes caf%C3%A9.
  • 👋 is four bytes, so it becomes %F0%9F%91%8B.

Letters A–Z and a–z, digits and the four characters - . _ ~ never need encoding. Everything else is either reserved for structure or has to be encoded. The ones you’ll meet most:

CharacterEncodedWhy it matters
space%20Not allowed in URLs
&%26Separates query parameters
=%3DJoins a parameter’s name and value
?%3FStarts the query string
#%23Starts the fragment; never sent to the server
/%2FSeparates path segments
+%2BOften read as a space in query strings
%%25Starts every escape

Encoding a value or a whole URL

This is the distinction that causes most bugs. There are two different jobs:

  • Encoding a value that goes inside a URL, such as a search term, encodes the structural characters too. fish & chips becomes fish%20%26%20chips, so the & can’t start a new parameter. In JavaScript, this is encodeURIComponent().
  • Encoding a whole URL must leave / ? & = # alone, or the address stops working. Only spaces and characters that aren’t allowed are encoded. In JavaScript, this is encodeURI().

Encode each value separately, then assemble the URL: https://example.com/search?q=fish%20%26%20chips. Running encodeURI() on the finished string instead gives ?q=fish%20&%20chips, and the search term is split in two.

Using the encoder

In the URL encoder and decoder, choose “Part of a URL” for a value or path segment and “A whole URL” for a complete address, then paste your text. When decoding form data, turn on “Treat + as a space”. The tool also warns when text is already encoded, so it isn’t encoded twice, and points out broken escapes such as %ZZ.

URL Encoder / Decoder

Percent-encode a value or a whole URL as UTF-8, or decode one, with warnings for double encoding and broken escapes.

Encode or decode a URL

Spaces: %20 or +?

Both appear, for historical reasons. In a URL path, a space is always %20. HTML forms, and functions that build query strings the same way, write spaces in the query as +:

new URLSearchParams({ q: "fish & chips", lang: "en" }).toString()
// "q=fish+%26+chips&lang=en"

Decoders for form data read + as a space; a plain URL decoder leaves it as a plus sign. That’s why a literal plus in a value must be written %2B.

URL encoding in code

  • JavaScript: encodeURIComponent() and decodeURIComponent() for values; URLSearchParams to build or read a query string.
  • Python: urllib.parse.quote() keeps / by default; quote_plus() and urlencode() use + for spaces; unquote() decodes.
  • PHP: rawurlencode() writes spaces as %20; urlencode() writes them as +.

Common mistakes

  • Encoding twice. Encoding hello%20world again gives hello%2520world, because % becomes %25. Encode raw values once, at the point where you build the URL.
  • Encoding a whole URL as a value. https://example.com/a?b=1 becomes https%3A%2F%2Fexample.com%2Fa%3Fb%3D1. That’s right when the URL is itself a parameter, such as a redirect target, and wrong when it’s the address you want to open.
  • Building query strings by joining text. Use URLSearchParams or your language’s equivalent, which encode each value for you.
  • Decoding more than once. Decoding user input repeatedly can turn harmless text into characters your code didn’t expect. Decode exactly once.
  • Mistaking encoding for security. Percent-encoding, like Base64, hides nothing. Anyone can decode it.

Related encodings

URL encoding makes text safe inside a URL. Base64 makes binary data safe as text, and has its own URL-safe variant; see how Base64 works. And if you control the URL, the simplest fix is to need less encoding in the first place: a lowercase, hyphenated slug from the slug generator needs none. The guide to SEO-friendly URL slugs explains how.

Frequently Asked Questions

Which characters don’t need encoding in a URL?

Letters A–Z and a–z, digits 0–9 and the four characters hyphen, full stop, underscore and tilde. Everything else is either reserved for the URL’s structure or must be encoded.

Why does my link break when I paste it into an email or chat?

Some apps end a link at the first space, quotation mark or bracket. Percent-encode those characters before you share the link, so the whole address stays one link.

How do I encode a URL in Excel or Google Sheets?

Both have an ENCODEURL function: =ENCODEURL(A1) percent-encodes the text in A1, much like encodeURIComponent. Neither has a built-in function to decode it again.

Is it safe to put an email address in a URL?

It works once the @ is encoded as %40, but anyone who sees the link can read the address, and it ends up in browser history and server logs. Keep personal data out of URLs where you can.