URL Encoder & Decoder

Percent-encode text for URLs, decode it back, and take a URL apart into its pieces.

As one value in a URL

Escaped the way encodeURIComponent does: the marks that mean something in a URL, like &, = and /, become escapes too.

As a whole URL

Escaped the way encodeURI does: the marks that shape the URL itself, like ://, ? and &, stay readable.

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Pick Encode, Decode or Take a URL apart; the box keeps its text when you switch. Results update as you type, and nothing is uploaded.

  • Encode shows As one value in a URL, escaped the way encodeURIComponent does, and As a whole URL, escaped the way encodeURI does. Each has a Copy button.
  • Decode shows Decoded, with a + left as a plus. If the text holds a +, As a form sends it reads each one as a space.
  • Take a URL apart lists the Scheme, User, Password, Host, Port, Path, Path segments and Fragment (none when missing), then Query pairs, in order, decoded, with (empty) for a missing value.

A broken escape shows an error naming it and its position in the box.

Examples

A search term, with Encode: C++ & Rust

As one value in a URL   C%2B%2B%20%26%20Rust
As a whole URL          C++%20&%20Rust

Only the first is safe after ?q=. Taking https://example.com/search?q=C++%20&%20Rust apart shows why: q is C and three spaces, and Rust becomes its own key.

A form-encoded query string, with Decode:

q=caf%C3%A9+au+lait&note=50%25+off
Decoded               q=café+au+lait&note=50%+off
As a form sends it    q=café au lait&note=50% off

%C3%A9 is the two UTF-8 bytes of é, and %25 is a literal percent sign.

A product search URL, with Take a URL apart:

https://shop.example.com/search/men%27s%20shoes/?q=running+shoes&size=10&size=11&sort=#reviews
Scheme          https
User            none
Password        none
Host            shop.example.com
Port            none
Path            /search/men%27s%20shoes/
Path segments   search / men's shoes / (empty)
Fragment        reviews

Key     Value
q       running shoes
size    10
size    11
sort    (empty)

Both size values are kept, and the trailing slash leaves an empty last segment.

A stray percent sign, with Decode: price=50%+off

The error is The percent sign at character 9 ("%+o") isn't an escape: an escape is a % and two hex digits, like %20. The % should have been %25.

Good to know

  • Percent-encoding is defined by RFC 3986. An escaped character becomes its UTF-8 bytes, each written as % and two hex digits: 💧 is %F0%9F%92%A7. Hex is case-insensitive: Caf%c3%a9 decodes to Café.
  • encodeURIComponent leaves ! ' ( ) * unescaped, though RFC 3986 counts only letters, digits, -, ., _ and ~ as unreserved. OAuth 1.0 (RFC 5849) and AWS Signature Version 4 need them escaped.
  • encodeURI can’t protect a value. It leaves ; / ? : @ & = + $ , # alone, yet escapes square brackets: http://[2001:db8::1]:8080/a b becomes http://%5B2001:db8::1%5D:8080/a%20b.
  • + means a space only in a query string. The rule comes from HTML forms (application/x-www-form-urlencoded), not RFC 3986. Take a URL apart applies it to the query but not the path; As a form sends it applies it to the whole text. A literal plus in a value must be sent as %2B.
  • The query is split on & before decoding, so redirect=https%3A%2F%2Fother.com%2F%3Fx%3D1%26y%3D2 stays one pair whose value is https://other.com/?x=1&y=2.
  • A # ends the query, so in /a?q=1#b?c the fragment is b?c. Scheme, host, port and Path are shown as written; the rest is decoded.
  • A name and colon are a scheme unless a port follows. RFC 3986 reads name: as a scheme; here digits up to 65535, then / or the end, make a host and port instead, as in localhost:3000/api. tel:112 stays a scheme: tel, mailto, sms, urn and data never take a host.
  • [email protected]:owner/repo.git is not a URL but the scp-like form git uses over SSH: user git, host github.com, path owner/repo.git, with a note. A port is digits, so ssh://[email protected]:owner/repo.git is an error naming both forms git takes.
  • A URL that starts with // has a host but no scheme: //cdn.example.com/lib.js gives host cdn.example.com and path /lib.js. RFC 3986 calls it a network-path reference, which takes the page’s scheme.
  • Decoding is strict. Every % needs two hex digits and the bytes must be valid UTF-8, so %E2%82 (two of the three bytes of €) is rejected. Take a URL apart trims surrounding whitespace; the other modes keep it, so a trailing line break encodes as %0A. Input is limited to 20,000 characters.

Questions

How do I URL-decode a string?

Choose Decode and paste it: each %XX escape becomes its character. In JavaScript, decodeURIComponent(s) does the same; for a form-encoded query, turn + into a space first or use URLSearchParams. Python has urllib.parse.unquote and unquote_plus.

What is the difference between encodeURI and encodeURIComponent?

encodeURIComponent escapes every mark with a meaning in a URL, including / ? & = + #, so it’s for one query value or path segment. encodeURI leaves them alone, so it only fits a complete URL.

Should a space be %20 or + in a URL?

Use %20: it’s a space anywhere in a URL, while + is one only in a form-encoded query string, the way HTML forms and URLSearchParams write it.

How do I parse a query string?

Choose Take a URL apart and paste the URL, or just the query starting with ?: every pair is listed decoded, in order. In JavaScript, new URL(href).searchParams.getAll('size') returns every value of a key. Python’s urllib.parse.parse_qsl(query, keep_blank_values=True) keeps order and sort=.