Extracts the query component of a URL, optionally parsing it into a list.
get_query(
url,
protocol_handling = "keep",
format = c("string", "list"),
decode = TRUE,
query_handling = c("keep", "drop", "filter", "allow"),
params_keep = NULL,
params_drop = NULL,
params_case_sensitive = FALSE,
sort_params = FALSE,
empty_param_handling = c("keep", "drop"),
decode_plus = FALSE,
scheme_policy = c("infer", "require"),
scheme_acceptance = c("web", "general"),
url_standard = NULL
)A character vector (format="string") or list (format="list").
A character vector of URLs.
A character string specifying how to handle
protocols. Defaults to "keep".
Regardless of this option, rurl only processes authority-based URLs whose
scheme is one of http, https, ftp, or ftps; a scheme-bearing input with any
other scheme (e.g. mailto:, tel:, ws:) yields
parse_status = "error". Scheme inference (below) also requires the
input to be host-shaped: a scheme-less string that is not a host (e.g.
"asdfghjkl", "12345", "/path") or is a non-canonical
IP literal (integer/hex/octal/short forms, or leading-zero octets like
"192.168.010.1") is rejected as "error" rather than having a
scheme fabricated for it.
"keep": If a supported scheme exists (http, https, ftp, ftps), it's
used. If no scheme and the input is host-shaped, "http://" is added;
otherwise the input is not a URL and yields "error".
"none": If a supported scheme exists, it's used. If no scheme, then no scheme is used (scheme component will be NA).
"strip": Any existing scheme is removed (scheme component will be NA).
"http": The scheme is forced to be "http".
"https": The scheme is forced to be "https".
Return format: "string" (default) or "list" for parsed elements.
Logical; if TRUE (default), percent-decodes the query
(the whole string for format="string", keys/values for format="list").
Set FALSE to obtain the query as written: the raw query for the default
query_handling = "keep", or the canonical re-encoded form (uppercase hex,
%20, %26/%3D) once any filtering is requested.
A character string controlling whether (and how) the
query string is included in clean_url. Defaults to "drop", which preserves
the historical query-free clean_url. The raw query result field is never
affected by this option — it always reports the faithful original query.
"drop": (Default) clean_url carries no query, exactly as before.
"filter": Keep contentful params, dropping known trackers via a
built-in denylist (e.g. utm_*, fbclid, gclid). params_drop
extends the denylist; params_keep rescues names (winning over both the
denylist and empty-dropping).
"allow": Keep only params whose names match params_keep; all
others are dropped. Here params_keep is an inclusion criterion only,
not an empty-rescue.
"keep": Keep every param, re-encoded into canonical form (not the
verbatim original — that stays on the query field).
In every non-"drop" mode the surviving query is re-encoded canonically
(uppercase percent-hex, spaces as %20) and appended after the path. The
query is intentionally EXEMPT from case_handling (query values are
case-sensitive — tokens, IDs, signatures), so under
case_handling = "lower" or "upper" the clean_url is no longer
uniformly cased: scheme/host/path fold but the query keeps its original
case. Because clean_url is the canonical_join key, any
non-"drop" mode also brings the query into that join key (so ?id=1 and
?id=2 stop collapsing, while utm-only differences still collapse under
"filter").
Character vector of parameter-name globs (only * is
special), or NULL (default). In "filter" mode this is the rescue list; in
"allow" mode it is the allowlist. Ignored in "drop"/"keep".
Character vector of parameter-name globs to add to the
built-in denylist in "filter" mode, or NULL (default). Ignored in
"drop"/"allow"/"keep".
Logical (default FALSE). Controls whether the
denylist and params_keep/params_drop matching is case-sensitive.
Logical (default FALSE). When TRUE, surviving params
are stably sorted by decoded key. Active in "filter"/"allow"/"keep".
One of "keep" (default) or "drop". "drop" removes
empty-valued params (e.g. ?ref=), except those rescued by params_keep
in "filter" mode.
Logical (default FALSE). When TRUE, + in query
values is treated as a space (HTML-form decoding) before percent-decoding.
FALSE keeps + literal (RFC 3986 generic behavior).
Controls whether scheme-less, host-shaped input is
accepted (an input-acceptance axis, distinct from protocol_handling,
which only controls how the scheme is presented, and from url_standard,
which controls interpretation). Defaults to "infer".
"infer": (Default) Fabricate http:// for scheme-less host-shaped
input (e.g. example.com parses as http://example.com), a
browser-omnibox-style affordance. This is the historical behavior.
"require": Reject scheme-less input — a scheme-less host-shaped
value becomes parse_status = "error" rather than gaining a fabricated
scheme. Use this for a strict, pure-parser posture. Note this governs
only bare host input; scheme-relative //host input is governed
separately by scheme_relative_handling.
Which scheme tokens may enter parsing (a
scheme-acceptance axis, distinct from scheme_policy, which governs
scheme-less input, and from url_standard, which governs interpretation).
Defaults to "web".
"web": (Default) Only the curated web-scheme allowlist
(http/https/ftp/ftps/file) is admitted; a scheme-bearing input
outside it is parse_status = "error". This is the historical,
byte-for-byte compatible behavior.
"general": Admit any syntactically valid scheme token and parse
opaque (mailto:x), non-special (foo://host), and RFC-generic URLs.
Requires an explicit url_standard ("rfc3986" or "whatwg"), which
decides the interpretation; general with url_standard = NULL is an
error. Non-special / opaque hosts receive no www-stripping, no domain/TLD
derivation, and are never run through the IDNA/punycode helpers.
A non-special scheme with no // is an opaque path: it has no
authority, so host, user, port and the domain/tld columns are
all NA and the entire remainder is the path (query/fragment are
still split off). This includes mailto: — the recipient's @ never
re-triggers authority parsing. To decompose a mailto: recipient, use
the accessors (get_host() / get_domain() / get_user(), ADR 0012 D7)
or get_mailto_recipients(); those deliberately return a recipient's
parts where this table presents NA, because a recipient domain is
extraction metadata, not the URL's authority.
Note that file: is admitted under both values, including the default.
A file: URL denotes local-filesystem access, and one with a non-empty
host (file://server/share/x) is a UNC path on Windows, so dereferencing
it reaches a remote SMB share. rurl parses file: URLs; it never opens
them. Restricting schemes before anything dereferences them is the
caller's job — see SECURITY.md.
Optional top-level standard profile: NULL (default),
"rfc3986", or "whatwg". With NULL the behavior is exactly what the
individual low-level options select (fully backward compatible). When set,
it selects a coherent set of standard-conformant behaviors for the axes it
governs — path percent/dot handling, the host IPv4/reg-name model, and
case_handling — so callers do not have to hand-assemble the low-level
knobs. Passing a governed low-level knob (path_normalization or
case_handling) with a value the selected
profile would not choose is an error; passing the value the profile would
pick is accepted (only case_handling = "lower_host" is accepted under a
selector — "keep", "lower", and "upper" all conflict, since "lower"
also lowercases the path, which neither standard sanctions). Added as the
last argument so existing positional calls keep their meaning; always
pass it by name. Under "whatwg" the selector additionally recognizes a
literal backslash as a path separator for WHATWG-special schemes
(http/https/ftp) and nulls default ports in parse output; use
port_handling = "strip_default" for spec-style clean URL port rendering.
See resolve_url for url_standard-governed
reference resolution. The selector does not govern whether
port_handling may be set (it is a standalone editorial knob), nor does it
govern path_encoding (an orthogonal path-presentation knob that layers
on any profile), IDNA rendering, or query handling.
Because decode = TRUE is the default, this accessor can return
characters the URL itself never contained literally — including control
characters such as CR and LF, which %0D/%0A decode to. Treat the result
as untrusted input: do not interpolate it into a header, a log line, a
shell command, or a SQL statement without escaping it for that sink, and do
not assume it is single-line. Pass decode = FALSE when you want the query
exactly as written, with no decoding step at all.
The underlying parse preserves the raw query string byte-for-byte (a bare
key such as ?flag stays flag, not flag=). By default this accessor
still percent-decodes for readability (decode = TRUE); pass
decode = FALSE to obtain the raw query exactly as written in the URL.
Under url_standard = "whatwg" the underlying query carries the standard's
percent-encoded spelling (the query percent-encode set is applied, so a
literal space becomes %20); under url_standard = "rfc3986" or no
selector it is the raw source spelling. That distinction is only visible
with decode = FALSE, since decoding collapses both spellings.
The filtering arguments (query_handling, params_keep, params_drop,
params_case_sensitive, sort_params, empty_param_handling,
decode_plus) share the engine used by get_clean_url, but
default to query_handling = "keep" here: an accessor returns the query as
found unless you ask it to filter. When no filtering or reordering is
requested (the default profile), the output is byte-for-byte identical to
earlier releases; once you opt in, the surviving params are selected first
and only then rendered per format/decode.
get_query("http://example.com/path?a=1&b=2")
get_query("http://example.com/path?a=1&b=2", format = "list")
# Drop trackers, keep contentful params:
get_query(
"http://example.com/?utm_source=nl&id=42",
query_handling = "filter"
)
# Canonical (re-encoded) form:
get_query(
"http://example.com/?a=1%262",
query_handling = "keep", decode = FALSE
)
Run the code above in your browser using DataLab