JavaScriptLocation & URL APIs

Location API and URL parsing

window.location represents the current page's URL, broken into useful pieces. Pair it with the modern URL and URLSearchParams classes and you have a complete toolkit for parsing and building URLs without ever reaching for a regex or string-splitting hack.

Anatomy of window.location

JS
// Suppose location.href === "https://shop.example.com:8443/cart?id=42&qty=2#summary"

location.href;     // the whole URL string
location.protocol; // "https:"
location.host;     // "shop.example.com:8443"
location.hostname; // "shop.example.com"
location.port;     // "8443"
location.pathname; // "/cart"
location.search;   // "?id=42&qty=2"
location.hash;     // "#summary"
location.origin;   // "https://shop.example.com:8443"

origin is the security boundary: protocol + host + port. Same-origin policy, CORS, cookies and storage are all scoped by it.

Navigating

JS
location.href = "/login";          // full navigation (adds a history entry)
location.assign("/login");         // identical to above
location.replace("/login");        // navigate WITHOUT adding a history entry
location.reload();                 // refresh the current page
  • assign — like clicking a link; back button returns here.

  • replace — like a server-side redirect; back button skips this page.

  • reload() — full page reload, hits the network unless the response is cacheable.

The URL class — parse without pain

JS
const url = new URL("https://shop.example.com/cart?id=42&qty=2#summary");

url.pathname;        // "/cart"
url.searchParams.get("id");  // "42"
url.searchParams.get("qty"); // "2"
url.hash;            // "#summary"

// Build incrementally:
url.searchParams.set("qty", 3);
url.searchParams.delete("id");
url.toString();
// "https://shop.example.com/cart?qty=3#summary"
/cart
42
2
https://shop.example.com/cart?qty=3#summary
Relative URLs and the second argument

The URL constructor takes an optional base. This is how you safely resolve relative paths against any URL — including location.href.

JS
new URL("/about", "https://example.com/blog/").href;
// "https://example.com/about"

new URL("../images/x.png", "https://example.com/blog/post/").href;
// "https://example.com/blog/images/x.png"

// Most common in practice:
const next = new URL("/dashboard", location.href);
URLSearchParams — read and write query strings

JS
const params = new URLSearchParams(location.search);

params.get("q");                  // "shoes"
params.has("page");               // true
params.getAll("tag");              // ["new", "sale"] — multi-value
for (const [key, value] of params) {
  console.log(key, value);
}

// Mutate then write back to the URL bar without reloading:
params.set("page", 2);
params.delete("debug");
history.replaceState(null, "", `?${params}`);
Note
`URLSearchParams` handles escaping for you: `params.set("name", "Ada Lovelace")` produces `name=Ada+Lovelace` automatically. Building query strings by hand is a common source of bugs.
Building a URL from scratch

Construct a search URL

JS
function searchUrl(query, page) {
  const url = new URL("/search", location.origin);
  url.searchParams.set("q", query);
  if (page > 1) url.searchParams.set("page", page);
  return url.toString();
}

searchUrl("hello world", 2);
// "https://example.com/search?q=hello+world&page=2"
Validating and normalising user input

JS
function safeUrl(input) {
  try {
    const u = new URL(input, location.origin);
    return u.protocol === "https:" || u.protocol === "http:" ? u : null;
  } catch {
    return null;
  }
}

safeUrl("javascript:alert(1)"); // null — safe
safeUrl("relative/path");        // resolved against the current origin
safeUrl("https://other.example/x"); // URL object
Tip
Always wrap `new URL(input)` in `try/catch` — invalid input throws `TypeError`. Use this as a poor man's URL validator.
Comparing URLs

JS
// Same-origin check:
const target = new URL(linkHref, location.origin);
if (target.origin !== location.origin) {
  // external link
}

// Comparison should always use parsed parts, not raw strings.
// "/path" and "/path/" are different URLs to most servers.
Reading the hash safely

location.hash includes the leading #. Strip it before use, and remember that hash routing libraries store route info there.

JS
const route = location.hash.slice(1) || "/";
addEventListener("hashchange", () => console.log("hash is now", location.hash));
Cheat-sheet
  • Parse: new URL(str) or new URL(str, base). Wrap in try/catch.

  • Query string: URLSearchParams. Use .set/.get/.has/.getAll/.delete.

  • Navigate: location.assign (with history) or location.replace (without).

  • Update the URL without reloading: history.pushState / history.replaceState.

  • Compare origins as url.origin, never as substring matches on href.