TidyURLs
Go to Tools
BLOG
The TidyURLsJournal

Practical guides, tutorials, and insights about URLs, SEO, web development, and online marketing. Learn, troubleshoot, and get the most of the web.

Back to the Journal
TidyURLs Journal

JavaScript URLSearchParams Tutorial: Read and Modify URL Parameters

Practical insights, clear explanations, and useful ideas for understanding the web.

October 25, 20269 min read6 topics
JavaScript URLSearchParams Tutorial: Read and Modify URL Parameters
Explore the details

Advertisement

#JavaScript#URLSearchParams#Query Strings#Web APIs#Frontend Development#Node.js
October 25, 20269 min read

URL parameters are everywhere: search pages, product filters, campaign links, pagination, language selection, and shareable dashboards. If you are building a JavaScript app, you often need to read values from a query string like ?q=phone&page=2, update one value without breaking the rest of the URL, or generate a clean link that users can share.

This JavaScript URLSearchParams tutorial shows how to work with query parameters using the standard URL and URLSearchParams APIs. You will learn how to read, add, update, delete, and serialize parameters safely, with practical examples that run in modern browsers and current Node.js versions.

Key takeaways

  • Use new URL(urlString) when you have a complete URL and want reliable parsing.
  • Use url.searchParams to read and change query parameters attached to that URL.
  • Use get(), getAll(), has(), set(), append(), and delete() for common operations.
  • Do not manually concatenate query strings when user input or special characters are involved.
  • Avoid storing secrets, tokens, or sensitive personal data in URL parameters because URLs can be logged, copied, cached, and shared.

What are URL parameters?

URL parameters, also called query parameters or query string parameters, are key-value pairs after the ? in a URL.

https://shop.example.in/products?category=books&page=2&sort=price

In this URL:

PartMeaning
https://shop.example.in/productsBase URL
?Starts the query string
category=booksParameter named category with value books
&Separates parameters
page=2Parameter named page with value 2

The browser does not automatically treat these values as numbers, booleans, arrays, or objects. Query parameter values are strings unless your code converts them.

Advertisement

Why use URLSearchParams instead of string splitting?

You may see code like this in older tutorials:

const query = window.location.search.substring(1);
const parts = query.split('&');

That approach works only for very simple URLs. It becomes error-prone when values contain spaces, &, =, Unicode characters, or repeated parameter names.

URLSearchParams is a built-in Web API designed for query strings. According to MDN, it provides utility methods to work with the query string of a URL. It handles encoding and decoding rules for you, which makes your code shorter and less fragile.

For a quick manual check while learning, you can also use TidyURLs to edit query parameters and compare the resulting URL with your JavaScript output.

Reading URL parameters in JavaScript

Read parameters from a full URL

Use URL when you have a complete URL string.

const url = new URL('https://shop.example.in/products?category=books&page=2&sort=price');

console.log(url.searchParams.get('category')); // 'books'
console.log(url.searchParams.get('page'));     // '2'
console.log(url.searchParams.get('sort'));     // 'price'

Remember that get() returns a string or null.

const page = url.searchParams.get('page');
const missing = url.searchParams.get('coupon');

console.log(typeof page); // 'string'
console.log(missing);     // null

If you need a number, convert it explicitly:

const pageParam = url.searchParams.get('page');
const page = pageParam === null ? 1 : Number.parseInt(pageParam, 10);

console.log(page); // 2

Read parameters from the current browser URL

In a browser, window.location.href gives you the current page URL.

const currentUrl = new URL(window.location.href);
const searchQuery = currentUrl.searchParams.get('q');

console.log(searchQuery);

For example, if the current page is:

https://example.in/search?q=javascript&page=1

Then searchQuery will be 'javascript'.

Check whether a parameter exists

Use has() when you care whether the parameter is present, even if its value is empty.

const url = new URL('https://example.in/offers?coupon=');

console.log(url.searchParams.has('coupon')); // true
console.log(url.searchParams.get('coupon')); // ''
console.log(url.searchParams.has('utm_source')); // false

This distinction matters because ?coupon= and no coupon parameter are not the same thing.

Working with repeated parameters

URLs can contain the same parameter name more than once:

https://example.in/products?tag=mobile&tag=android&tag=budget

Use get() for the first value and getAll() for every value.

const url = new URL('https://example.in/products?tag=mobile&tag=android&tag=budget');

console.log(url.searchParams.get('tag'));    // 'mobile'
console.log(url.searchParams.getAll('tag')); // ['mobile', 'android', 'budget']

Repeated parameters are common for filters, tags, selected categories, and multi-select form controls.

Modifying URL parameters

