A URL query is the part after ? : name=value pairs joined by &
In a web address, the query runs from the first ? up to a #. In https://shop.example.com/products?color=white&size=9.5 the query is color=white&size=9.5: two pairs split by &, with the names color and size and the values white and 9.5. Queries carry things like a search phrase, a page number, filter choices or advertising tags to the server or script behind the page. What each name means is decided by each site.
This tool splits the query of a pasted URL into a name and value table and rebuilds the URL as you edit. Percent-encoded text is shown as readable characters, and pairs you do not touch keep their original spelling. Tracking parameters added by ad and analytics companies are flagged only when their official documentation confirms them, and you can strip them in one click. It also shows which value PHP, Python, Java and other servers read when the same name appears more than once. The URL you paste never leaves your browser.
When you need to see a query as a table
- Before sharing a link: links from ads and newsletters often end in a long tail of
utm_source,gclidorfbclid. Without it the URL is shorter, and an ID that points to one ad click or one email recipient is not reused for someone else's visit. - Building or checking campaign links: you can see at a glance whether utm_source, utm_medium and utm_campaign are spelled right and whether a name appears twice. '+ UTM' adds the three as empty rows.
- Checking an API request URL: change one value and resend, or see how an empty value and a name without = are passed on. The result can also be copied as JSON.
- Fixing a return URL after login or checkout: the address inside
redirect_uriornextis encoded a second time and hard to read. 'Open as table' lets you edit the inner URL separately and put it back into the outer one. - Checking that filters reach the server: PHP reads
color=white&color=blackas one value (the last), while Python reads a list of two. You can compare what the server really receives. - Reading URLs from access logs: server logs and analytics keep search terms and filters encoded. Decode them item by item.
How to use it
- Paste: put a full URL (
https://…), a query starting with?, or justname=kim&page=2into 'Original URL'. The query is split into a name and value table, and the start of the URL and the part after#get their own boxes. - Strip tracking: in the length bar, striped cells are click and visitor IDs and light orange cells are campaign tags. 'Remove click IDs' takes out only IDs such as gclid and fbclid. 'Remove all tracking' also removes campaign tags such as UTM. 'Undo' brings them back right away.
- Edit the table: type values as plain, unencoded text. Enter moves to the next cell and adds a new row on the last line (Shift+Enter makes a line break inside a value). × removes a row, 'Sort by name' sorts, and 'Reset' goes back to the start.
- Open a URL inside a value: when a value is a URL, 'Open as table' appears in the flags column. Edit the inner URL the same way, then press 'Back to outer URL' to put it into the outer value.
- Copy: copy the rebuilt URL as a full URL, query only or JSON. Edited items are underlined. You also choose whether edited spaces are written as
+or%20, and whether untouched items keep their original spelling. - See what the server reads: click a row and the cards below show how eight environments read that name. The color on the left of each card is the way it reads (first value, last value, list, comma-joined, dropped).
The characters that split a query
The query parsing rules of the WHATWG URL Standard (application/x-www-form-urlencoded) cut the query at &, split each piece at its first = into a name and a value, turn + into a space, turn %XX back into bytes and read them as UTF-8. The browser's URLSearchParams follows exactly this, and so does this tool when it builds the table.
| Character | What it does | Example | Value shown in the table |
|---|---|---|---|
? | Starts the query, right after the first ? of the URL. A ? inside the query is normally just a character | /search?q=a?b | q → a?b |
& | Boundary between items | a=1&b=2 | a → 1, b → 2 |
= | Boundary between name and value. Only the first = counts | a=1=2 | a → 1=2 |
# | Ends the query and starts the fragment. The fragment is not sent to the server | ?q=a#top | q → a, fragment top |
+ | A space | q=red+shoe | q → red shoe |
%XX | One byte (two hexadecimal digits) | k=%C3%A9 | k → é |
; | Not a separator | z=1;w=2 | z → 1;w=2 |
A bare flag with no equals sign is read as an item with an empty value, the same as flag=, and an empty piece such as && is skipped. The HTML 4.01 specification recommended that servers accept ; in place of &, but today's URL Standard and Python's parse_qs use & only. Go treats a pair that contains ; as invalid and drops it.
How names and values are read
| Raw query | Value in the table | Why |
|---|---|---|
q=red+shoe | red shoe | + is a space |
lang=C%2B%2B | C++ | A literal plus sign is written %2B |
lang=C++ | C followed by two spaces | Both + are read as spaces |
p=100% | 100% | A % without two hex digits after it stays a character (flagged 'bad %' in the flags column) |
b=%2526 | %26 | Decoded only once. A twice-encoded value keeps one layer |
e=%E9 | � | This is 'é' in Windows-1252, a byte that is not valid UTF-8 (flagged 'Not UTF-8') |
flag | (empty value) | With no equals sign the value is empty (flagged 'No =') |
Values written in an old, non-UTF-8 encoding look garbled in the table. If you do not edit such an item, 'Keep original notation' leaves the original bytes alone, so the rebuilt URL still opens as before. To see what the garbled characters were, use the encoding auto-detection in the URL Encoder / Decoder.
Tracking parameters: what is safe to remove
A tracking parameter has nothing to do with the page content. It tells the site which ad, email or campaign a visitor came from. Without it the same page usually opens, but the site owner can no longer tell where that visit came from. The tool flags only names confirmed in official company documentation and sorts them into two groups.
- Click and visitor IDs (striped cells in the bar): values that point to one ad click, one email recipient or one visit. There is no reason to pass them on, so it is better to remove them before sharing.
- Campaign tags (light cells): labels that say which source, medium and campaign a link belongs to. Keep them on campaign links you build yourself. When you forward someone else's link, you may remove them.
| Name | Added by | Meaning | Group |
|---|---|---|---|
utm_source utm_medium utm_campaign utm_term utm_content | The advertiser who builds the link (read by Google Analytics) | Source, medium, campaign, keyword, ad content | Campaign tag |
utm_id utm_source_platform utm_creative_format utm_marketing_tactic | The advertiser (the source platform is set automatically by some Google platforms) | Campaign ID, source platform, creative format, targeting tactic | Campaign tag |
gclid gbraid wbraid | Google Ads auto-tagging | Ad click IDs (gbraid and wbraid are for iOS conversion measurement) | Click / visitor ID |
gad_source gad_campaignid | Google Ads | Ad source and the ID of the campaign that produced the click | Campaign tag |
dclid | Campaign Manager 360, Display & Video 360 | Display ad click ID | Click / visitor ID |
srsltid | Google Merchant Center auto-tagging | Marks a visit from a Google free product listing | Click / visitor ID |
_gl | Google tag (cross-domain measurement) | Linker value that carries visit data to another domain | Click / visitor ID |
fbclid | Meta | Click ID on Facebook and Instagram links | Click / visitor ID |
msclkid | Microsoft Advertising auto-tagging | Ad click ID | Click / visitor ID |
ttclid twclid li_fat_id | TikTok · X · LinkedIn | Each company's ad click ID | Click / visitor ID |
mc_eid | Mailchimp (campaigns with e-commerce tracking on) | Email recipient ID | Click / visitor ID |
mc_cid | Mailchimp | ID of the email campaign that holds the link | Campaign tag |
_hsenc _hsmi | HubSpot email | Recipient identification and email click tracking | Click / visitor ID |
yclid | Yandex Direct | Ad click ID | Click / visitor ID |
mtm_campaign pk_campaign and others | Matomo analytics | Campaign name, keyword and source labels | Campaign tag |
NaPm | Naver Ads (a South Korean search service) | Added when someone clicks an ad, used for conversion tracking | Click / visitor ID |
Values with no official explanation, such as si on YouTube share links and igsh on Instagram share links, are not in the list. If you know what they do and want them gone, press × on the row. Names that only look similar, such as ref, source and from, are left alone because some sites use them for page content.
The same name twice: servers read it differently
When a name repeats, as in tag=red&tag=blue, the URL Standard keeps both items in order. Which value the code uses afterwards is up to the language or framework on the receiving end, and they differ. Many shops send several values on purpose for filters, so a server that reads only one value loses part of the selection.
| Environment | Code that reads it | Result | How it reads |
|---|---|---|---|
| JavaScript | new URLSearchParams(q).get('tag') | "red" | First value (getAll returns both) |
| PHP | $_GET['tag'] | "blue" | Last value |
| Python | parse_qs(q)['tag'] | ["red", "blue"] | All as a list |
| Django | request.GET['tag'] | "blue" | Last value (getlist returns both) |
| Node · Express 5 | req.query.tag | ["red", "blue"] | All as a list (default parser: querystring) |
| Java Servlet | request.getParameter("tag") | "red" | First value (getParameterValues returns both) |
| Go | r.URL.Query().Get("tag") | "red" | First value |
| ASP.NET Core | Request.Query["tag"] | "red,blue" | Joined with a comma when turned into a string |
PHP reads tag[]=red&tag[]=blue, with brackets after the name, as an array, and turns dots and spaces in a name into underscores. So price.min=10000 becomes $_GET['price_min'] and can collide with a separate price_min item. Python's parse_qs drops empty values by default, so flag and empty= leave no key at all; pass keep_blank_values=True to keep them. Go drops any pair that contains ; or a bad %. 'What the server reads', below the tool, works out these differences for the item you click.
Putting another URL inside a value
When a whole URL goes into a value, as with redirect_uri, next or returnUrl, the ? & = # of the inner URL must all be encoded so they are not read as characters of the outer query. If you paste it unencoded, everything after the inner & becomes a separate item of the outer URL.
| How it is inserted | Items the outer URL reads |
|---|---|
Pasted as is?next=https://shop.example.com/cart?item=12&size=L | next → https://shop.example.com/cart?item=12 size → L (split apart) |
Encoded?next=https%3A%2F%2Fshop.example.com%2Fcart%3Fitem%3D12%26size%3DL | next → https://shop.example.com/cart?item=12&size=L |
If the inner URL has encoded values of its own, they are encoded once more and look like %252F. 'Open as table' shows the inner URL, with one layer removed from the outer value, as a separate table. After you edit it, 'Back to outer URL' encodes it again and puts it back. In the 'Login redirect' example, the redirect_uri holds one more layer: next=%2Fcart.
What changes when the URL is rebuilt
The same query can be written in several ways. A space as + or %20, flag or flag=, hex digits in upper case %C3 or lower case %c3 are all read as the same value. Most servers do not care, but a signed URL may stop working, depending on the server, if it is written differently from how it was signed. That is why 'Keep original notation' is on by default and only edited items are re-encoded.
| Original item | Keep original notation | Off · space as + | Off · space as %20 |
|---|---|---|---|
q=red%20shoe | q=red%20shoe | q=red+shoe | q=red%20shoe |
flag | flag | flag= | flag= |
n=%c3%a9 | n=%c3%a9 | n=%C3%A9 | n=%C3%A9 |
t=~tilde | t=~tilde | t=%7Etilde | t=~tilde |
a=x;y | a=x;y | a=x%3By | a=x%3By |
The + rule is how HTML forms and URLSearchParams write spaces, and the %20 rule is how JavaScript's encodeURIComponent() does. The browser's URLSearchParams rewrites every item even when you delete only one, so %20 turns into + (see the code below). Signed URLs, such as an AWS S3 presigned URL (X-Amz-Signature) or an Azure Storage SAS (sig), must not be edited; you need a new signature instead. The tool warns you when you edit a URL that carries a signature.
Doing it in code
// JavaScript
const u = new URL('https://shop.example.com/p?color=white&color=black&q=red%20shoe&utm_source=newsletter');
u.searchParams.getAll('color'); // ['white', 'black']
u.searchParams.delete('utm_source');
u.toString(); // 'https://shop.example.com/p?color=white&color=black&q=red+shoe' (%20 became +)
# Python
from urllib.parse import urlsplit, parse_qsl, urlencode, urlunsplit
s = urlsplit('https://shop.example.com/p?color=white&color=black&flag&utm_source=newsletter')
pairs = [(k, v) for k, v in parse_qsl(s.query, keep_blank_values=True) if not k.startswith('utm_')]
urlunsplit(s._replace(query=urlencode(pairs)))
# 'https://shop.example.com/p?color=white&color=black&flag=' (flag became flag=)
// PHP
parse_str('tag=red&tag=blue&size[]=S&size[]=M&price.min=10000', $q);
// $q = ['tag' => 'blue', 'size' => ['S', 'M'], 'price_min' => '10000']
http_build_query(['tag' => ['red', 'blue']]);
// 'tag%5B0%5D=red&tag%5B1%5D=blue'
All three parse the query and write it out again, so none of them keeps the original spelling. If the original spelling matters, cut the pieces you want out of the query string and join the rest yourself. That is what 'Keep original notation' does in this tool.
Common mistakes
- Typing %20 into a value cell: values in the table are decoded text. If you type
%20, the tool sees the characters %, 2 and 0 and sends out%2520. Type a plain space. - Pasting C++ straight into a query:
lang=C++is read as 'C' plus two spaces. If you type C++ into a value cell, the tool writes it asC%2B%2B. - Deleting a repeated name as if it were an error:
color=white&color=blackmay be a filter with several choices. Check how the server reads it first. - Deleting items with an empty value:
empty=orflagcan still mean something. Some servers switch a feature on just because the item exists. - Treating what follows # as query: the
x=1in/page#tab?x=1is part of the fragment, is not sent to the server, and the tool keeps it in the fragment box. - Forgetting to encode a URL inside a value: the
&of the inner URL splits the outer item in two. - Only extending the expiry of a signed URL: changing
X-Amz-Expiresbreaks the signature, and the request is rejected.
Limits
- The tool splits the query only at
&, as the URL Standard does. Sites that split items with;or,, and parameters inside the path (/a;b=1/), are not split. - Values are decoded as UTF-8 only. Values in older encodings look garbled, and editing such an item re-encodes it as UTF-8.
- The start of the URL (scheme, host, path) and the
#fragment are handled as written and are neither encoded nor cleaned up. - Even with 'Keep original notation', changing any item drops empty pieces (
&&) and a trailing&. - Only tracking parameters confirmed in official documentation are flagged. Any tracking value not on the list you have to remove yourself.
- 'What the server reads' shows each environment's default behavior. Changing settings or using another parser (qs, Rack and so on) changes the result, and limits such as PHP's max_input_vars are not reflected.
- The tool never connects to the URL, so it does not check whether the address opens or is safe.
Basis: query parsing follows the application/x-www-form-urlencoded rules of the WHATWG URL Standard, tracking parameters come from each company's official help pages, and per-server behavior was checked on October 22, 2026 against runs of PHP 8.5, Python 3.14 and Node.js 26 and the official documentation of Java Servlet, Go, ASP.NET Core, Django and Express 5.
Sources
- 01WHATWG URL Standard: application/x-www-form-urlencodedSplitting at &, the first =, + as a space, percent-decoding and serialization
- 02MDN: URLSearchParamsget, getAll, delete, toString
- 03Google Analytics Help: Collect campaign data with custom URLsMeaning of the nine utm parameters
- 04Google Ads Help: Google Click Identifier (GCLID)The value auto-tagging adds to every ad click
- 05Google Ads Help: gbraid and wbraidParameters for iOS conversion measurement
- 06Google Ads Help: gad_source and gad_campaignidAd source and campaign ID
- 07Google tag: cross-domain measurementThe linker parameter _gl
- 08Meta: fbp and fbc parametersThe click ID added to links (fbclid)
- 09Ad and email company documentation: dclid · srsltid · Microsoft click ID · ttclid · twclid · li_fat_id · mc_cid, mc_eid · _hsenc, _hsmi · yclid · Matomo · NaPmOfficial explanation from the company that adds each parameter
- 10PHP: Variables From External SourcesDots and spaces in names become underscores; [] arrays
- 11Python: urllib.parse.parse_qskeep_blank_values defaults to False; only & separates
- 12Django: QueryDict__getitem__ returns the last value, getlist returns all
- 13Express 5: app settings (query parser)The default "simple" is Node querystring
- 14Java EE: ServletRequest.getParameterWith several values, the first of getParameterValues
- 15Go: net/urlValues.Get returns the first value; a pair with ; is invalid
- 16.NET: StringValues.ToStringSeveral values joined with commas into a string
- 17HTML 4.01 Appendix B.2.2The old recommendation to accept ; instead of &
Frequently asked questions
What is a URL query (query string)?
It is the part of a URL after the ? and before any #. Pairs like color=white&size=9.5 are joined with &, and carry things such as search terms, page numbers, filters and tracking values to the server. Each site decides what every name means.
Can I paste just name=kim&page=2 without the question mark?
Yes. The tool accepts a full URL, a query that starts with ?, and a query with no question mark. For a full URL, the start of the address and the # fragment get their own boxes, and you can copy the rebuilt full URL or only the query.
Does the page open the same without the tracking parameters?
Usually yes, because values such as utm and gclid are used to count where a visit came from. Some sites do show a different notice or coupon by traffic source, though, so if the page looks different, use the original URL. You can also remove only the click IDs and keep UTM.
With tag=red&tag=blue, which value gets used?
It depends on the server. PHP and Django read the last value, blue. JavaScript get(), Java Servlet and Go read the first, red. Python parse_qs and Express 5 give a list of both, and ASP.NET Core joins them as red,blue. Click an item and the comparison appears below the tool.
Why does the + in q=red+shoe show as a space?
Under the form rules used to read queries, + means a space. A literal plus sign has to be written %2B, and if you type C++ into a value cell, the rebuilt URL contains C%2B%2B.
I edited the table and %20 turned into +. Is that the same value?
Yes, when a query is read, %20 and + are both a space. With 'Keep original notation' on, items you did not touch stay exactly as written, and only edited items use the rule you choose (+ or %20). A signed URL needs every character to match, so it needs a new signature instead.
How do I edit a URL that sits inside a value?
When a value such as redirect_uri or next is a URL, 'Open as table' appears in the flags column. It opens the inner URL as its own table, and after you edit it, 'Back to outer URL' encodes it again and puts it into the outer value.
Is the URL I enter sent to a server or stored?
No. Splitting, rebuilding, tracking detection and the per-server comparison all run in this browser. The URL is not sent or stored, it is not added to the page address, and the tool never connects to it.