Form URL encoding 2026-11-05
Form URL encoding is the application/x-www-form-urlencoded format for serializing an ordered list of name/value pairs. It is used by URLSearchParams and common form-processing conventions. Repeated names are allowed; the data model need not be a dictionary with one value per name.[ref]
For example, the three pairs ("q", "a b+c"), ("tag", "x") and ("tag", "y") serialize as q=a+b%2Bc&tag=x&tag=y.
Here the space becomes +, while the literal plus in the value becomes %2B. Parsing the result recovers a b+c and both tag values. Replacing every plus with a space before deciding which encoding convention applies would misread data from other URL contexts.
Structural separators must also be distinguished from value data. The encoded pair q=a%26b has one value, a&b, rather than two pairs. The form parser first recognizes pair boundaries and then decodes their component data. Percent-encoding inside a component is consequently not an instruction to reinterpret the resulting characters as new separators.[ref]
For modern serialization, text is encoded as UTF-8 bytes before the relevant bytes are percent-encoded. The name/value pair ("word", "café") therefore produces word=caf%C3%A9. This connects a text character with its byte representation rather than assigning one arbitrary percent code to the whole character.[ref]
A query string can use this format, but generic URL syntax does not require every query to be interpreted this way. State the parser and encoding when comparing an original spelling with its recovered list of values.
Percent-encoding 2026-11-05
Percent-encoding represents a byte using a percent sign followed by two hexadecimal digits. For example, byte value 32 is written %20. Non-ASCII text is first encoded as bytes: in UTF-8, é becomes the two bytes hexadecimal C3 A9, represented as %C3%A9.[ref]
A useful example distinguishes data from delimiters. The path in https://example.org/a/b has two segments; the path in https://example.org/a%2Fb retains the encoded slash within one segment in the parsed URL record. A server may apply additional decoding, but the two spellings must not be assumed interchangeable at every processing stage.
Percent-encoding is neither encryption nor a universal instruction to decode repeatedly. The string %252F decodes once to the text %2F; a second decoding changes it again. Likewise, the plus sign is not universally a space: that convention belongs to form-style query string processing, including URLSearchParams, rather than all URL components.[ref]
Query string 2026-11-05
A query string is the component following ? and preceding #, or the end, in a URL. It carries data whose interpretation is defined by the resource or application. The generic syntax does not require a dictionary of names and values.[ref]
For example, https://example.org/search?q=red&tag=a&tag=b#results has query q=red&tag=a&tag=b. An application using form-style conventions can interpret repeated tag entries as a list. URLSearchParams preserves repeated entries: getAll('tag') returns both a and b. Converting that list directly into a dictionary with one value per name can lose information.
Encoding conventions also matter. Under URLSearchParams parsing, q=a+b gives the value a b, while q=a%2Bb gives a+b. That distinction comes from the specified form parser, rather than a general law that every plus in every URL means a space.[ref]
A useful test records both the original query string and the parsing convention. A changed spelling, changed list of values and changed server response are three different observations.
Relative URL reference 2026-11-05
A Relative URL reference identifies a target using a base URL to supply missing context. It can contain a path, a query string or a fragment identifier, without independently specifying an entire network address. Resolution combines the reference with the base according to a defined algorithm.[ref]
Trailing slashes provide an illuminating comparison. Resolving c against https://example.org/a/b gives https://example.org/a/c; resolving it against https://example.org/a/b/ gives https://example.org/a/b/c. In the first case the last base path segment is replaced, while in the second it names a directory-like prefix.
A parent-directory step is similarly concrete: ../image.png against https://example.org/a/b/page.html gives https://example.org/a/image.png. These outcomes follow from URL processing, not from examining an actual filesystem. No network request is needed to calculate them.[ref]
The base is therefore part of the input. Copying the same relative spelling into a document with a different base can change its target even when every character of the reference stays unchanged.
URL 2026-11-05
A URL, or Uniform Resource Locator, is a structured identifier interpreted according to a URL scheme and parsing rules. On the web it can identify the resource a browser navigates to or requests. The URL parser produces a record with components such as scheme, host, port, path, query and fragment; which components are present depends on the particular URL.[ref]
For example, https://example.org:8443/a/b?x=1#part has scheme https, host example.org, port 8443, path /a/b, query string x=1 and fragment identifier part. This hierarchical HTTPS example is useful without implying that every URL must contain a network host or an explicit port.
A Relative URL reference needs a base. Resolving ../img/p.png against https://example.org/a/b/page.html gives https://example.org/a/img/p.png. The base's directory and parent-directory step explain the result. Parsing and serialization can also normalize a spelling: https://EXAMPLE.org:443/a serializes as https://example.org/a, lowercasing the host and omitting the default HTTPS port.[ref]
Percent-encoding represents bytes in a URL spelling, and encoded data must be distinguished from structural delimiters. A query string is not universally a dictionary of name/value pairs, even though many applications use that convention. Nor does successful parsing prove that a resource is reachable or that its content never changes. Distinguishing syntax, identifier interpretation and an actual retrieval prevents an address from being confused with the information returned on one occasion.
URL parser 2026-11-05
A URL parser is a procedure that turns input text, and sometimes a base URL, into a structured URL record or a failure. The record separates components such as scheme, host, path, query string and fragment identifier. URL serialization converts that structured result back into text; it is a different operation from retrieving the identified resource.[ref]
For a worked example, parsing https://EXAMPLE.org:443/a and serializing the result yields https://example.org/a. The host is normalized and the default port omitted. Successful parsing did not test whether the server exists, whether access is permitted or what content would be returned.
Failure also differs from a recoverable validation issue. The WHATWG algorithms can flag some nonconforming input while still producing a record, so an implementation should specify whether it reports validation diagnostics, a usable result or both. A regular expression recognizing one tidy address format is not automatically an implementation of the full parser.
A practical reproducibility check compares parsed fields and the serialized output under a stated parsing model. The WHATWG model and generic RFC syntax serve related purposes but should not be silently treated as identical grammars.
URL record 2026-11-05
A URL record is the structured internal representation of a URL, rather than its original text. The URL parser produces components such as scheme, host, port, path, query string and fragment identifier; URL serialization turns the record into a string. A component can be absent, and the representation of a path depends on the scheme.[ref]
Parse https://example.org:8443/a?x=1#part. The host is example.org, the port is 8443, the path contains a, the query is x=1, and the fragment is part. The separators ? and # belong to the serialized syntax, rather than the stored query and fragment values. These fields let a program change one component without guessing its boundaries by cutting an arbitrary string.
The original spelling need not survive. Parsing https://EXAMPLE.org:443/a yields a lowercased host and no stored explicit port, because 443 is the scheme default. Therefore the record does not contain a faithful log of every character supplied by the user. If an application needs that log, it must retain the input separately.[ref]
URL scheme 2026-11-05
A URL scheme is the leading component before :, selecting a family of interpretation and processing rules. For example, https is the scheme of https://example.org/a. Scheme syntax begins with an ASCII letter and then permits letters, digits, plus, hyphen and period. Comparison is case-insensitive, and standard serialization uses lowercase.[ref]
The scheme does not imply that every URL names a remote server. Compare https://example.org/a with data:text/plain,hello: both have schemes, but the second example carries data in its own spelling rather than naming an HTTPS host. A URL parser must apply the appropriate rules rather than demand a host and port for every case.
The colon also separates a scheme from a familiar relative-path interpretation. The text a:b is parsed as a URL with scheme a, whereas ./a:b can be a Relative URL reference. Adding the initial dot and slash therefore changes the syntactic role of the colon-containing text.
Scheme-specific defaults matter too: omitting port 443 when serializing an HTTPS URL reflects that scheme's default, not a rule that all numerical ports are redundant.[ref]
URLSearchParams 2026-11-05
URLSearchParams is an API for representing and manipulating an ordered list of name/value pairs, commonly obtained from a URL's query string. Repeated names are permitted. It uses form URL encoding, rather than imposing its interpretation on every conceivable query syntax.[ref]
For new URLSearchParams('tag=a&tag=b&q=a+b'), getAll('tag') returns both a and b, while get('q') returns a b. Calling set('tag','c') replaces the repeated entries with one: toString() then returns tag=c&q=a+b. An associative array holding just one value for each name would discard the original repeated-field information.
A literal plus needs a different spelling. Appending the pair q and a+b to a URL's searchParams produces query ?q=a%2Bb. The plus in the data is represented by percent-encoding, whereas the plus in q=a+b represents a space under this parser. These examples distinguish a character in a value from a character used by the encoding convention.[ref]
A URL's searchParams object is connected to that URL; changes update its query. Constructing a separate URLSearchParams from a query string instead gives an independent object, useful when the original spelling must remain available for comparison.[ref]
URL serialization 2026-11-05
URL serialization produces the textual spelling of a structured URL record. It is the output side of processing that begins with a URL parser. The WHATWG serializer returns an ASCII string and can optionally omit the fragment identifier.[ref]
A worked example separates the stages. Constructing new URL('https://EXAMPLE.org:443/a/../b?q=hello%20world~#top') gives href equal to https://example.org/b?q=hello%20world~#top. Lowercasing the host, removing the default port and resolving the parent-directory segment happen during parsing; the serializer exposes the resulting record.
Now call u.searchParams.sort() on that object. Even though there is only one query pair to sort, href becomes https://example.org/b?q=hello+world%7E#top. The decoded query value is unchanged, but URLSearchParams has rewritten its spelling using form URL encoding. Thus changing the query through an API can alter its percent-encoding without changing the value returned by that API.[ref]
A serialized address is also different from a browser's chosen display text or a server's returned content. Comparing those different outputs answers different questions.