Add or update a parameter with set()

set() updates the parameter if it already exists. If it does not exist, set() adds it.

const url = new URL('https://shop.example.in/products?category=books&page=2');

url.searchParams.set('page', '3');
url.searchParams.set('sort', 'price-low-to-high');

console.log(url.toString());
// 'https://shop.example.in/products?category=books&page=3&sort=price-low-to-high'

If the parameter appears multiple times, set() replaces all existing values with one value.

const url = new URL('https://example.in/products?tag=mobile&tag=android');

url.searchParams.set('tag', 'laptop');

console.log(url.toString());
// 'https://example.in/products?tag=laptop'

Add another value with append()

Use append() when repeated values are intentional.

const url = new URL('https://example.in/products?tag=mobile');

url.searchParams.append('tag', 'android');
url.searchParams.append('tag', 'budget');

console.log(url.toString());
// 'https://example.in/products?tag=mobile&tag=android&tag=budget'

Remove a parameter with delete()

Use delete() to remove a parameter.

const url = new URL('https://example.in/products?category=books&utm_source=newsletter&page=2');

url.searchParams.delete('utm_source');

console.log(url.toString());
// 'https://example.in/products?category=books&page=2'

This is useful when cleaning tracking parameters, resetting filters, or removing temporary state from shareable links.

Updating the browser address bar without reloading

If you modify a URL object, the browser address bar does not change automatically. To update the visible URL without reloading the page, use the History API.

Use replaceState() when the change should not create a new Back button entry, such as updating a filter while typing.

const url = new URL(window.location.href);

url.searchParams.set('q', 'javascript');
url.searchParams.set('page', '1');

window.history.replaceState({}, '', url);

Use pushState() when the change represents a meaningful navigation step that the user may expect to return to with the Back button.

const url = new URL(window.location.href);

url.searchParams.set('category', 'laptops');

window.history.pushState({}, '', url);

These examples update the URL displayed in the browser. They do not automatically fetch new data or re-render your page. Your application code still needs to respond to the new state.

Advertisement

Practical workflow: build a product filter URL

Here is a small function that builds a product listing URL from filter values. It demonstrates common real-world needs: setting a category, resetting pagination, supporting multiple brands, and skipping empty values.

function buildProductUrl(baseUrl, filters) {
  const url = new URL(baseUrl);

  if (filters.category) {
    url.searchParams.set('category', filters.category);
  } else {
    url.searchParams.delete('category');
  }

  if (filters.sort) {
    url.searchParams.set('sort', filters.sort);
  } else {
    url.searchParams.delete('sort');
  }

  // Reset to page 1 whenever filters change.
  url.searchParams.set('page', '1');

  // Replace existing brand filters with the current selection.
  url.searchParams.delete('brand');

  for (const brand of filters.brands) {
    url.searchParams.append('brand', brand);
  }

  return url.toString();
}

const nextUrl = buildProductUrl('https://shop.example.in/products?page=4', {
  category: 'phones',
  sort: 'price-low-to-high',
  brands: ['samsung', 'oneplus']
});

console.log(nextUrl);
// 'https://shop.example.in/products?page=1&category=phones&sort=price-low-to-high&brand=samsung&brand=oneplus'

The exact parameter order may vary depending on how you add and modify values. Your server or frontend should not rely on query parameter order for correctness.

Practical workflow: read query parameters into an object

Sometimes you want to convert query parameters into an object for easier use in your application. Be careful with repeated keys: a plain object can lose information if you store only one value per key.

This helper stores repeated parameters as arrays.

function queryParamsToObject(searchParams) {
  const result = {};

  for (const [key, value] of searchParams) {
    if (Object.prototype.hasOwnProperty.call(result, key)) {
      const currentValue = result[key];
      result[key] = Array.isArray(currentValue)
        ? [...currentValue, value]
        : [currentValue, value];
    } else {
      result[key] = value;
    }
  }

  return result;
}

const url = new URL('https://example.in/products?tag=mobile&tag=android&page=2');
const paramsObject = queryParamsToObject(url.searchParams);

console.log(paramsObject);
// { tag: ['mobile', 'android'], page: '2' }

This is useful for debugging and simple state management, but for complex applications you may prefer a schema-based parser that validates expected fields and types.

Using URLSearchParams in Node.js

Modern Node.js also supports the WHATWG URL API.

const url = new URL('https://api.example.in/search?q=nodejs&page=1');

url.searchParams.set('page', '2');
url.searchParams.append('lang', 'en');

console.log(url.href);
// 'https://api.example.in/search?q=nodejs&page=2&lang=en'

