Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the browser’s URL and URLSearchParams APIs to build each test URL, then compare both the parsed parameter values and the serialized URL in every browser you support. A raw-string difference is not automatically a bug: for example, a space may serialize as %20 in URL.search and as + through URLSearchParams. Test the decoded meaning first, and assert exact spelling only if your application or server requires it.

What to compare in a cross-browser URL test

A query string is structured data, not just text appended to a page address. The WHATWG URL Standard defines how URLs are parsed and serialized. For each test case, record two outputs: the query value as read back through searchParams, and the complete serialized URL. The first tells you whether the intended data survived; the second shows how it was spelled on the wire.

  • Decoded value: Does each parameter return the intended characters?
  • Serialization: Does the raw query use a required representation, if your contract specifies one?
  • Delimiters: Do encoded &, =, ?, and # remain part of a value rather than becoming query structure or a fragment?
  • Unicode: Does accented, CJK, or other non-ASCII text survive construction and reading?
  • Environment: Which browser version and operating system produced the result?

Why a URL can change spelling without changing meaning

URL.search and URLSearchParams can serialize equivalent query values differently. In particular, form-style URLSearchParams serialization encodes U+0020 SPACE as +, while URL.search may show a space as %20. The standard states that URLSearchParams encodes a space as +; MDN’s URL.search documentation describes the visible difference and notes that updating searchParams can rewrite the URL string.

That rewrite is not by itself evidence of a browser defect. Compare the parsed value and confirm how the receiving application interprets it. If a server, signature scheme, cache key, or other downstream component requires one exact representation, make that representation an explicit requirement and test it directly. Interpretation at that boundary is application-specific.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build a repeatable test fixture

Construct with URLSearchParams, not string concatenation

Pass special-character-bearing input as a parameter value rather than manually joining it into a query string. This keeps characters such as & and = from accidentally being treated as query separators during construction.

const base = "https://example.com/search");
const cases = [
  { name: "ordinary", value: "wireless keyboard" },
  { name: "space", value: "red blue" },
  { name: "plus", value: "C++" },
  { name: "percent", value: "50% complete" },
  { name: "delimiters", value: "a&b=c?d#e" },
  { name: "accented", value: "café" },
  { name: "CJK", value: "検索" }
];

for (const test of cases) {
  const url = new URL(base);
  url.searchParams.set("q", test.value);
  console.log({
    name: test.name,
    serialized: url.href,
    parsed: url.searchParams.get("q")
  });
}

In a runnable version, ensure the base URL is a valid absolute URL; for example, the first line should be const base = "https://example.com/search";. The extra closing parenthesis shown above is not part of valid JavaScript and should be omitted.

Cover the characters most likely to expose mistakes

  • Spaces, including leading or trailing spaces if your application accepts them.
  • A literal plus sign, which should not be confused with a space by an application’s decoding rules.
  • Percent signs and percent-escape-looking text such as %2F.
  • Ampersand and equals signs, which commonly delimit query fields.
  • Question marks and hash characters inside values.
  • Unicode samples such as café and 検索.

For percent cases, distinguish the literal input text %2F from a slash character. Record the intended input and the value read back so the test reveals whether the percent sign itself survived.

Run the same cases in each target browser

  1. Choose the parameter name and exact input values, including whether you are testing one parameter or several.
  2. Run the same fixture in each browser and operating-system combination you support. Use the browser’s developer console, an existing automated test harness, or a page that runs the fixture.
  3. For every case, record the browser name and version, operating system, input, serialized output, parsed value, and pass/fail result.
  4. Assert that the parsed value equals the intended input. Add an assertion on the serialized URL only when the application or server contract requires exact text.
  5. If the URL is navigated to or sent to a server, verify the value at that receiving boundary as well; a browser-side round trip alone does not establish application-specific server interpretation.
  6. If you suspect a standards-level discrepancy, compare the case with the URL web-platform-tests suite, a conformance-testing resource referenced by the standard: https://github.com/web-platform-tests/wpt.

This procedure describes how to collect results; it is not a pass/fail report for particular current browser versions. Record actual versions and outcomes rather than inferring compatibility from standards documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common failures and how to diagnose them

The raw URL differs, but the parsed value matches

Check whether the difference is a known serialization variation such as %20 versus +. If the decoded value and receiving application behavior are correct, a string-only assertion may be too strict. Keep it only when exact wire spelling is part of the contract.

An ampersand or equals sign creates an unexpected parameter

Do not concatenate an untrusted value directly into a query string. Set it through searchParams.set(), then inspect both the serialized URL and the result of searchParams.get().

A plus sign comes back as a space

Separate the literal-plus test from the space test and inspect the parsed result. Confirm that the value was constructed as data with the URL API and check the decoding behavior of the application receiving it.

A hash appears to disappear from the query

A literal hash can introduce a URL fragment if inserted as raw URL text. Put it into a parameter value using searchParams, then check the query value and fragment separately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Changing searchParams changes the displayed URL

That can be expected: updating searchParams may reserialize the query. Compare the parsed values before treating the altered spelling as a failure.

Results differ between runs or machines

Make the test record the browser version, operating system, exact input, and whether the comparison concerns parsed meaning or exact serialization. If navigation or a server is involved, capture the value at that boundary so you can distinguish URL construction from later application behavior.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For a screenshot of a URL’s rendered page, ScreenshotNeo accepts one GET request and returns an image or PDF. For example, this cURL request captures the search page with a query value encoded as a URL parameter:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/search?q=red%20blue -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Screenshot capture can help inspect what a URL renders, but it does not replace checking parsed query values across browsers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for ScreenshotNeo to get 1,000 free screenshots a month with no card.

Frequently Asked Questions

Does %20 mean the same thing as + in every URL?

Not necessarily. In the relevant form-style query serialization, a plus represents a space, but application-specific decoding and contracts determine how a server interprets a request. Test the parsed value and the receiving application.

Should my cross-browser test require identical URL strings?

Only when the exact serialized representation is part of your application or server contract. Otherwise, assert that the parameter parses to the intended value.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.