Extracting Query Parameters from a URL

Parse URL query strings in JavaScript, Python, Go, and PHP. Extract, read, and modify individual query parameters correctly, including encoded values and repeated keys.

ZERO UPLOAD · ALL LOCAL
  1. Paste any URL into the input box — results appear instantly as you type.
  2. The URL Parts section shows all 17 URL components: scheme, host, pathname, and more.
  3. If the URL has query parameters, they appear in the Query Parameters section below.
  4. Click the circle-? icon next to a known parameter name to see what it does.
  5. Use the Copy buttons next to each property or parameter to grab individual values.

Worked examples for this use case

Parse a query string with repeated keys in JavaScript

Before
// Manual split — loses duplicate tag values
const query = "q=search&page=2&tag=js&tag=python";
const params = Object.fromEntries(new URLSearchParams(query));
console.log(params.tag); // "python" — "js" was lost
After
// Correct: use getAll() for repeated keys
const params2 = new URLSearchParams(query);
console.log(params2.getAll("tag")); // ["js", "python"]

Parse query string with percent-encoded values in Python

from urllib.parse import parse_qs params = parse_qs("q=hello%20world&page=2&tag=python&tag=url") # params["q"] → ["hello world"] (decoded automatically) # params["tag"] → ["python", "url"] (both values preserved)

URL PARTS

href
scheme
protocol
origin
authority
host
hostname
subdomain *
domain *
tld *
port
resource
directory
pathname
filename
search
hash

* Subdomain, domain, and TLD use simple dot-splitting and may be incorrect for two-part TLDs (co.uk, com.au).

QUERY PARAMETERS

Extracting Query Parameters from a URL

Query strings carry data in a URL's searchable component. Every character after the ? and before the # is part of the query string, and most applications rely on individual parameters embedded within it, including page numbers, search terms, filter selections, tracking tokens, and authentication state. Parsing them correctly means handling percent-encoded values, repeated keys, keys with empty values, and the difference between the raw string and its decoded form.

Every language provides at least one standard way to parse a query string without manual splitting. In JavaScript, URLSearchParams handles it.1 In Python, urllib.parse.parse_qs returns a dict of lists. In Go, url.Values carries all parameters. Using these built-in parsers avoids subtle bugs around percent-decoding and delimiter handling that trip up manual string splits.

How query strings are structured

After the ?, parameters follow the format key=value. Multiple pairs are separated by &. The same key can appear multiple times: ?tag=js&tag=python is a valid query string with two tag values. Consequently, any parser that stores results in a plain dict, where each key maps to one string, silently drops duplicate values. For APIs that use repeated keys as arrays, always use a parser that returns a list per key, like parse_qs() in Python or URLSearchParams.getAll() in JavaScript.1 Keys without a value, such as ?flag or ?key=, are also valid and may have distinct meanings. A bare key like ?flag is typically treated as a boolean presence flag, while ?key= represents a key with an empty string value.

Reading and modifying parameters

Reading a single parameter by name is a one-liner in every major language. JavaScript: url.searchParams.get('page'). Python: parse_qs(query)['page'][0]. PHP: parse_str($query, $out); echo $out['page']. Building on this, modifications follow the same API: in JavaScript, url.searchParams.set('page', '2') updates the parameter and url.searchParams.delete('tag') removes it, and the url.href reflects the change immediately.2 For languages without a mutable params object, rebuild the query string from a modified dict using the appropriate encoding function. In Python, calling urlencode() on the updated dict produces a new query string that you can assign to the URL. In Go, modifying the url.Values map and calling its Encode() method returns the updated query string in the correct format.

Edge cases and pitfalls

Percent-encoded values must be decoded before display or comparison: %20 is a space, %2B is a literal +, and + itself means a space in application/x-www-form-urlencoded format but is a literal + in RFC 3986 path contexts.3 Built-in parsers handle this automatically in most runtimes, so manual decoding is only needed when parsing query strings with a custom parser.

Handling keys with empty values versus bare keys

A key with an empty value (?key=) and a key with no value (?key) may both appear in the same query string, and different parsers treat them differently. Some parsers omit bare keys entirely, while others represent them with an empty string or a null value. Test your parser against both cases to confirm which behavior you get, since treating a bare key as a boolean flag while the parser returns an empty string leads to subtle logic bugs.

