Skip to content
beginner

Read and Update URL Query Parameters with JavaScript

A query string is the page's small, shareable memory: the part of the address that survives a copy-paste, a bookmark, or a link sent to a friend. Here is…

Published 2026-10-03Updated 2026-10-0410 min read
Epic sunset view over the sea with silhouettes of industrial cranes on the horizon.
Epic sunset view over the sea with silhouettes of industrial cranes on the horizon. Photo by Pixabay on Pexels.

A query string is the page's small, shareable memory: the part of the address that survives a copy-paste, a bookmark, or a link sent to a friend. Here is how to read it and change it without breaking the URL.

You have probably seen a URL like this:

https://example.com/search?name=Sam&page=2

Everything after the ? is the query string. It is data your page can read, and it is data your page can change. That means a search term, a page number, or a selected filter can live in the address bar — and a link you send to someone else can carry that state with it.

The tool for this job is URLSearchParams. It reads a query string, gives you clean values, and writes a new query string back — including the encoding you would otherwise have to handle by hand.

In this cookbook, you will build one small page that reads a name value from the URL, falls back to a default when the value is missing, and updates the URL when you click a button.

What a Query String Actually Is

Before any API, get the mental model right. A query string is just text, which is why your string skills already apply.

It starts at the ? and holds name=value pairs joined by &:

?name=Sam&page=2
  • name is a key, Sam is its value.
  • page is a key, 2 is its value.
  • The same key can appear more than once: ?tag=js&tag=css.

One important distinction: the query string is data the page reads, not a file path. Changing it does not load a different HTML file. It changes the values your JavaScript sees when the page runs.

That is exactly why it is useful. A URL with ?q=javascript is a link you can share, bookmark, and reload — and the page can rebuild itself from it.

Read a Parameter from the Current URL

The browser exposes the raw query string through window.location.search. It includes the leading ?:

?name=Sam

Wrap that string in new URLSearchParams(...) and you get an object with readable methods. The one you will use most is get().

Here is a complete, runnable page. Save it as index.html and open it in your browser:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Query Params Demo</title>
</head>
<body>
  <h1>Hello, <span id="greeting">...</span></h1>

  <script>
    const params = new URLSearchParams(window.location.search);
    const name = params.get('name');

    document.getElementById('greeting').textContent = name;
  </script>
</body>
</html>

Now open it with the parameter present:

file:///path/to/index.html?name=Sam

Expected output on the page:

Hello, Sam

Open it without the parameter:

file:///path/to/index.html

Expected output on the page:

Hello, null

That null is the first thing that trips up beginners. get() returns null — not an empty string — when the key is missing. It is JavaScript's way of saying "this key was never here."

Knowledge check

Check your understanding

Answer this question before you continue.

Given the query string in the stimulus, what does this code log?
Output Prediction

Focus: Read a named value from the current URL using URLSearchParams and get().

const params = new URLSearchParams('?name=Sam&page=2');
console.log(params.get('name'));

Handle a Missing Parameter with a Default

A shared link without the parameter should not produce a blank page. So give the value a fallback.

The shortest fix uses the || operator:

const params = new URLSearchParams(window.location.search);
const name = params.get('name') || 'friend';

document.getElementById('greeting').textContent = name;

Open the page with no query string, and the output becomes:

Hello, friend

If you prefer to be explicit, an if check reads just as clearly:

let name = params.get('name');

if (name === null) {
  name = 'friend';
}

Both work. The || version is shorter and idiomatic for this exact case. The if version is easier to extend later if you need more than a simple fallback.

Common mistake: Calling a string method on the result of get() before checking for null. params.get('name').toUpperCase() throws a TypeError when the key is missing. Always handle the missing case first.

Knowledge check

Check your understanding

Answer this question before you continue.

If the current URL has no query string, what value does this expression produce?
Single Choice

Focus: Supply a fallback value when a query parameter is absent.

const params = new URLSearchParams(window.location.search);
const name = params.get('name') || 'friend';

Create and Update Parameters with set()

A flow shows the current URL passing its query string into URLSearchParams. A read branch uses get() to produce a value; an update branch uses set(), then returns the changed URL to the address bar while preserving the path and hash.
Follow the query string from the address bar into JavaScript, then see how an update returns it to the URL.

Reading is half the job. Writing is the other half.

