A URL query string can carry search terms, filters, pagination settings, and other values between pages. In JavaScript, reading or changing those values by splitting strings manually is easy to get wrong: parameters can repeat, values can contain encoded characters, and URLs may include a hash fragment. This JavaScript URLSearchParams tutorial shows how to handle query parameters with the built-in URL APIs, with examples you can adapt in a browser or Node.js.
Key takeaways
- Use
new URL()to parse a complete URL and access its.searchParams. - Use
URLSearchParamsdirectly when you already have a query string. - Use
get()for one value andgetAll()for repeated values. - Use
set()to replace a parameter,append()to add another occurrence, anddelete()to remove a parameter. - Validate parameter values before relying on them; parsing a URL does not make its contents trustworthy.
Parse a URL and read its parameters
A query string is the part of a URL after ?. URL parses a complete URL, while its searchParams property gives you a URLSearchParams object for the query string.
const url = new URL("https://shop.example/products?category=books&page=2");
console.log(url.searchParams.get("category")); // "books"
console.log(url.searchParams.get("page")); // "2"
console.log(url.searchParams.has("sort")); // false
get() returns the first matching value, or null if the parameter is absent. Query parameter values are strings, so convert them when your code needs a number or another type:
const url = new URL("https://shop.example/products?page=2");
const rawPage = url.searchParams.get("page");
const page = rawPage === null ? 1 : Number(rawPage);
console.log(page); // 2
This conversion handles a missing value, but it does not validate every possible input. For example, Number("not-a-number") produces NaN; check ranges and formats before using input in application logic.
If you have only a query string, pass it to URLSearchParams. A leading ? is optional:
const params = new URLSearchParams("?q=javascript&page=1");
console.log(params.get("q")); // "javascript"
console.log(params.get("page")); // "1"
If you need to work with query parameters interactively, you can use the TidyURLs query editor.
Handle repeated parameters
A query string can contain the same key more than once, such as tag=javascript&tag=web. get() returns only the first value. Use getAll() when every occurrence matters:
const params = new URLSearchParams("tag=javascript&tag=web");
console.log(params.get("tag")); // "javascript"
console.log(params.getAll("tag")); // ["javascript", "web"]
You can also iterate through all key-value pairs. Repeated keys appear as separate entries:
const params = new URLSearchParams("tag=javascript&tag=web&page=1");
for (const [key, value] of params) {
console.log(`${key}: ${value}`);
}
// tag: javascript
// tag: web
// page: 1
Add, update, and remove parameters
Use the methods that match the change you intend to make:
| Method | What it does |
|---|---|
set(name, value) | Adds the key if absent; otherwise replaces its values with one value. |
append(name, value) | Adds another key-value pair, even if that key already exists. |
delete(name) | Removes all entries with that key. |
For example, set() is useful when a filter should have one current value:
const url = new URL("https://shop.example/products?category=books&page=1");
url.searchParams.set("page", "2");
url.searchParams.set("sort", "price");
url.searchParams.delete("category");
console.log(url.toString());
// https://shop.example/products?page=2&sort=price
Use append() when the URL should include multiple values for the same key:
const params = new URLSearchParams();
params.append("tag", "javascript");
params.append("tag", "web");
console.log(params.toString()); // tag=javascript&tag=web
Passing an object to the URLSearchParams constructor is convenient for simple, single-value parameters. An array value in an object is converted to a string; it does not create repeated keys. Use append() or an iterable of key-value pairs when you need repeated keys.
Build and serialize a query string
URLSearchParams handles encoding when it serializes values. Provide raw values rather than encoding them yourself:
const params = new URLSearchParams();
params.set("q", "URL tools & JavaScript");
console.log(params.toString());
// q=URL+tools+%26+JavaScript
When you add parameters to a complete URL, use the URL object and read the final URL with toString():
const url = new URL("https://example.com/search");
url.searchParams.set("q", "URL tools & JavaScript");
console.log(url.toString());
// https://example.com/search?q=URL+tools+%26+JavaScript
Serialization may change how characters are represented, even when the decoded parameter value is equivalent. For example, spaces are represented as + by URLSearchParams. Avoid comparing raw query strings when what you actually need to compare are their parsed keys and values.
A literal plus sign in a query string must be encoded as %2B if it should be read as a plus rather than a space. When setting values through URLSearchParams, pass the literal value; the API handles serialization.
Update the current page's URL
In a browser, modify the current address with the History API. replaceState() changes the current history entry; pushState() creates a new entry that the Back button can return to.
const url = new URL(window.location.href);
url.searchParams.set("page", "2");
window.history.replaceState(window.history.state, "", url);
Use this pattern in browser code, not in Node.js, where window and history are not available. Decide whether you want to replace the current entry or add a navigable one before choosing between replaceState() and pushState().
Common mistakes and troubleshooting
Parsing the full URL with URLSearchParams
URLSearchParams is for query parameters, not for parsing a complete URL. For a full URL, create a URL first and use .searchParams. In environments where a relative URL is possible, provide a base:
const url = new URL("/products?category=books", "https://shop.example");
console.log(url.searchParams.get("category")); // "books"
Assuming get() returns every value
get() returns only the first occurrence. Use getAll() or iterate when a key can repeat.
Confusing a missing value with an empty value
get() returns null when a key is absent, but returns an empty string for a key written as flag=. Check explicitly if the distinction matters:
const params = new URLSearchParams("present=");
console.log(params.get("present")); // ""
console.log(params.get("missing")); // null
Encoding values manually
Calling encodeURIComponent() before passing a value to set() or append() can encode it twice. Pass the original string and let URLSearchParams serialize it.
Treating query values as trusted or typed data
Query values are untrusted strings. Validate expected formats, allowed values, and numeric ranges before using them. Encoding a value for a URL is not the same as validating it or making it safe to insert into HTML, SQL, or another context.
A practical checklist
- Parse complete URLs with
new URL(); provide a base if the input is relative. - Read one value with
get()or repeated values withgetAll(). - Convert and validate values before using them in application logic.
- Use
set(),append(), anddelete()according to the intended behavior. - Let the URL APIs handle serialization instead of manually assembling encoded strings.
- In browser code, choose
replaceState()orpushState()based on the desired Back-button behavior.
Conclusion
URL and URLSearchParams provide a practical way to read and modify query strings without manually splitting and joining URL text. Knowing how they handle repeated keys, missing values, and serialization helps you build more reliable browser features and server-side JavaScript. Treat the resulting parameter values as input that still needs validation.
