Method
The arithmetic
Values are trimmed, lower-cased, and have runs of whitespace collapsed to a single hyphen before anything else happens. They are then written into the link with the browser's own URL parser, so percent-encoding is applied once by the same code the browser uses to read the link back. An existing query string is kept, a utm_ parameter that is already present is replaced rather than duplicated, and the fragment stays at the end. Empty optional fields are left out entirely instead of being written as blanks.
value = lowercase(trim(input)) with whitespace → "-"
tagged = url + (url already has a query ? "&" : "?") + utm_source=… & utm_medium=… & utm_campaign=…
Worked example
One run through the numbers
Tagging https://example.com/pricing with the source Newsletter, the medium Email, and the campaign name Spring Sale produces https://example.com/pricing?utm_source=newsletter&utm_medium=email&utm_campaign=spring-sale. The capitals are gone and the space has become a hyphen, which is the difference between one campaign row in your reports and three.
Paste your own link above. Once the traffic arrives, the funnel calculator is where the tagged sessions turn into a pass rate.
Asked often
UTM Builder: questions that come up
Which UTM parameters are actually required?
Source, medium, and campaign. Analytics tools will accept a link with only some of them, but a session tagged with a campaign and no source lands in an unhelpful bucket, so filling all three is the practical minimum. Term and content are for paid keywords and creative variants and can be left blank.
Does adding UTM parameters hurt SEO?
Tagged URLs are for links you place yourself — emails, ads, social posts, partner links. The concern with crawlers is duplicate URLs, which is handled by the self-referencing canonical tag a well-built destination page already has. What you should not do is tag internal links between your own pages, because that restarts the session attribution mid-visit.
Why does the builder lower-case my values?
Because analytics platforms compare the strings exactly. Capitalisation that varies between the ad platform, the email tool, and the link you pasted by hand fragments one campaign into several rows, and the fragments are usually too small to notice individually.
What happens to a link that already has a query string?
It is kept. The UTM parameters are appended with an ampersand rather than a question mark, and if the link already carries a utm_source it is replaced rather than added a second time. Anything after a # stays at the end of the link where the browser expects it.