SnippetJavaScript

Read URL query parameters

Wraps URLSearchParams to read single values, all values of a repeated key, and every param as a plain object, from a full URL string.

Last updated

Snippetjavascript
function getQueryParams(url) {
  const params = new URLSearchParams(new URL(url).search);
  return {
    get: (key) => params.get(key),
    getAll: (key) => params.getAll(key),
    entries: () => Object.fromEntries(params),
  };
}

// const q = getQueryParams("https://x.test?tag=js&tag=css&page=2");
// q.getAll("tag") -> ["js", "css"]

How it works

new URL(url).search extracts just the query string (including its leading "?"), which URLSearchParams then parses into an iterable, decoded key/value structure — no manual splitting on "&" and "=", and percent-encoded characters are decoded for you automatically.

The wrapper exposes get, getAll and entries separately because they answer different questions: get() returns only the FIRST value for a key, which silently drops data when a key repeats (as multi-select filters or checkboxes often produce) — getAll() is what you want whenever a key might appear more than once.

Edge cases to know

  • →Object.fromEntries(params) keeps only the last value for any repeated key, since a plain object can't hold two values under one key — use getAll for those, not entries.
  • →This needs a full, absolute URL string because it goes through the URL constructor; in a browser, pass location.href for the current page's params instead of a relative path.
  • →All values come back as strings — "page=2" gives you the string "2", not the number 2, so cast before doing arithmetic on it.

Part by part

new URL(url)
Parses the whole URL and validates it. Passing a relative path throws, which is why a second base argument exists for that case.
new URLSearchParams(new URL(url).search)
Takes just the query string and gives it a proper API — decoding, repeated keys and encoding all handled correctly.
getAll: (key) => params.getAll(key)
Returns every value for a repeated key. get returns only the first, which is the distinction most hand-rolled parsers miss.
Object.fromEntries(params)
A plain object of the parameters, keeping only the last value where a key repeats. Convenient, and lossy for exactly that reason.

Common mistakes

  • url.split("?")[1].split("&").map((p) => p.split("="))

    Breaks on a value containing an encoded equals sign or ampersand, and leaves everything percent-encoded so a space arrives as %20. The platform parser handles all of that.

  • Object.fromEntries(params) on a query with repeated keys

    Silently keeps only the last value, so ?tag=js&tag=css becomes { tag: "css" } and the first tag disappears. Use getAll when a key can legitimately repeat.

  • new URL("/path?a=1")

    A relative URL throws without a base. Pass one as the second argument, or use window.location.href when you only want the current page's parameters.

Questions

How do I read the current page's parameters?

new URLSearchParams(window.location.search) skips the URL parsing entirely, since you already have the query string. That is the common case and needs no wrapper.

Does it decode values automatically?

Yes. URLSearchParams returns decoded values, so a parameter containing %20 arrives with a real space. Do not decode again — double-decoding corrupts any value containing a literal percent sign.

How does it treat a key with no value?

As an empty string rather than null, so ?debug gives "" for that key. Use params.has to distinguish a present-but-empty parameter from an absent one.

Should I trust these values?

No — they are entirely under the visitor's control. Validate types and ranges before using them, and never interpolate one into HTML or a query without escaping.

Related in Snippets