Parsed parameters
Site: https://northpeak.example. Convention: the default (lowercase; hyphens between words; utm_medium from cpc, paid-social, email, social, referral, affiliate, display). Parsing and counts were done by script. Encoded values are decoded for display (%20 and + are spaces).
| Row | Base URL | utm_source | utm_medium | utm_campaign | utm_content | utm_term |
|---|---|---|---|---|---|---|
| 1 | https://northpeak.example/jackets | paid_social | Fall_Sale | |||
| 2 | https://northpeak.example/jackets | paid-social | fall-sale | |||
| 3 | https://northpeak.example/boots | newsletter | boots launch (sent as boots%20launch) | |||
| 4 | http://northpeak.example/boots | cpc | boots-launch | hiking boots (sent as hiking+boots) | ||
| 5 | https://northpeak.example/sale | social | (missing) | |||
| 6 | https://northpeak.example/about | northpeak | internal | footer | ||
| 7 | https://northpeak.example/jackets | partnerblog | affiliate | fall-sale | review-link |
Issues by row
Each issue type is counted once per row. Medium is checked against the allowed list after lowercasing, so a case problem counts only as uppercase.
| Row | Issues | Count |
|---|---|---|
| 1 | Uppercase (Fall_Sale); underscores (paid_social, Fall_Sale); medium not allowed (paid_social); source spelled two ways (facebook here, Facebook in row 2) | 4 |
| 2 | Uppercase (Facebook); source spelled two ways (with row 1) | 2 |
| 3 | Uppercase (Email); encoded space (boots%20launch) | 2 |
| 4 | http instead of https; encoded space (hiking+boots) | 2 |
| 5 | Missing utm_campaign | 1 |
| 6 | UTMs on an internal link (same domain as the site); medium not allowed (internal) | 2 |
| 7 | None | 0 |
Issue counts
Rows showing each issue type:
| Issue type | Rows | Count |
|---|---|---|
| Uppercase | 1, 2, 3 | 3 |
| Underscores where hyphens are the rule | 1 | 1 |
| Medium not in allowed list | 1, 6 | 2 |
| Same source spelled two ways | 1, 2 | 2 |
| Spaces or encoded spaces | 3, 4 | 2 |
| http instead of https | 4 | 1 |
| Missing source, medium or campaign | 5 | 1 |
| UTMs on internal link | 6 | 1 |
Total from the per row view: 4 + 2 + 2 + 2 + 1 + 2 + 0 = 13. Total from the per type view: 3 + 1 + 2 + 2 + 2 + 1 + 1 + 1 = 13. The two views agree.
Also worth noting, though it isn't a lint rule: the boots campaign appears as "boots launch" (row 3) and "boots-launch" (row 4). Once row 3 is fixed, they match.
Proposed convention
| Parameter | Rule | Example from your links |
|---|---|---|
| All values | Lowercase; hyphens between words; no spaces or underscores | fall-sale |
| utm_source | The platform or site name, one spelling per source | facebook, google, instagram, newsletter, partnerblog |
| utm_medium | One of: cpc, paid-social, email, social, referral, affiliate, display | paid-social |
| utm_campaign | Required on every tagged link; the campaign name in hyphen case | boots-launch |
| utm_content | Optional; tells apart links or creatives within a campaign | review-link |
| utm_term | Optional; paid keyword, hyphen case | hiking-boots |
| Internal links | Never tagged | |
| Scheme | Always https:// |
Corrected URLs
| Row | Corrected URL |
|---|---|
| 1 | https://northpeak.example/jackets?utm_source=facebook&utm_medium=paid-social&utm_campaign=fall-sale |
| 2 | https://northpeak.example/jackets?utm_source=facebook&utm_medium=paid-social&utm_campaign=fall-sale |
| 3 | https://northpeak.example/boots?utm_source=newsletter&utm_medium=email&utm_campaign=boots-launch |
| 4 | https://northpeak.example/boots?utm_source=google&utm_medium=cpc&utm_campaign=boots-launch&utm_term=hiking-boots |
| 5 | https://northpeak.example/sale?utm_source=instagram&utm_medium=social&utm_campaign=[SET: campaign] |
| 6 | https://northpeak.example/about (UTMs removed: this is an internal footer link) |
| 7 | No change |
Rows 1 and 2 are now identical. If they were meant to track different ads, tell them apart with utm_content, for example ad names you supply.
Reporting notes
- In GA4, traffic already recorded keeps its old values, such as "Facebook", "paid_social" and "Email". The fixes only apply to new sessions. For past data, group the old spellings together in an exploration or a custom channel group.
- UTMs on internal links (row 6) can replace a visitor's original source in GA4 session reports. Removing them stops that from happening for new visits.
- Row 4: a Google Ads keyword tagged by hand duplicates auto tagging, if auto tagging is on. Check with the paid search owner.
Needs your decision
- Set a campaign name for row 5.
- Each channel owner approves changes to their live links: paid social (rows 1, 2), email (row 3), paid search (row 4), organic social (row 5), web (row 6).
