Skip to content
FormatKit

Free online URL encoder

URL encode with the right escape set

Type a value and this free encoder shows all four percent-encodings at once, with no account and no limit: encodeURIComponent for a value inside a URL, encodeURI for a whole URL you have already built, form encoding where a space becomes a plus, and strict RFC 3986 for a signature that has to match a server byte for byte. They differ on exactly eighteen printable characters, which is why a value that works in one place breaks in another, and a live table shows exactly which of those characters are in your own input. Everything is converted to UTF-8 first, so é is %C3%A9 and one emoji is four escapes.

  • 100% free
  • No signup
  • Four escape sets
  • RFC 3986 strict mode
  • Live character table

A query value, a path segment or a fragment

encodeURIComponent(value)

All three take the same escape set, because in all three the delimiters : / ? # & = are data rather than structure and have to go.

A whole URL you already built

encodeURI(url)

A finished link that only needs its spaces and non-ASCII cleaned up. Leaves : / ? # & = untouched, which is exactly why it must never be used on a value.

A form field or a POST body

new URLSearchParams({ k: value }).toString()

application/x-www-form-urlencoded, the default encoding of an HTML form. Space becomes +, and ! ' ( ) ~ are escaped where encodeURIComponent leaves them alone.

A signature base string

encodeURIComponent(v).replace(/[!'()*]/g, hex)

OAuth 1.0a, AWS SigV4 canonical requests, and anything else that has to agree with a server byte for byte. RFC 3986 unreserved characters only: A-Z a-z 0-9 - . _ ~

Nothing encoded yet. Type a value, or press Ctrl+V anywhere on this page.

Which characters each set escapes

CharacterComponentWhole URLFormStrict
space%20%20+%20
!exclamation mark!!%21%21
#hash — starts a fragment%23#%23%23
$dollar%24$%24%24
&ampersand — separates pairs%26&%26%26
'apostrophe''%27%27
(open bracket((%28%28
)close bracket))%29%29
*asterisk***%2A
+plus — a space in form encoding%2B+%2B%2B
,comma%2C,%2C%2C
/slash — separates path segments%2F/%2F%2F
:colon — after the scheme%3A:%3A%3A
;semicolon — a legacy pair separator%3B;%3B%3B
=equals — separates name and value%3D=%3D%3D
?question mark — starts the query%3F?%3F%3F
@at — ends the userinfo%40@%40%40
~tilde~~%7E~

Grey means the character is passed through untouched. Every cell is produced by running that one character through the encoder on this page, so the table cannot drift from what the boxes above return. Decoding runs the other way and does not need to know which set produced the string.

How to URL-encode a value

Type the value, choose the panel that matches where it is going, copy.

  1. Type the value, not the URL

    Put in the thing that has to survive being carried by a URL: a search term, a filename, a redirect target, a signature payload. The four panels fill in together as you type, and a paste lands here from anywhere on the page — Ctrl+V, or ⌘V under macOS.

  2. Pick the panel that matches the consumer

    Each panel names the call that produces it and the job it is for. One value inside a URL is the ordinary case; a whole URL you already built is the second panel and the one people reach for by mistake; a form body is the third; a signature base string that has to match a server byte for byte is the fourth. Copy the panel you need.

  3. Check the table when two panels disagree

    The table underneath runs every interesting character through all four encoders and highlights the rows that appear in your input, with a count. It is generated by the same functions that fill the panels, so it cannot drift out of date, and the “only where they disagree” filter cuts it down to the eighteen printable characters the four sets actually argue about.

Technical specifications

Encode sets producedFour at once: encodeURIComponent, encodeURI, the WHATWG form-urlencoded serializer, and RFC 3986 unreserved-only
Characters they disagree aboutExactly 18 of printable ASCII — space ! # $ & ' ( ) * + , / : ; = ? @ ~ — while 12 more, including " % < > and the brackets, are escaped identically by all four
Form encodingSpace becomes +, and only A-Z a-z 0-9 * - . _ pass through; ! ' ( ) ~ are escaped, matching what URLSearchParams.toString() writes
Strict modeKeeps A-Z a-z 0-9 - . _ ~ and nothing else, as RFC 3986 §2.3 defines unreserved — the set OAuth 1.0a and AWS SigV4 canonical requests require
Character handlingText is converted to UTF-8 before encoding, so é is %C3%A9 (2 bytes) and 😀 is %F0%9F%98%80 (4 bytes); escapes are written with uppercase hex digits
Comparison table24 probe characters plus any character from your own input the four sets treat differently, each cell computed by the encoder itself rather than copied from a reference
Maximum input262,144 characters. All four encodings are recomputed on every keystroke, and a value that long is a request body rather than a URL part
Price and processingFree, no signup; nothing is uploaded — the encoding happens in this tab

Frequently asked questions

encodeURI or encodeURIComponent — which one do I want?

encodeURIComponent, unless you are handing it a complete URL. The difference is what each one considers structure: encodeURIComponent escapes the delimiters : / ? # & = + $ , ; @ because it assumes your string is a single value being placed inside a URL, while encodeURI leaves all of them alone because it assumes your string already is the URL and those characters are doing their job. Roughly: build the parts, encode each part with encodeURIComponent, join them; use encodeURI only to tidy up a finished link that has a space or an accent in it.

Why did encoding my URL break it?

Because it was encoded as a value, so the characters that make it a URL were escaped along with everything else. https://example.com/a?b=c comes back as https%3A%2F%2Fexample.com%2Fa%3Fb%3Dc — a perfectly correct escaping of that text, and no longer a link anything can follow. This page detects a whole URL in the box and says so. The one place that escaping is right is when a URL is the value of a parameter in another URL, which is exactly how a redirect or a callback parameter is meant to look.

Why does URLSearchParams escape ! ' ( ) when encodeURIComponent does not?

Because they are two different specifications that were written twenty years apart. encodeURIComponent comes from ECMAScript and follows the older RFC 2396 idea of unreserved characters, which included the six marks ! ' ( ) * ~; the WHATWG URL standard defines the form-urlencoded serializer with a larger escape set and keeps only letters, digits and * - . _ . Both decode back to the same string, so nothing breaks — but if you are comparing your output against what a browser posted, or building a signature the server recomputes, the two will not be byte-identical.

Do I need to encode a slash inside a path segment?

Yes, always, and as %2F. A slash is the segment separator, so a filename like invoices/2026 written raw into a path creates a directory boundary that was never in the data. Encoding it is the correct fix, but be warned that it is only half a fix in production: Apache rejects %2F in a path with a 404 unless AllowEncodedSlashes is turned on, and some proxies normalise the escape back to a slash before your application sees it. Where that bites, the value belongs in the query string instead.

How do I encode a value for an OAuth or AWS signature?

Use the strict panel, the fourth one. RFC 5849 §3.6 requires OAuth 1.0a to percent-encode everything outside the RFC 3986 unreserved set — A-Z, a-z, 0-9 and - . _ ~ — and AWS Signature Version 4 asks for the same when it builds a canonical request. Plain encodeURIComponent leaves ! * ' ( ) unescaped, so a value containing any of those produces a different string from the one the server signs, and the request fails with a signature mismatch that says nothing about which character caused it.

Why does one emoji become twelve characters?

Because percent-encoding works on bytes, and that emoji is four of them. Encoding converts the text to UTF-8 first, then writes each byte that cannot appear literally as three characters — a percent sign and two hex digits. 😀 is F0 9F 98 80, so it leaves as %F0%9F%98%80. The same arithmetic applies further down the scale: é is two bytes and becomes %C3%A9, 東 is three and becomes %E6%9D%B1. Anything that produces a two-character escape for an accented letter is encoding in Latin-1, and the value will not survive a UTF-8 reader.

Should I encode a URL before putting it in a redirect parameter?

Yes — once, with the component set, and then leave it alone. The failure people hit is encoding it twice, usually because one layer of a framework already did it: the target arrives as https%3A%2F%2F… , gets encoded again into https%253A%252F%252F… , and the receiving service redirects to a nonsense address or refuses the request. If you are looking at a value with %25 in front of every escape, that is what happened, and the decoder on the other page unwinds it round by round.

About percent-encoding

RFC 3986 sorts the printable ASCII characters into two named groups and a remainder. Unreserved characters — letters, digits, - . _ ~ — always stand for themselves and must never be escaped, because escaping them changes nothing and breaks comparison. Reserved characters split into gen-delims (: / ? # [ ] @) and sub-delims (! $ & ' ( ) * + , ; =), and these are the interesting ones: each is either syntax or data depending on where it sits, and the specification cannot decide for you. Everything outside both groups — space, quotes, angle brackets, every byte above 127 — has to be escaped wherever it appears.

That “depends where it sits” is the whole reason four encoders exist rather than one. An ampersand between two query pairs is syntax and must stay raw; an ampersand inside a search term is data and must become %26. A slash between path segments is syntax; a slash inside a filename is data. The library functions each hard-code an assumption about which situation you are in: encodeURIComponent assumes everything you gave it is data, and encodeURI assumes the delimiters are structure. Neither is more correct — they are answers to different questions, and picking the wrong one is how a redirect parameter loses its scheme or a query value swallows the rest of the string. Seeing both outputs together, which is what the panels above are for, makes the choice obvious in a way that reading the two function names never has.

The two remaining sets exist because the first two are not strict enough. Form encoding is the format a browser has posted since HTML 2.0 and the one URLSearchParams writes; it turns a space into a plus and escapes ! ' ( ) ~ as well, so its output is not byte-identical to encodeURIComponent even though both decode to the same text. Strict RFC 3986 goes further and escapes every sub-delim, which is what OAuth 1.0a and AWS SigV4 require: a signature is computed over the encoded string, so a single character encoded differently at each end produces a mismatch and a 403 with no explanation. When the string comes back the other way, none of this matters — decoding treats every %XX identically, whichever set produced it, and only the plus sign still needs a decision.

Where the encoding happens

In this tab, character by character, with no request made at any point. The value you type is held in the page's memory for as long as the tab is open and is written nowhere else — no upload, no log, no analytics event carrying its contents. Search terms and signing keys both pass through pages like this one, so the encoder is built not to need the network at all.