UTM checker for the links you did not build.
paste a campaign URL and this tells you what is wrong with the tagging before you trust a single number in the report. it catches the capital letters, the spaces, the duplicate parameters and the missing utm_medium, then hands back a cleaned up version. free, nothing is uploaded.
| parameter | value | what it is |
|---|---|---|
| paste a link above and every parameter on it appears here. | ||
- utm_source, utm_medium or utm_campaign missing
- capital letters in a value
- spaces, %20 or + in a value
- the same parameter twice
- an anchor before the query string
- utm_term or utm_content present but empty
- an unusual utm_medium
- http instead of https
- ad platform click ids riding along
Why one campaign quietly becomes three rows
GA4 and almost every other analytics platform store UTM values as literal strings and match them exactly. that means utm_source=Google, utm_source=google and utm_source=GOOGLE are three different sources sitting in three different rows. nothing merges them, nothing warns you, and each row shows a third of the traffic and a third of the conversions. at the end of the month none of them looks like it worked.
spaces do the same thing by a different route. a space in a value gets sent as %20 or as +, so spring launch and spring_launch are two values that sort nowhere near each other in a long list. some reporting tools decode it back to a space and some show the raw %20, which is how one campaign ends up looking like two even inside the same account.
the fix is boring and it works: lowercase everything, underscores instead of spaces, and a medium taken from a short fixed list you agreed once. if you are making new links, the UTM link builder applies all of that by default. this page is for the links that already exist and are already out.
What a duplicate parameter actually does
a query string is an ordered list of key and value pairs, not a dictionary, so ?utm_source=google&utm_source=google-ads is a perfectly legal URL. what happens next is undefined and depends entirely on what reads it. some systems take the first value, some take the last, some join them into one string, and a redirect in the middle can reorder them before anyone gets a look.
this is the failure mode most link checkers miss, and there is a specific reason why. in javascript, searchParams.get('utm_source') returns only the first match and reports nothing unusual, so a checker written the obvious way sees a valid link. searchParams.getAll() returns the whole list. this page uses getAll, which is why a repeated parameter shows up here as two rows and a hard fail.
duplicates almost always come from a link that was tagged twice: an already tagged URL pasted into a builder, a shortener that appends its own tags, or a landing page redirect that adds a source of its own. when you see one, go back to wherever that link is stored and fix it there. patching the copy in one ad leaves the other four wrong.
The click ids you did not set
gclid, fbclid, ttclid, msclkid, twclid and li_fat_id are click identifiers, and you do not write them. the ad platform appends its own at the moment of the click: gclid is Google Ads, fbclid is Meta, msclkid is Microsoft Ads, ttclid is TikTok, twclid is X and li_fat_id is LinkedIn. each one carries the auction and click detail back to the platform so it can tie a conversion to the exact click that caused it.
so a click id in a browser address bar is normal and correct. a click id in a link you are about to publish is not. it means somebody clicked an ad, copied the URL out of their address bar, and pasted it into a brief. that one dead id will now ride along on every impression of the new campaign, matching nothing, making the URL longer and occasionally getting stripped by a redirect on the way through. this checker leaves them out of the cleaned version for that reason.
worth knowing that click ids and UTMs answer different questions. the click id is how the ad platform attributes its own conversions. the UTM is how your analytics attributes the visit. the one overlap is Google: if your Google Ads account is linked to GA4, the auto-tagged gclid alone is enough for GA4 to attribute that traffic, which is why manually tagging Google Ads links is usually unnecessary and can override the auto-tagged data. no other platform click id does anything for your analytics.
Clean tags are the easy half. Knowing what to cut is the other one.
if the tagging is fixed and the report still will not tell you which channel is carrying the growth, that is the conversation. bring one account to the breakdown call.
Common questions
What does this UTM checker actually check?
it parses the link, lists every parameter it finds, then runs a fixed set of checks: the three required tags, capital letters, spaces, duplicate parameters, empty values, an unusual medium, http instead of https, an anchor sitting in front of the query string, and any ad platform click ids riding along. each one comes back as pass, warn or fail with the reason, and you get a cleaned up link at the end.
Why do capital letters break a UTM campaign?
because the values are stored as literal strings and matched exactly. utm_source=Google and utm_source=google become two separate sources in GA4, so one campaign arrives as two rows and each looks half as good as it really was. nothing warns you at the time and it is not fixable afterwards without reprocessing the data, so lowercase everything.
What happens if the same UTM appears twice in a link?
the behaviour is undefined and depends on what reads it. a query string is an ordered list of pairs, so a repeated key is legal, and different platforms take the first, take the last, or join them. treat it as broken rather than guessing which one wins. note that searchParams.get() returns only the first match and hides the duplicate entirely, which is why a lot of checkers never report it.
What is gclid and should I remove it?
gclid is the Google Ads click id, appended by Google when someone clicks an ad. it belongs on a URL in a browser address bar, not in a link you are about to publish. if you find one in a link you inherited, somebody copied it out of their address bar after clicking an ad, and it will never match a click again, so take it off. same goes for fbclid, ttclid, msclkid, twclid and li_fat_id.
My link has UTMs but the traffic still shows as direct, why?
usually a redirect. if the link goes through a shortener, a vanity domain or an http to https hop, some setups drop the query string on the way and the tags never arrive. test the final landing URL rather than the one you pasted into the ad. a link opened inside an app browser, a QR scan and an email client that rewrites links can all do the same thing.
Is the link I paste sent anywhere?
no. the parsing and every check run in your browser with javascript. nothing is uploaded, nothing is stored and there is no account. you can go offline after the page loads and it still works, which matters here because a campaign URL usually carries a client name or an internal path in it.