params.set('page', '3') does two things depending on what it finds:

  • If the key exists, it updates the value.
  • If the key does not exist, it creates it.

Then params.toString() turns the object back into a query string. To put that new string in the address bar without reloading the page, use history.replaceState().

The safest way to update the current URL is to build a URL object from window.location.href, change its searchParams, and pass the whole thing to replaceState(). That keeps the path, the #hash, and anything else already in the address intact.

Here is the full example. It reads name, shows it, and updates the URL when you click the button:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Query Params Demo</title>
</head>
<body>
  <h1>Hello, <span id="greeting">...</span></h1>
  <button id="set-name">Set name to Alex</button>

  <script>
    const params = new URLSearchParams(window.location.search);
    const name = params.get('name') || 'friend';
    document.getElementById('greeting').textContent = name;

    document.getElementById('set-name').addEventListener('click', () => {
      const url = new URL(window.location.href);
      url.searchParams.set('name', 'Alex');
      history.replaceState(null, '', url);
      document.getElementById('greeting').textContent = 'Alex';
    });
  </script>
</body>
</html>

Before clicking, the address bar might look like this:

file:///path/to/index.html?name=Sam

After clicking, it becomes:

file:///path/to/index.html?name=Alex

The page did not reload. The address bar just changed — and if you copy that URL now, it carries name=Alex with it. If the original URL had a #section fragment, it is still there too, because you never rebuilt the URL from scratch.

Note: set() replaces every existing value for that key. If the URL had ?tag=js&tag=css and you call params.set('tag', 'html'), you end up with a single tag=html. Use append() when you want to add another value instead of replacing.

Knowledge check

Check your understanding

Answer this question before you continue.

What does params.toString() produce after this code runs?
Output Prediction

Focus: Use set() to replace all existing values for a query parameter name.

const params = new URLSearchParams('?tag=js&tag=css');
params.set('tag', 'html');
console.log(params.toString());

Repeated Names and getAll()

The same key appearing more than once is valid and common. Multi-select filters use it all the time:

?tag=js&tag=css

Here is the behavior you need to remember:

  • get('tag') returns only the first match: "js".
  • getAll('tag') returns an array of all matches: ["js", "css"].
const params = new URLSearchParams('?tag=js&tag=css');

console.log(params.get('tag'));
console.log(params.getAll('tag'));

Expected output:

js
[ 'js', 'css' ]

And the write side:

  • append('tag', 'html') adds another value: ?tag=js&tag=css&tag=html.
  • set('tag', 'html') collapses them all to one: ?tag=html.

If your UI lets users pick multiple filters, append() and getAll() are the pair you want. If it is a single choice, set() and get() are enough.

Why Your Values Look Encoded

Spaces and non-Latin characters cannot sit raw in a URL. They get percent-encoded — replaced with a % followed by their UTF-8 code. A space becomes %20, and for historical reasons it can also appear as +.

The good news: URLSearchParams handles this automatically. You pass plain text in, and you read plain text out.

const params = new URLSearchParams();
params.set('q', 'test me!');
console.log(params.toString());

Expected output:

q=test+me%21

Notice the + and the %21. That is the serialized form. When you read it back with get('q'), you get "test me!" again — decoded.

One subtlety worth knowing: the URL's own search property encodes spaces as %20, while URLSearchParams serializes them as +. Both are valid. If you update searchParams and then look at the URL, the encoding may shift slightly. That is expected, not a bug.

Tip: Do not build query strings with string concatenation. '?q=' + userInput breaks the moment the input contains a space, an &, or a ?. Let URLSearchParams encode for you.

Knowledge check

Check your understanding

Answer this question before you continue.

What does this code log?
Output Prediction

Focus: Recognize how URLSearchParams serializes spaces and punctuation in query values.

const params = new URLSearchParams();
params.set('q', 'test me!');
console.log(params.toString());

Common Beginner Mistakes

These are the errors that cost the most time on this task.

  • Forgetting that get() returns null. Calling .toUpperCase() or .trim() on the result throws before you ever see the value.
  • Using set() when you meant append(). You silently drop repeated values and wonder where the other filters went.
  • Rebuilding the URL by hand. Concatenating window.location.origin + '?' + params loses the path or the #hash. Build a URL from window.location.href and update its searchParams instead.
  • Reading the parameter once at load. If the URL changes later — through a link, a back button, or your own code — the page will not update unless you re-read it.
  • Mixing raw strings and objects. URLSearchParams accepts both '?name=Sam' and 'name=Sam', but passing a full URL string will not work the way you expect. Pass window.location.search, not window.location.href.

