Skip to main content
SwiftTools

How to URL-Encode Strings and Query Parameters

Published 20 October 2026Guide for the URL Encoder & Decoder

A URL looks like a simple string until it needs to carry a space, an ampersand or a hash - and then the rules kick in. Percent-encoding is how URLs stay unambiguous: reserved characters are written as %XX (their byte in hexadecimal), and everything else is what you type. The skill is encoding the right part, exactly once.

This guide covers which characters need escaping, the encoding contexts that differ (URLs versus form data), and the two bugs that cause most real-world breakage.

Which characters need escaping

URIs have a small set of reserved characters that carry structural meaning: : / ? # [ ] @ ! $ & ' ( ) * + , ; =. Anything else - letters, digits and the "unreserved" symbols - may appear as-is. When a character that carries meaning needs to be data instead of structure, it is written as a percent followed by two hex digits of its byte value: space is %20, & is %26, # is %23, ? is %3F, + is %2B.

The rule that trips people up: encode values, not whole URLs. The = and ? and & that separate parameters must remain real structural characters; only the content of each parameter value gets escaped. Encoding the whole URL produces a string no server can parse.

Query parameter encoding
Search term: "c++ & rust"
Value encoded: c%2B%2B%20%26%20rust   (or c++%20%26%20rust if + may stay literal)
Full URL:    https://example.com/search?q=c%2B%2B%20%26%20rust

The + trap: form encoding is not URL encoding

Two related-but-different conventions share the same name. In generic URI percent-encoding, a space is %20 and a plus sign stays a literal +. In application/x-www-form-urlencoded - the encoding for form submissions and many query strings - a space becomes + and a literal plus becomes %2B.

The consequences are one-directional breakage: a query string sent with + for spaces, read by a server expecting %20, turns every space into a plus. And a + that meant "plus sign" read as form encoding becomes a space. The fix is context-awareness: encode with the convention your target expects, and when in doubt, prefer %20 - it is correct under both conventions.

Double-encoding: the most common real bug

Double-encoding happens when a value is encoded, then treated as plain text and encoded again: the % of %26 becomes %25, and the value arrives as %2526 instead of &. It is visible - a decoded value that still contains %XX sequences - and it usually means two layers of the pipeline each "helpfully" escaped the data (a framework escaping what a library already escaped).

The diagnostic is simple: decode once; if the result still looks encoded, decode again, and then find which layer should have stopped. The cure is always "encode exactly once, at the boundary where text becomes a URL", not "decode defensively at the other end".

Before shipping any URL you construct programmatically:

  1. 1Each parameter value is encoded; the separators (?, &, =) are not.
  2. 2The convention matches the consumer: form encoding for form posts, percent-encoding for links and APIs.
  3. 3Values that are themselves URLs or JSON are encoded as whole values (nesting is legal; the inner URL's own characters are escaped as part of the outer value).
  4. 4You round-trip tested: encode, decode, and confirm you got the original bytes back - including the tricky ones (spaces, &, #, non-ASCII).

Frequently asked questions

Do I need to encode every special character?

No - only characters that are reserved in that context, or that must not be interpreted as structure. Letters, digits and unreserved symbols may stay literal. Over-encoding is legal but ugly; under-encoding is a bug.

Why is my + coming back as a space?

The receiver used form-encoding rules, where + means space. Encode a literal plus as %2B when the context is form-encoded - %2B decodes to + under both conventions.

How do I encode non-ASCII characters?

Percent-encoding operates on bytes: non-ASCII characters are encoded as their UTF-8 byte sequence, each byte as %XX. A single character can become several %XX groups.

Is my input stored anywhere?

No - encoding and decoding run entirely in your browser; nothing is uploaded.

Want to try it?

The URL Encoder & Decoder is free and runs right in your browser (developer tools). Open it now and see the guide in action.

Try the URL Encoder & Decoder