URL Encoding Percent Guide: Both JavaScript Functions, Verified Side by Side

A link breaks because one space or one ampersand in a query value was sent

raw. You reach for an encoder, discover two JavaScript functions with

similar names, and now the bug depends on which one you picked. We ran both

functions on the same inputs and documented where their outputs diverge and

where decoding throws.

What percent-encoding replaces

The rule is short. Every byte outside the unreserved set, letters, digits,

dash, dot, underscore, tilde, becomes a percent sign followed by two

hexadecimal digits. One character can become several percent groups, because

encoding works on UTF-8 bytes. We verified the three cases people hit first:

input encoded

hello world hello%20world

Q&A session Q%26A%20session

café & crème? caf%C3%A9%20%26%20cr%C3%A8me%3F

The space becomes %20. The ampersand becomes %26. The é is two bytes in

UTF-8, so it becomes %C3%A9. The question mark becomes %3F. These mappings

are byte-level facts, so they are identical in every correct implementation.

The two functions and the one rule for choosing

Our tool shows both outputs at once for a reason. The labels in the code are

aggressive for encodeURIComponent and mild for encodeURI, and the difference

shows up the moment your input contains structure characters:

input: https://example.com/search?q=hello world&lang=en#nav

encodeURIComponent

https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dhello%20world%26lang%3Den%23nav

encodeURI

https://example.com/search?q=hello%20world&lang=en#nav

The aggressive form encodes the colons, slashes, question mark, ampersands,

and hash, because it assumes your text is data. The mild form encodes only

the space, because it assumes your text is already a URL.

That assumption is the choosing rule. Use encodeURIComponent on each

parameter name and value before you assemble a query string. Use encodeURI

only when you have a complete, already-structured URL and want to clean up

stray unsafe characters. Encode values, never re-encode an assembled URL,

and never build a query string by concatenating raw user text.

The ampersand is the character that causes the most damage. Send

q=Q&A session unencoded and the server reads a second parameter named

A session with no value. Our first sample shows the fix: %26.

Double encoding, the bug that hides until production

The percent sign itself is not in the unreserved set, so it encodes to %25.

Run an encoder over text that is already encoded and every existing escape

grows a second layer. We verified both directions:

already encoded Q%26A session %20

encoded again Q%2526A%20session %2520

decoded once Q%26A

The double-encoded string looks healthy and decodes without an error, which

is what makes it dangerous. The server receives the literal text %26 instead

of an ampersand and every comparison against the expected value fails.

The rule is structural. Encode once, at the boundary where raw text becomes

a URL, and never re-encode a string that already contains percent groups.

If a value arrives containing %25 followed by two hex digits, decode it once

and inspect the result before you use it.

Decode errors are data, not noise

Decode mode runs decodeURIComponent on your paste. Two input classes throw

URIError with the message "URI malformed", and the tool catches the throw

and shows its invalid string message instead of output.

1. A stray percent sign. The string 100% does not decode, because % starts

an escape and 0% is not one.

2. A truncated multi-byte sequence. The fragment %E2%82 is two of the three

bytes of a euro sign, so it throws before producing partial text.

Both errors are useful. A throw tells you the paste came from a system that

already decoded once, or that the string was cut mid-copy. Fix the source,

then decode again.

The plus sign trap

Forms submit spaces as plus signs in the application/x-www-form-urlencoded

format. Percent-encoding does not. We verified that

decodeURIComponent("a+b") returns a+b with both plus signs intact.

If you decode a form-submitted value and the output still contains plus

signs where spaces belong, you decoded with the wrong family. Search query

parameters in URLs use %20. Reach for decodeURIComponent for URL work, and

use form-specific decoding when the byte stream came from an HTML form post.

One annoyance documented in the code

Switching between the Encode and Decode tabs clears the input. The state

reset is intentional, but it costs you your paste when you want to encode a

string and immediately decode the result to compare. Keep the source text in

a scratch buffer until you finish the round trip.

Steps to fix a broken URL

1. Isolate the failing part. Load the URL in a browser and read the value

the server actually received.

2. Identify the character class in that value: space, ampersand, hash,

non-ASCII text.

3. Encode each parameter value with encodeURIComponent and reassemble the

query string.

4. Decode the result with decodeURIComponent and compare against your

source text. A throw means step 3 skipped a value.

5. Check for plus signs in the decoded output. Any survivor means the data

passed through form encoding somewhere upstream.

Checklist before you ship a URL with user data

  • Every parameter value encoded with encodeURIComponent.
  • Ampersands inside values sent as %26, never raw.
  • Spaces sent as %20, and plus signs only where form encoding is explicit.
  • Non-ASCII characters expected as multi-byte %C3%A9 style groups.
  • A decode round trip applied once as a test.

If you have a URL that one encoder fixes and the other breaks, the pair of

outputs is worth keeping as a regression case. Compare the aggressive and

mild forms for your own strings in the URL encoder at

https://webrecast.com/en/url-encoder