URL Query Parameters: When to Encode a Value and When Not To
Why this matters: the real problem with query values
Developers and site owners routinely build links that include query parameters: tracking tags, filters, user state, or return URLs. Small mistakes in how you encode those values can break analytics, open security holes (open-redirects), or produce confusing data when values contain &, +, spaces, or non-ASCII characters. This guide explains when to percent-encode a value and when not to, how repeated parameters work, what “+” means, and how to safely handle untrusted destinations. Read it to avoid subtle bugs and to debug query-string issues quickly.
URL anatomy overview
Before digging into encoding rules, recall URL components. A full URL like
https://example.com/path/to/page?search=blue+shirt&utm_source=newsletter#section
breaks down into the following parts:
- Scheme:
https - Authority (host + optional port):
example.com - Path:
/path/to/page - Query string:
search=blue+shirt&utm_source=newsletter - Fragment:
section
Query string vs. path vs. fragment
Encoding rules differ by component: characters allowed in the path are not the same as in the query. The query string is where key=value pairs live, separated by ampersands. The fragment is client-side and typically not sent to the server.
When to encode query values
Rule of thumb: always percent-encode characters in a query value that have a special meaning in the query syntax or that can change semantics or structure of the URL. That includes: &, =, ?, #, and whitespace. If a value will be inserted into a URL literal, use a proper encoder like JavaScript’s encodeURIComponent or URL-safe libraries which percent-encode non-safe characters.
Encoding preserves literal value. For example, a value of rock & roll should be encoded so the ampersand doesn’t start a new parameter.
Plus signs, spaces, and application/x-www-form-urlencoded
One confusing detail: in HTML forms submitted as application/x-www-form-urlencoded, space characters are encoded as +. But in RFC 3986 percent-encoding, spaces are encoded as %20. JavaScript’s encodeURIComponent produces %20 for space; it does not produce a +. Many servers and libraries accept both, but you must know which encoding your tooling uses.
Key points:
- Forms often use
+for spaces when generating the body for HTTP requests with form encoding. - encodeURIComponent produces percent-encoding (
%20), not plus signs. - When parsing a query string with libraries, some parsers convert plus to space automatically; others do not.
Repeated parameters: how to represent arrays
Repeated keys are common. You can represent arrays in query strings in several common ways:
- Duplicate keys:
tag=red&tag=blue - Indexed:
tag[0]=red&tag[1]=blue - Comma-separated:
tags=red,blue
Each format has trade-offs. Duplicate keys are unambiguous in transmission but require server-side code to merge multiple values into an array. Comma-separated lists are compact but require parsing and careful encoding (commas in values must be encoded). Pick the convention used by your backend and document it.
Analytics tags and tracking parameters
Tracking tags (utm_source, utm_medium, gclid, etc.) are ordinary query parameters. Treat them like other values: encode any special characters inside the parameter values. Avoid placing multiple tracking systems under the same name unless you intentionally want them to collide.
Be careful when constructing tracking URLs programmatically; a common bug is failing to encode the value for utm_campaign and hence truncating or mis-parsing downstream analytics.
Building and debugging query strings
Use structured builders instead of manual string concatenation. Native APIs like URL and URLSearchParams (in browsers and Node.js) help avoid mistakes. When you must manually build, always run values through an encoder.
Example: building with encodeURIComponent
// JS: manual construction (safe)
const base = 'https://example.com/search';
const params = {
q: 'rock & roll',
page: 2
};
const qs = 'q=' + encodeURIComponent(params.q) + '&page=' + encodeURIComponent(params.page);
const url = base + '?' + qs;
// Result: https://example.com/search?q=rock%20%26%20roll&page=2
Example: using URLSearchParams
// JS: modern API
const url = new URL('https://example.com/search');
url.searchParams.append('q', 'rock & roll');
url.searchParams.append('page', '2');
console.log(url.toString());
// Result: https://example.com/search?q=rock+%26+roll&page=2 (some implementations show + for spaces)
Debugging walkthrough (ordered workflow)
- Reproduce the problem with a concrete example URL.
- Isolate the query string: separate the part after the first
?and before any#. - Decode the query using a reliable decoder to reveal percent-encoded bytes or plus signs. (Use URL Encoder and Decoder for quick decoding of values.)
- Split pairs by
&and ensure each pair has at most one=, decoding names and values separately. - Check how the server or client parses repeated keysโdoes it keep the last value, first value, or build an array?
- Fix by re-encoding the appropriate component (name or value) and test again.
Quick checklist before shipping links
- Encode all query values that may contain special characters.
- Do not double-encode values.
- Use structured builders (URL, URLSearchParams) where possible.
- Document your convention for repeated parameters.
- Validate any user-supplied destination URLs against an allowlist or hostname rules.
Markdown-style examples table
Below is a compact mapping of a few sample raw values to common encodings.
| Raw Value | Percent-encoded | Form-encoding (spaces โ +) |
|---|---|---|
| rock & roll | rock%20%26%20roll | rock+%26+roll |
| name=alice&role=admin | name%3Dalice%26role%3Dadmin | name%3Dalice%26role%3Dadmin |
| 100% sure | 100%25%20sure | 100%25+sure |
Common mistakes
- Not encoding ampersands or equals inside values โ causes extra key/value pairs.
- Assuming
+is always a literal plus โ some parsers decode it to space. - Double-encoding โ encoding an already encoded string leads to
%25sequences. - Manually concatenating query strings without an encoder โ fragile and risky.
- Trusting user-supplied redirect URLs without validation โ opens open-redirect vulnerabilities.
Limitations and privacy considerations
Online encoder/decoder tools are convenient, but avoid pasting secrets, API keys, passwords, or personal data into public utilities. If you use a web-based decoder, assume the paste could be logged. Also note that these tools typically perform only encoding/decoding and parsing; they do not validate hostname safety, detect phishing, or guarantee that a URL is safe to redirect to.
When building or debugging, perform sensitive work in local tooling or trusted environments. If a utility provides a pasteboard or share feature, check privacy policies.
Tools: what they can and cannot do
Use small utilities to accelerate tasks, but understand their scope:
- URL Encoder and Decoder โ Quickly percent-encode or decode strings and convert between
%XXbytes and readable text. It helps you see whether a space is%20or+. It cannot parse complex query semantics for your backend and should not be used with private keys or PII. - Query String Parser and Builder โ Parse a query string into a structured object and build one back from fields. It can show repeated keys, bracketed notations, and create properly-encoded output. It cannot enforce server-side conventions or validate redirect destinations; it only builds syntactically correct query strings.
Safe handling of untrusted destinations
If your application accepts a destination URL (for example, a return URL after login), validate before redirecting.
- Prefer an allowlist of hostnames or origins; match exact host + port where possible.
- Reject or canonicalize URLs that use unusual schemes (
javascript:,data:, etc.). - Normalize by parsing the URL, resolving relative paths, and ensuring the decoded query doesn’t inject control characters.
Example: simple hostname check in Node.js
// Node.js: simple allowlist check
const allowed = new Set(['example.com', 'example.org']);
function isSafeRedirect(urlString) {
try {
const u = new URL(urlString);
return allowed.has(u.hostname);
} catch (e) {
return false;
}
}
FAQ
Q: Should I use plus signs or percent-encoding for spaces?
A: Use percent-encoding (%20) when you control URL generation with standard encoders (encodeURIComponent). Use + only if you need to produce application/x-www-form-urlencoded bodies or if the consumer expects form-encoding. Avoid mixing the two without clear expectations.
Q: Are duplicate parameters allowed and which format is best?
A: Yes, duplicate parameters are allowed. Choose a convention your backend supportsโduplicate keys are simple and unambiguous during transport. Bracketed or comma-separated formats may be more convenient for certain frameworks but require consistent parsing on the server.
Q: Can I safely paste URLs with tracking parameters into online tools?
A: Be cautious. Tracking parameters may contain PII or session information. If uncertain, strip sensitive values first or use local tools.
Sources
Editorial note: This guide is an educational overview. Confirm the output against the documentation and workflow that apply to your project.