When to Use URLSearchParams and When Not To

Use it for small, shareable, human-readable state: search terms, filters, page numbers, selected tabs, sort order. Anything you would want to see in the address bar or send to someone else.

Do not use it for:

  • Secrets. Everything in the URL is visible in the address bar, browser history, and server logs.
  • Large data. Query strings have practical length limits in browsers and servers. A few hundred characters is fine; a serialized object is not.
  • Persistence across visits. If a value should survive without appearing in the URL, that is a job for localStorage, not the query string.

The rule I use: if the value describes what the user is looking at right now, it belongs in the URL. If it describes who the user is or what they saved, it belongs somewhere else.

A Small Variation: Build the Query String from Scratch

So far you have been editing the current URL. Sometimes you need to build a fresh one — for example, when constructing a link.

Call new URLSearchParams() with no argument to start empty, then fill it:

const params = new URLSearchParams();
params.set('q', 'javascript');
params.set('page', '1');

const link = '/search?' + params.toString();
console.log(link);

Expected output:

/search?q=javascript&page=1

The rule is simple:

  • Editing the current page? Start from new URLSearchParams(window.location.search).
  • Building a new link? Start from new URLSearchParams().

What to Memorize and What to Look Up

You do not need the whole API in your head. Five methods cover almost everything:

MethodWhat it does
get(name)Returns the first value, or null
set(name, value)Updates or creates a single value
append(name, value)Adds another value without replacing
getAll(name)Returns all values as an array
toString()Serializes back to a query string

Plus the pattern itself: new URLSearchParams(window.location.search).

Everything else — delete, has, sort, keys, values, entries, forEach — is worth knowing exists, but you can look it up when you need it. The five above will carry you through filters, search boxes, pagination, and tab state.

Your Next Step

Take the page you built and add a text input. On every keystroke, write the input's value into a q parameter using set() and history.replaceState(). Then reload the page and confirm the input is repopulated from the URL.

That is the moment the query string stops being decoration and becomes state you control. Once you feel that, you will start noticing it everywhere — in search pages, dashboards, and every filter UI that remembers what you picked.

Knowledge check

Final check

Finish the article by checking the ideas you just learned.

To read the current page's query parameters, which value should you pass to URLSearchParams?
Question 1 of 2Misconception Check

Focus: Choose the current URL component to pass to URLSearchParams when reading its query parameters.

A preference should survive visits but should not appear in the address bar. Which storage choice does the article recommend?
Question 2 of 2Single Choice

Focus: Select an appropriate place for data that should persist without appearing in the URL.

References

  1. URL: searchParams property - Web APIs | MDNdeveloper.mozilla.org
Practical resource

Want a more structured JavaScript path?

Use the JavaScript for AI Applications Starter Pack to turn individual tutorials into a focused path from language fundamentals to interactive AI applications.

View the bundle
Coming soon

JavaScript for AI Applications Starter Pack

Build the JavaScript foundation behind modern interactive applications. The JavaScript for AI Applications Starter Pack takes you from core language concepts through functions, browser events, forms, DOM updates, application state, debugging, and practical projects—so you can learn how interfaces take input, work with structured data, respond to users, and turn results into experiences people can actually use.

$9
PDF BundleJavaScriptWeb DevelopmentAI Applications
  • 253-page illustrated PDF
  • 12 guided JavaScript chapters
  • Visual concept diagrams
  • Self-assessment quizzes
  • Bonus deep-dive sections
  • DOM, events, forms & application state
  • Browser projects, debugging & practical workflows

Coming soon

Keep learning

Related tutorials

Continue with nearby JavaScript topics and beginner-friendly explanations.

Dramatic aerial view of Panama City skyline during sunset showcasing modern skyscrapers.
beginner
10 min read

Build a Click Counter

There's a moment in learning JavaScript when things stop being abstract. You've studied variables and functions. You've followed along with examples. But…

Read tutorial
Close-up of a tropical flower with vibrant red and yellow petals in vivid detail.
beginner
13 min read

Build a JavaScript Quiz App

You've learned arrays, conditionals, click events, and DOM updates as separate lessons. Now it's time to see them work together. A quiz app is the perfect…

Read tutorial