UTM Best Practices: 7 Rules for Clean Campaign Data
/ on this page
We checked the standard UTM advice against Google’s own channel rules: the values the engine actually reads when it files your traffic. A surprising amount of it doesn’t survive the check.
Open your acquisition report and count how many times Facebook shows up.
More than once? Then your campaign data is split, and the fix is smaller than you’d think. It comes down to three habits, and one of them does most of the work.
That one is utm_medium: take it from the list Google’s official channel rules actually test, because that field decides where your traffic gets filed. Then lowercase every value, and tag source, medium and campaign together or not at all.
That’s three of the seven rules on this page. The rest is why these and not others. We checked every one against Google’s own docs, and a lot of the standard advice didn’t pass.
One idea holds all seven together, and it isn’t a naming convention.
A convention only sticks if something applies it for you, because the box you type these values into will accept anything you write.
What is a UTM tag?
A UTM is one of the utm_ tags you add to the end of a link so Analytics can file the visit.
Think of the tag they stick on your suitcase at the airport. You don’t write it for yourself to read later. A machine reads it, picks a chute, and the bag goes where the tag says, not where you meant.
Your UTM values are inputs to a rule engine you can’t edit -- and Google says so flatly:
“Channel definitions aren’t case sensitive and can’t be edited.”[1]
Two UTM tags do nearly all the work. utm_source is where the click came from, and utm_medium is what kind of traffic it is. Together they decide the channel.
What is a channel in Google Analytics?
The channel is the bucket Analytics files each visit under: Paid Social, Organic Social, Organic Search, Email.
It behaves like a chute rather than a folder. The visit goes down one of them, it goes down once, and Google picks which one by reading your tag.
Here’s the strange part. The most obvious word to put on a social ad is social, and that’s the one word that files a paid ad under Organic Social.
That’s Rule 1.
True or false: the standard UTM advice
If you tag a paid Facebook ad with the medium social, GA4 files the visit under Paid Social.
You got 0 of 5
If you tag a paid Facebook ad with the medium social, GA4 files the visit under Paid Social.
If one link says Email and another says email, GA4 still files both visits under the Email channel.
Tagging a link with only a campaign name is better than leaving it untagged.
GA4 has a filter that changes all your UTM values to lowercase.
If your tags match none of Google’s channel rules, GA4 files the visit under Unassigned.
It’s false. Paid Social also needs a paid medium, and social isn’t one. Organic Social matches on the source alone, so your ad lands there.
It’s true. Google’s channel rules ignore capital letters, but the values underneath them don’t. So the channel looks right while the medium report splits into separate rows.
It’s false. Google says missing tags show up as (not set) in your reports. Leave the link untagged instead and Analytics can read the page the visitor came from.
It’s false. GA4’s filters only include or exclude internal and developer traffic. The old Universal Analytics had a lowercase filter, and GA4 has nothing like it.
It’s true. Unassigned isn’t an error. It’s where GA4 puts a visit when your values aren’t on Google’s lists.
- Claim 1 of 5If you tag a paid Facebook ad with the medium social, GA4 files the visit under Paid Social.False. Paid Social also needs a paid medium, and social isn’t one. Organic Social matches on the source alone, so your ad lands there.
- Claim 2 of 5If one link says Email and another says email, GA4 still files both visits under the Email channel.True. Google’s channel rules ignore capital letters, but the values underneath them don’t. So the channel looks right while the medium report splits into separate rows.
- Claim 3 of 5Tagging a link with only a campaign name is better than leaving it untagged.False. Google says missing tags show up as (not set) in your reports. Leave the link untagged instead and Analytics can read the page the visitor came from.
- Claim 4 of 5GA4 has a filter that changes all your UTM values to lowercase.False. GA4’s filters only include or exclude internal and developer traffic. The old Universal Analytics had a lowercase filter, and GA4 has nothing like it.
- Claim 5 of 5If your tags match none of Google’s channel rules, GA4 files the visit under Unassigned.True. Unassigned isn’t an error. It’s where GA4 puts a visit when your values aren’t on Google’s lists.
Rule 1 · Take utm_medium from the channel rules, not your own vocabulary
Medium is the parameter Google’s channel rules lean on most. It turns up in more of them than source or campaign, and most of the rules it’s in can be settled by medium alone.[1] So its value comes off Google’s official channel rules, not out of your head.
One scoping note, because it goes unsaid everywhere we looked. Everything here comes from one of Google’s six rule groups, the one headed Channels for manual traffic, which covers links you tag by hand.[1]
Look at what medium is competing with. That’s utm_campaign, where you write the campaign’s name, and it barely shows up in Google’s channel rules at all.[1] Most teams we work with still spend an hour naming campaigns and none on the medium list, which is backwards.
Because everything downstream inherits the channel. And channel is the unit budget conversations happen in.
Now look at the four rules in play, which come in two pairs. Paid Social and Organic Social both watch for a social source like facebook. Paid Search and Organic Search both watch for a search source like google.[1]
The paid rule in each pair needs two things at once: a source on that pair’s list and a paid medium. The organic rule is looser: the source alone is enough, and so is a medium from its own short list, social for Organic Social or organic for Organic Search.[1]
So within a pair, the rules ask one thing about your medium: is it a paid one?
A medium counts as paid if it contains cp, or starts with paid, or is exactly ppc or retargeting.
Google writes that as one pattern. Here it is, if you want to check the wording yourself:
^(.*cp.*|ppc|retargeting|paid.*)$
You don’t have to read it. You only have to notice that social isn’t in there.
That reads like a formatting detail. It is where the money goes.
Where would this UTM land?
?utm_source=facebook&utm_medium=social
social isn’t one of the paid values, so the Paid Social rule fails. But the Organic Social rule matches on the source alone, so it’s the only rule left standing. That’s how your Meta spend lands inside your organic line.
Nobody gets an error. That’s the problem.
The report even looks fine. But the return on that spend reads too low, and that’s how a working channel gets defunded.
The move itself is simple: use paid_social on social ads, never social. Here’s the short version of why.
The usual warning says cpc on a social campaign sends the traffic to Paid Search. It can’t. Paid Search needs a source on Google’s search-site list, and facebook isn’t on it.[1]
What cpc does instead is our own reading, and we haven’t seen it stated anywhere: a social source with any paid medium satisfies Paid Social and Organic Social at the same time, because Organic Social accepts the source on its own.
Which leaves the outcome resting on which rule Google checks first. Google publishes both and never says which one, so every page presenting this as a settled lookup is filling in a blank.[1]
One boundary, though, because it’s where a lot of tagging effort disappears. Google Ads writes these parameters itself, a feature called auto-tagging, and on its own links it beats anything you type:
“in Google Analytics 4 (GA4), auto-tagging is prioritized over manual tagging due to the absence of an override option.”[6]
The setting that used to let your tags win is gone with Universal Analytics, the version before GA4. Meaning hand-tagging Google Ads links is often work the platform quietly overwrites.
| utm_medium | Where it lands | Note |
|---|---|---|
cpc, ppc, retargeting, paid_social | The paid channel the source implies | All four count as paid; the source decides which paid channel |
social, social-network, social-media, sm | Organic Social | Right for organic posting, wrong for anything you paid for |
organic | Organic Search | Do not hand-tag this. You’re overwriting real organic data |
email, e-mail, e_mail, e mail | Matches on source or medium, so either field gets you there | |
sms | SMS | Exact match |
affiliate | Affiliates | |
referral, app, link | Referral | |
newsletter, fb-ad, promo | Unassigned | Matches no rule, so the visit falls through |
Unassigned on that last row isn’t an error. Google defines it as “the value Analytics uses when there are no other channel rules that match the event data”.[1]
So a pile of traffic sitting there means the engine did exactly what it says it does, and your values weren’t on the list.
Pick medium from the table. Then put your own words in utm_campaign and utm_content, where they cost you nothing.
Pick source and medium from a list, not from memory.
Our free UTM builder follows Google’s own channel rules, so nothing you pick can send the visit to Unassigned.
Rule 2 · Tag all three, or tag nothing
Source, medium and campaign go on a link together, or none of them do. Because a partial tag is worse than no tag at all.
This is the one we see broken most often, and always with the best intentions.
Somebody wants to label a link. They add utm_campaign=spring_newsletter, leave source and medium off, and figure a partial tag beats no tag.
It does not, and Google asks for the opposite in plain words:
“if you’re setting one UTM parameter, we strongly recommend that you set all relevant UTM parameters, especially utm_source, utm_medium, utm_campaign, utm_id, and utm_source_platform.”[2]
The reason sits in the sentence right before that quote. We nearly walked past it too, because most guides chop that opening clause off.
The full rule has two parts, and both turn on the click ID. That’s the code Google Ads staples to a link so Analytics can match the visit to the ad.
When that click ID stops working, Analytics falls back to your UTMs. And if even one of them is there, it will “derive all cross-channel traffic source dimension values from UTM parameters, exclusively.”[2]
Exclusively.
The referrer is the page they clicked through from. It would have told you they came from a search engine, and now nothing asks it.
We should bound that claim, because the trimmed version of the quote is everywhere.
Google documents that exclusive behaviour for the click-ID case. It doesn’t spell out the same thing for a plain link that never carried a click ID. But Google puts no such condition on the result, which it states flatly: “Missing UTM parameters will result in (not set) values being present in reporting.”[2]
You did not add a label. You deleted where the visit came from, and left a label in its place.
All three, or none at all
utm_source, utm_medium and utm_campaign travel together. Leave one off and you’re better off not tagging the link at all, so Analytics can read the referrer instead.
A second Google page says it shorter. It’s still more modest than the advice people build on top of it:
“When you add parameters to a URL, you should always use utm_source, utm_medium, and utm_campaign.”[3]
While we’re here: the five-parameter framing you’ve probably absorbed is out of date. Google actually documents nine.
utm_id, utm_source, utm_medium, utm_campaign, utm_source_platform, utm_term, utm_content, utm_creative_format and utm_marketing_tactic. We’ve written up what all nine parameters do separately, because that list is a subject of its own.
Two of them are documented but you can’t report on them. Google says so plainly for each:
“utm_creative_format isn’t currently reported in Google Analytics properties.”[3]
A documented parameter and a field you can report on are two different things.
Rule 3 · Lowercase everything, and enforce it where the link is made
Every value goes in lowercase, and the enforcing happens in whatever builds the link. Not in a document, and not in a cleanup pass afterwards.
Here’s how it goes wrong. Somebody will tell you GA4 isn’t case sensitive, you’ll relax, and your rows will split anyway.
Channel matching ignores case, exactly as Google’s line at the top of this page says. The values underneath don’t:
“Parameter values are case sensitive, e.g. utm_source=google is different from utm_source=Google.”[3]
So utm_medium=Email lands in the Email channel, correctly. But Email, email and eMail are three separate rows in every report that shows you medium.
Your channel report is right. But everything under it is wrong, and you won’t see it until you look at the rows.
One channel, three rows
Email, email and eMail all land in the Email channel, because channel matching ignores case. Open the medium report underneath and they are three separate rows. One campaign’s numbers, split three ways.
So our position is lowercase everything, always. No exception for acronyms or brand names.
Take LinkedIn. It’s exactly the value a careful person capitalizes correctly, and splits in the process.
Enforce it at creation, then, because almost nothing fixes mixed case afterwards. The old Universal Analytics at least had a lowercase filter. GA4 has nothing like it:
“Currently, Google Analytics offers filters to either include or exclude internal traffic and developer traffic.”[4]
That is the whole filter menu.
GA4 does have one other feature people reach for here, called event modification. It replaces values you name, or copies one parameter’s value into another. That’s the whole of it -- no case conversion anywhere in it.[5]
It won’t catch whatever spelling somebody invents next month. And it doesn’t reach backwards either: “Modified and new events do not apply to historical data.”[5]
You can clean the values as they arrive, in your tag manager. That’s the tool that fires your tracking scripts. If you do it there, lowercase the UTM values one by one, never the whole URL.
Google Ads leaves its own click ID on that same URL. It’s called gclid, it is case sensitive, and lowercasing it destroys it.
You can also fix it in the warehouse. That’s the database where your raw data lands, and one command there lowercases a whole column. That command is LOWER() in BigQuery, and it’s the only route that repairs history.
Either one works. Both are real work you’re doing because a link got built wrong.
Lock one spelling across a whole campaign at once.
Our free UTM builder writes every link in the campaign at once, so only the asset changes.
Rule 4 · Pick one separator and never mix them
Underscore or hyphen, pick one and hold it everywhere. Which one you pick matters far less than picking.
Separators split your rows the same way case does. Which means paid_social and paid-social are two values and two rows. That’s one manual merge every month.
What they don’t have is a documented effect on anything else. That’s where the usual argument goes wrong.
The page everybody cites is Google’s URL structure guidance. It recommends “using hyphens (-) instead of underscores (_) to separate words in your URLs” because underscores are “already commonly used for denoting concepts that should be kept together”.[7]
But that page is about how Google Search reads words in a URL. It never mentions campaign parameters, UTM parameters or analytics anywhere.[7]
We searched it for the words UTM and campaign. It contains neither.[7]
Nothing in Google’s docs covers separators inside a campaign value, and we couldn’t find a published test showing Search reads utm_campaign=black_friday any differently from black-friday.
So “Google prefers hyphens in your UTMs” is an extrapolation wearing a citation.
Our position: underscores inside a value, hyphens between fields.
https://yoursite.com/pricing?utm_source=facebook&utm_medium=paid_social&utm_campaign=2026_q3-sponsored_story
That gives you two levels, so 2026_q3-sponsored_story splits cleanly back into fields once the data reaches your warehouse, and each field stays readable.
Names built by position do bring one trap. Skip a segment and every value after it shifts one place, with nothing to warn you.
The fix is to keep the slot and put a word in it, rather than letting the name collapse.
The tradeoff is real, because if your team has a hyphen convention that people follow, then changing it costs more than it buys, and consistency beats our preference.
What it does not beat is having no convention at all, which is where most teams sit.
Rule 5 · Never put UTMs on internal links
No utm_ parameters on a link from one page of your site to another. Not on the homepage banner, not on the nav promo.
Everyone agrees on that much, but the reason normally given describes a product that no longer exists. You’ll read that UTMs on internal links restart the session and inflate your session count, and that was Universal Analytics.
In GA4 the session doesn’t restart, and a session is just one visit anyway. The trouble is, that’s where most people stop reading -- they take the correction, decide the practice is harmless now, and carry on.
The real damage is the behaviour we quoted in Rule 2: Analytics reads the source off your parameters whenever they’re there.[2] So a visitor arrives from a search engine, clicks a homepage banner tagged utm_source=homepage, and the source of that visit becomes your own homepage.
They told you where they came from, and you crossed it out and wrote in your own name.
The damage does not stop when the visit does, either.
That’s because GA4 keeps crediting the last source it saw that wasn’t direct, and a direct visit is one that arrives with no source at all. So if they come back by typing your address in, your internal banner is still the source days later, attached to traffic it had nothing to do with.
One caveat, and it’s bigger than the one usually offered. No official Google page we could find says “do not tag internal links”, and the sentence we quoted in Rule 2 covers the click-ID case. Which leaves this rule resting on strong convention, not on a citation.
The fix is simple. Measure internal clicks as events.
If you genuinely need the value on the URL, use a parameter that doesn’t start with utm_, like ?promo=hero_banner, and read it into a custom dimension. Those are reporting fields you define yourself, and they never touch traffic source.
UTMs and events answer different questions
A UTM says where the visit came from, read once, at the door. An event records what happened inside it -- a click, a scroll, a form submit.
Which is why the swap isn’t a downgrade. A click on your own page always belonged at that layer.
There’s a second reason, and it usually arrives as an SEO question. A tagged link is a different URL pointing at the same page. Now Google finds pages by following links, so tagging your own links is how those extra URLs get found at all.
When Google has several URLs showing the same page, it picks one to keep. That one is the canonical:
“the URL of a page that Google chose as the most representative from a set of duplicate pages.”[12]
So point your canonical at the untagged version, though that’s a preference rather than an instruction: “indicating a canonical preference is a hint, not a rule.”[12]
What campaign parameters don’t do is change how a page ranks. The page everybody reaches for there is the same URL guidance we take apart in Rule 4, and it never mentions campaign parameters anywhere.[7]
Rule 6 · Date every campaign, and leave unused parameters off
Put the period in every campaign name, and leave a parameter off the link when you’re not using it. Both cost nothing at creation. But getting either one wrong can’t be undone later.
Take the dating first. Reuse a campaign code and the two periods become one value. Last spring’s spring_sale and this spring’s spring_sale are the same row, carrying the same conversions, and no report can pull them apart.
Which is why you date every campaign, including the ones you’re certain are one-offs.
https://yoursite.com/pricing?utm_source=newsletter&utm_medium=email&utm_campaign=2025_q2-spring_sale
https://yoursite.com/pricing?utm_source=newsletter&utm_medium=email&utm_campaign=2026_q2-spring_sale
The second one is smaller and far more common: filling an unused parameter with a stand-in, utm_term=none, feels tidier than leaving a gap in the link.
It does not leave the field empty. It creates a real value called none.
That value shows up in every report of that field, and it defeats any missing-data check you write later.
Leave it off instead.
Rule 7 · Close the value list
Close the list. That means a fixed set of approved sources and mediums, a way to ask for additions, and no way to type a value that isn’t on it.
Because every rule above assumes somebody applies it, and that assumption is the failure. A convention that lives in a document and gets applied in a free text box is a hope with a filename. You’re writing input for software with no undo, so the only conventions worth having are the ones something enforces for you.
The moment a value can be typed freely, somebody will type it differently.
Short codes belong on that list or nowhere. Sure, shortening Instagram to ig is a fair answer to a character limit.
But if ig isn’t on the list, it brings back the exact FB against facebook split you just finished fixing.
The list to start from
Closing a list is easier than writing one, so here’s a minimal set that already agrees with Google’s official channel rules. Take it and cut whatever you don’t run.
The instinct on seeing a list this short is to add to it. But every value you add before a campaign forces you to is one more that somebody will spell two ways.
| Field | Starting values | Why these |
|---|---|---|
utm_source | google, bing, facebook, instagram, linkedin, youtube, newsletter, partner_name | The platform, never the format. One spelling each, lowercase, and no fb or li unless the short code is on the list too |
utm_medium | paid_social, cpc, email, sms, affiliate, referral, social | Every value here matches a channel rule from the table in Rule 1. social is for organic posting only |
utm_campaign | <period>-<theme>, such as 2026_q3-spring_sale | Dated first, so two periods can never collapse into one row. Hyphen between fields, underscore inside them |
utm_content | <placement>-<variant>, such as hero-a | The one field where per-asset variation belongs, which keeps it out of the other three |
That’s four fields on one page, with nothing typed freehand. The fifth, utm_term, stays off the link unless you’re running search ads and reporting on keywords.
The values matter less than the fact that the list is closed. When a team goes from one tagged link to two hundred, it has something to extend instead of something to invent. And inventing under deadline is where the drift starts.
What you cannot fix afterwards
Almost none of it. That’s the answer, and the whole argument for enforcing anything at all.
The bag has already landed. Here’s the accounting.
| Damage | Fixable in the GA4 interface? | Where it can actually be fixed |
|---|---|---|
| Mixed casing or separators splitting rows | No | Tag manager going forward; one command in BigQuery repairs history |
| A medium that matched no channel rule | No | A channel group you define yourself, going forward; standard reports stay as collected |
Half-tagged link producing (not set) | No | Nothing. The referrer was discarded at collection |
| Internal UTMs overwriting real sources | No | Remove the tags. The affected visits stay wrong |
| Reused campaign code merging two periods | No | Nothing. The two periods are one value |
| A dashboard that has to read correctly today | Cosmetically | A formula in your dashboard tool, which fixes the chart and not the data |
Every row says no, and even the two features people expect to say yes don’t. Those filters cover internal and developer traffic,[4] and event modification changes values you name one at a time, going forward only.[5]
The layer above GA4, where the value never arrives
All of that assumes your values reach Analytics in the first place. Two layers sit in front of it, and both are worth knowing before you blame your tagging.
The first is the browser. Safari’s Link Tracking Protection strips some parameters off a link before the page even loads.
But the version you’ve probably read, that iOS strips your UTMs, isn’t what Apple documents. Apple draws a line between codes that identify a click or a person and parameters that only name a campaign, and UTMs sit on the safe side of it:
“a parameter that’s only used for campaign attribution, as opposed to click or user-level tracking. Safari allows such parameters to pass through.”[8]
So utm_source survives the trip. What changes is who can read it at the other end.
A script loaded by another company reads that URL with the parameters stripped off.[8] But exactly which scripts that catches, Apple doesn’t list, and we haven’t measured it.
The second layer is consent. When a visitor declines, Google’s consent mode sends measurements without cookies and then estimates the conversions it can no longer count.[9] But that estimate has a floor: 700 ad clicks over seven days in each country you advertise in, and below that the gap just stays a gap.[10]
Server-side tagging is the standard fix here, and it moves collection off the visitor’s browser onto a server you run. But Google’s guidance carries a condition most write-ups drop. That server has to run on your own domain, and on the Google-hosted address you get by default you lose the very durability you moved for.[11]
None of this is repairable in a report either. Same lesson as the table, one layer up.
Last thing, since this page has been strict about sources. Several numbers circulate on this topic: a share of sites with broken UTMs, a monthly cost of bad tracking.
We went looking for the method behind them and found none.
We haven’t repeated them here. Next time one turns up in a pitch deck, it’s worth asking whose sample it came from.
The seven rules, in one place
- Take
utm_mediumfrom the channel rules, not your own vocabulary It does more than any other field to decide which channel you land in. Usepaid_socialfor social ads, neversocial. - Tag all three, or tag nothing
utm_source,utm_mediumandutm_campaigntravel together. A partial set deletes the real source and puts(not set)in its place. - Lowercase everything, and enforce it where the link is made Channel matching ignores case. Nothing under channel level does, and no filter fixes it later.
- Pick one separator and never mix them Underscores inside a value, hyphens between fields, if you want names you can split apart later.
- Never put UTMs on internal links
Use events instead, or a parameter that doesn’t start with
utm_. - Date every campaign, and leave unused parameters off
Two periods sharing one code cannot be pulled apart, and
utm_term=nonecreates a real value callednone. - Close the value list A fixed set of approved sources and mediums, with a way to ask for additions. A free text box is a convention with nothing enforcing it.
That’s the checklist. But the part that actually works is building the links somewhere that cannot produce a value that isn’t on the list.
Because a document cannot enforce anything. That is not a criticism of documents, it is the definition of one.
- Default channel group Google Analytics Help. Retrieved 18 October 2026.
- Traffic-source dimensions, manual tagging, and auto-tagging Google Analytics Help. Retrieved 27 July 2026.
- URL builders: Collect campaign data with custom URLs Google Analytics Help. Retrieved 27 July 2026.
- Filter, report on, or restrict access to data subsets Google Analytics Help. Retrieved 27 August 2026.
- Rename and generate new events Google Analytics Help. Retrieved 27 August 2026.
- About auto-tagging Google Ads Help. Retrieved 27 July 2026.
- URL structure best practices for Google Search Google Search Central. Retrieved 27 July 2026.
- Private Browsing 2.0 WebKit. Retrieved 31 July 2026.
- Consent mode overview Google for Developers. Retrieved 31 July 2026.
- About consent mode modeling Google Ads Help. Retrieved 31 July 2026.
- Custom domain configuration Google for Developers. Retrieved 31 July 2026.
- What is URL Canonicalization Google Search Central. Retrieved 31 July 2026.
Frequently asked questions
Are UTM parameters case sensitive?
Partly, and where the line falls is what catches people out. Google documents that the values are case sensitive. So facebook and Facebook stay two separate rows in every report that shows you source. But the channel rules that file a visit under Email or Paid Social ignore case, so utm_medium=Email still lands in the Email channel. Your channel report looks right while the detail under it splits in two.
Should UTM parameters be lowercase?
Yes, and enforce it where the link gets made, not in a cleanup later. Google Analytics has no filter that lowercases campaign values. Its filters cover internal traffic and developer traffic, and nothing else. One other feature gets suggested here, called event modification. It only swaps values you name. It has no way to change case, and it never touches data you already have. Lowercase is cheap at creation and close to impossible afterwards.
Should I use hyphens or underscores in UTM parameters?
Either, as long as nobody mixes them. Google Analytics doesn't treat them differently. The Google page people cite here is about how Search reads words in a URL, not about campaign parameters. We searched it on 27 July 2026 and it doesn't contain the word campaign or the word UTM anywhere. Mixing the two is what costs you, because it splits one campaign into two rows.
What are the standard utm_medium values?
The ones Google's default channel rules actually test. That list is organic, email, affiliate, referral, app, link and sms. It also takes the social set, which includes social and social-media. And it takes any paid value, such as cpc, ppc, retargeting or paid_social. A medium that matches no rule at all sends the visit to Unassigned. Google defines that as the value it uses when no other channel rule matches.
Is it bad to tag a link with only utm_campaign?
Yes, and it's worse than leaving the link untagged. Google's own advice is that if you set one UTM parameter you should set all the relevant ones, because missing parameters produce (not set) values in your reports. A campaign-only link also gives up the referrer. That's the page the visitor clicked through from, and it would have told you where they came from. Source, medium and campaign travel together.
Should I use UTM parameters on internal links?
No. The usual reason given is that the tags restart the session. That was Universal Analytics, not GA4. The real damage is different. Analytics reads the source off your parameters whenever they're there. So an internal banner writes over how the visitor really arrived, and that value can carry into their next visit. Measure internal clicks as events instead.
Do UTM parameters affect SEO?
Not in the way the question usually means. Campaign parameters don't change how a page ranks, and the Google page most often cited in this debate is about how Search reads words in a URL. It never mentions campaign parameters at all. The real risk is duplication, because a tagged link is a different URL pointing at the same page. When Google has several URLs showing the same page, it picks one to keep. And it treats your canonical tag as a hint rather than a rule. So point the canonical at the untagged version. Keep UTMs off your own links too, so those extra URLs never get found in the first place.