Developer Guides Beginner Friendly

URLs, Encoding, and Query Strings

Percent-Encoding, Base64, and How the Web Passes Data

12 min read • Updated March 2026

Anatomy of a URL

Every URL (Uniform Resource Locator) has a defined structure governed by RFC 3986. Understanding this structure helps make sense of why encoding is necessary and where it applies.

URL breakdown:

https://example.com:8080/path/to/page?name=John+Doe&lang=en#section-2

Scheme: https — the protocol

Host: example.com — the domain

Port: :8080 — optional, defaults to 80 (HTTP) or 443 (HTTPS)

Path: /path/to/page — the resource location

Query string: ?name=John+Doe&lang=en — key-value parameters

Fragment: #section-2 — anchor within the page (never sent to server)

Each component has its own rules about which characters are allowed unencoded. The rules differ between the path, query string, and fragment — which is why URL encoding can be confusing.

Why URLs Need Encoding

URLs can only contain a limited set of ASCII characters. The characters A-Z, a-z, 0-9, and a handful of special characters (-, _, ., ~) are "unreserved" — they can appear in URLs without any encoding.

Other ASCII characters like ?, &, =, /, and # are "reserved" — they have special meaning within the URL structure. If you want to pass a value that contains one of these characters (like a search query containing an ampersand), you must encode it so the server doesn't misinterpret it as a URL delimiter.

Non-ASCII characters — anything outside the basic ASCII range, including letters from non-Latin alphabets, emoji, and accented characters — must always be encoded because they're not part of the original URL specification.

Example of why encoding matters:

Intended: Search for "cats & dogs"

❌ /search?q=cats & dogs

Server sees: q="cats " (parameter ends at &), then "dogs" as unknown second parameter

✓ /search?q=cats%20%26%20dogs

Server correctly receives: q="cats & dogs"

Percent-Encoding Explained

Percent-encoding (also called URL encoding) represents unsafe characters using a percent sign followed by two hexadecimal digits. The hexadecimal value is the UTF-8 byte value of the character.

For example, the space character has the UTF-8 byte value of 32 decimal, which is 20 in hexadecimal — so a space becomes %20. The ampersand (&) has the byte value 38 decimal = 26 hexadecimal, so it becomes %26.

Common percent-encoded characters:

Space → %20
& → %26
= → %3D
+ → %2B
? → %3F
# → %23
/ → %2F
@ → %40
: → %3A
! → %21
" → %22
→ %E2%82%AC

Notice that the Euro sign (€) encodes to three percent-encoded bytes (%E2%82%AC). This is because the Euro sign requires 3 bytes in UTF-8 encoding, so each byte gets its own %XX representation.

The + Confusion

In query strings specifically, a + sign is historically used to represent a space (inherited from HTML form encoding). So q=hello+world and q=hello%20world both mean "hello world" in query strings. However, + outside of query strings is not a space — it's a literal plus sign. This inconsistency causes bugs; using %20 for spaces is unambiguous in all contexts.

Query Strings and Parameters

Query strings are the mechanism for passing parameters to a web server through the URL. They begin with ? and consist of key-value pairs separated by &.

Query string anatomy:

?category=electronics&sort=price_asc&page=2&q=USB+cable

category=electronics — first parameter

sort=price_asc — underscore doesn't need encoding

page=2 — numbers don't need encoding

q=USB+cable — space encoded as +

Reading Query Parameters

In JavaScript, the URLSearchParams API provides a clean way to parse and manipulate query strings:

const params = new URLSearchParams(window.location.search);
const query = params.get('q');       // "USB cable" (already decoded)
const page = params.get('page');     // "2"
const sort = params.get('sort');     // "price_asc"

// Setting parameters
params.set('page', '3');
const newUrl = '?' + params.toString();
// Automatically encodes values properly

URLSearchParams handles all the encoding and decoding automatically — you work with the decoded values and it handles the URL-safe representation.

URL Encoding in JavaScript

JavaScript provides three ways to encode URLs, and choosing the wrong one is a common source of bugs:

encodeURIComponent()

Encodes a value to be used as a component of a URL (like a query parameter value or path segment). It encodes everything except letters, digits, -, _, ., !, ~, *, ', (, ). Use this when encoding individual values to be inserted into a URL.

encodeURIComponent('cats & dogs') // → "cats%20%26%20dogs"

encodeURI()

Encodes a complete URL, preserving URL-structural characters like ?, &, =, /, :, and #. Does NOT encode these structural characters because they're assumed to be intentional parts of the URL structure. Use this when you have a complete URL and only need to encode unsafe characters like spaces or non-ASCII chars.

encodeURI('https://example.com/path with spaces') // → "https://example.com/path%20with%20spaces"

escape() — Deprecated

An old function that should not be used for URL encoding. It uses non-standard encoding for non-ASCII characters and doesn't handle Unicode correctly. Use encodeURIComponent() or encodeURI() instead.

Rule of thumb: When building URLs programmatically, always encode individual parameter values with encodeURIComponent() or use the URLSearchParams API which handles encoding automatically.

What Is Base64?

Base64 is a binary-to-text encoding scheme that represents binary data using only printable ASCII characters. Despite the name, it's not technically URL encoding — but it's frequently used in web contexts and often confused with URL encoding.

Base64 works by taking groups of 3 bytes (24 bits) of binary data and encoding them as 4 ASCII characters from a 64-character alphabet consisting of letters (A-Z, a-z), digits (0-9), and + and /. The encoded output is always 33% larger than the input.

Base64 encoding example:

Input: "Hello, World!" (13 bytes)

Base64: SGVsbG8sIFdvcmxkIQ== (20 characters)

The == is padding added when the input length isn't divisible by 3

Common Uses of Base64

  • Email attachments: MIME encoding uses Base64 to embed binary files in text-based email messages
  • Data URLs: Embedding images directly in CSS or HTML using data:image/png;base64,...
  • JSON web tokens (JWTs): JWT claims are Base64url-encoded (a URL-safe variant)
  • API authentication: HTTP Basic Authentication sends credentials as Base64-encoded strings
  • Storing binary data in text fields: Databases or APIs that only accept text strings can store binary via Base64

Base64 vs. Base64url

Standard Base64 uses + and / which are special characters in URLs. "Base64url" replaces these with - and _, making the encoded string safe to use in URLs without percent-encoding. JWTs use Base64url encoding specifically for this reason.

URL Encoding vs. Base64 — When to Use Which

These two encoding schemes serve different purposes and are commonly confused. Here's a clear decision guide:

Use Percent-Encoding when:

  • • Including user input in a URL (search queries, filter values)
  • • Building URLs programmatically in JavaScript
  • • Encoding form data for GET requests
  • • Any value that will be part of a URL structure

Use Base64 when:

  • • Embedding binary data (images, files) in text-based formats
  • • Working with JWTs or OAuth tokens
  • • HTTP Basic Authentication headers
  • • Embedding small images as data URLs

Neither is encryption

Both URL encoding and Base64 are encodings, not encryption. They are trivially reversible and provide zero security. Never use Base64 to "hide" sensitive data — it provides no protection. For sensitive data, use proper encryption.

Encoding and Decoding Tools