If you are parsing an incoming request path such as /search?q=nodejs, you need a base URL because new URL() requires an absolute URL unless you provide a base.

const requestPath = '/search?q=nodejs&page=1';
const url = new URL(requestPath, 'https://example.in');

console.log(url.pathname); // '/search'
console.log(url.searchParams.get('q')); // 'nodejs'

Do not treat query parsing as security validation. If a parameter controls database queries, redirects, file access, or API calls, validate it separately on the server.

Encoding: let the API handle special characters

One major benefit of URLSearchParams is correct encoding. You should usually pass normal strings and let the API serialize them.

const url = new URL('https://example.in/search');

url.searchParams.set('q', 'best phones under ₹30000');
url.searchParams.set('city', 'Bengaluru South');

console.log(url.toString());
// 'https://example.in/search?q=best+phones+under+%E2%82%B930000&city=Bengaluru+South'

When you read the values back, the API decodes them.

const url = new URL('https://example.in/search?q=best+phones+under+%E2%82%B930000');

console.log(url.searchParams.get('q'));
// 'best phones under ₹30000'

Avoid manually calling encodeURIComponent() before passing values to set() unless you have a specific reason. Double encoding can produce confusing output.

const url = new URL('https://example.in/search');

url.searchParams.set('q', encodeURIComponent('red shoes'));

console.log(url.toString());
// 'https://example.in/search?q=red%2520shoes'

The %25 in the output is the encoded form of %, which means the value was encoded twice.

Common mistakes and pitfalls

Passing a full URL to URLSearchParams directly

URLSearchParams is for query strings, not full URL parsing. If you have a full URL, use new URL() first.

// Avoid this for full URLs:
const wrong = new URLSearchParams('https://example.in/search?q=javascript');
console.log(wrong.get('q')); // null

// Prefer this:
const url = new URL('https://example.in/search?q=javascript');
console.log(url.searchParams.get('q')); // 'javascript'

Forgetting that values are strings

const url = new URL('https://example.in/articles?page=2');

console.log(url.searchParams.get('page') + 1); // '21'
console.log(Number(url.searchParams.get('page')) + 1); // 3

Convert and validate values before using them as numbers.

Assuming new URLSearchParams(url.search) updates the URL automatically

If you create a separate URLSearchParams object from url.search, changes to that separate object do not automatically update the original URL.

const url = new URL('https://example.in/search?q=old');
const params = new URLSearchParams(url.search);

params.set('q', 'new');

console.log(url.toString());
// 'https://example.in/search?q=old'

url.search = params.toString();
console.log(url.toString());
// 'https://example.in/search?q=new'

When possible, use url.searchParams directly to avoid this extra assignment.

Using query parameters for sensitive data

Do not put passwords, OTPs, API keys, session tokens, Aadhaar numbers, PAN details, or other sensitive data in URL parameters. URLs may appear in browser history, server logs, analytics tools, referrer headers, screenshots, and shared messages.

Assuming client-side changes are enough

A user can edit URL parameters manually. If your application receives ?role=admin or ?price=1, your backend must not trust it just because your frontend generated a different value. Always validate and authorize sensitive operations on the server.

Defensive best practices

  • Define an allowlist of expected query parameter names.
  • Validate types and ranges, such as page being a positive integer.
  • Set safe defaults when parameters are missing or invalid.
  • Limit maximum lengths for search terms and free-text parameters.
  • Avoid open redirects by validating redirect targets on the server.
  • Keep sensitive values out of URLs.
  • Use replaceState() for frequent UI changes and pushState() for meaningful navigation.
  • Treat URL parsing as parsing only, not as complete security protection.

Here is a simple validator for pagination parameters:

function readPage(searchParams) {
  const rawPage = searchParams.get('page');
  const page = rawPage === null ? 1 : Number.parseInt(rawPage, 10);

  if (!Number.isInteger(page) || page < 1 || page > 1000) {
    return 1;
  }

  return page;
}

const url = new URL('https://example.in/articles?page=abc');
console.log(readPage(url.searchParams)); // 1

This is intentionally small. Real applications should validate every parameter according to the business rule it affects.

Conclusion

The URL and URLSearchParams APIs are the cleanest way to read and modify URL parameters in JavaScript. Use new URL() for complete URLs, work with url.searchParams for query changes, and rely on methods like get(), set(), append(), and delete() instead of fragile string manipulation.

For beginner and intermediate developers, the most important habits are simple: remember that query values are strings, handle repeated parameters intentionally, let the API manage encoding, and validate everything important on the server. With these patterns, you can build search pages, filters, pagination, and shareable links that are easier to maintain and less likely to break.

References