Parsing query strings in URL fragments for SPA routing

Single-page applications frequently encode route state in the fragment after a secondary hash or in a query string within the fragment. A URL like https://app.example.com/#/dashboard?tab=analytics&date=2026-06 contains the query parameters tab and date inside the fragment, not in the server-visible query string. JavaScript on the page reads window.location.hash to get #/dashboard?tab=analytics&date=2026-06, then parses that string as a query string using new URLSearchParams(hash.split('?')[1]). This pattern lets SPAs maintain navigation state without triggering a full page reload.

Working with nested query parameters across frameworks

Different server frameworks handle nested query parameters with bracket notation differently.4 PHP automatically parses bracket notation into nested arrays so that $_GET['filter']['status'] equals 'active'. Ruby on Rails converts filter[status] into params[:filter][:status] through its routing layer. Java's Servlet API does not parse brackets automatically, requiring a library or manual parsing. Python's parse_qs returns flat keys containing the literal bracket notation unless you post-process them into a nested structure yourself. When building an API consumed by multiple languages, document whether you support bracket notation or prefer dot-notation, and test parsing on each consumer.

Documenting the convention up front saves debugging time because the symptom of a mismatch is usually a silently empty nested field rather than an error. If you control both the client and server, pick one scheme and encode it consistently so the bracket or dot structure survives the round trip intact. When you must accept input from a third party, normalize their format into your internal representation before any business logic touches the parameters.

Query string security: parameter pollution and injection

Watching for HTTP parameter pollution in query strings matters because an application that receives multiple values for the same key but uses only the first or last without documenting which5 lets an attacker who appends ?role=admin to a URL where ?role=user already exists escalate privileges if the application reads the last value. Different frameworks choose differently: PHP uses the last value, Node.js's querystring.parse returns the last value, but URLSearchParams.get also returns the first.6 Building on this, always document which duplicate-value semantics your API uses and validate accordingly.

Preventing query parameter injection in server-side redirects

A server-side redirect that forwards query parameters from the request URL to a redirect target is vulnerable to parameter injection. If your /login endpoint redirects to /dashboard?returnTo=/home&theme=dark and the attacker crafts /login?returnTo=/admin&theme=<script>, the unencoded values flow into the redirect URL. Encoding all user-supplied values with encodeURIComponent() before concatenating them into a redirect URL prevents most injection attacks, but a stronger approach is to use an allowlist of permitted returnTo paths and ignore the user-supplied value entirely if it does not match. CapyToolkit runs all URL parsing examples locally in your browser for safe testing.

When to use this

Use a dedicated query parameter parser whenever your code reads parameters from user-supplied URLs, API responses, OAuth redirects, or webhook payloads, any time the query string may contain encoded characters, repeated keys, or empty values your code did not generate.

Examples

Parse a query string with repeated keys in JavaScript

Before
// Manual split — loses duplicate tag values
const query = "q=search&page=2&tag=js&tag=python";
const params = Object.fromEntries(new URLSearchParams(query));
console.log(params.tag); // "python" — "js" was lost
After
// Correct: use getAll() for repeated keys
const params2 = new URLSearchParams(query);
console.log(params2.getAll("tag")); // ["js", "python"]

Parse query string with percent-encoded values in Python

from urllib.parse import parse_qs params = parse_qs("q=hello%20world&page=2&tag=python&tag=url") # params["q"] → ["hello world"] (decoded automatically) # params["tag"] → ["python", "url"] (both values preserved)

Sources
  1. 1.

    Mozilla Developer Network, "URLSearchParams," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

  2. 2.

    WHATWG, "URL Standard," url.spec.whatwg.org, accessed June 2026. https://url.spec.whatwg.org/

  3. 3.

    "Query string," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Query_string

  4. 4.

    PHP, "parse_str," php.net, accessed June 2026. https://www.php.net/manual/en/function.parse-str.php

  5. 5.

    OWASP, "Testing for HTTP Parameter Pollution," owasp.org, accessed June 2026. https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution

  6. 6.

    Node.js, "Query string," nodejs.org, accessed June 2026. https://nodejs.org/docs/latest-v26.x/api/querystring.html

FAQ