Channel Grouping
Channel Grouping is how Sealmetrics buckets each visit into a marketing channel — Paid Search, Organic Social, Email, Affiliates, and so on — instead of showing a raw list of every utm_source / utm_medium combination. You see those channels in the Sources → Channels report.
Sealmetrics ships with a set of GA4-style default channels that work out of the box. When those aren't enough (a paid-social alias you use internally, a partner network, a "Brand vs Non-Brand" split for paid search…), you can define your own rules from the dashboard, via CSV, or through the MCP.
Where to find it
- Open Site settings (gear icon, top right).
- Go to the Channels tab.
You'll see three areas:
- Test a visit — a live tester that classifies a
source / medium / campaigncombination exactly like the pixel would. - Your rules — custom rules for this site (initially empty).
- Default channels — the GA4-style rules that ship with Sealmetrics. You can't edit or delete them, but you can override them (see below).
How rules are evaluated
For every visit that comes in, the pixel checks the rules in this order:
- Your custom rules first, sorted by priority (highest first).
- Then the default channels, also by priority.
- The first rule that matches wins — its
channel_nameis stored with the hit. - If nothing matches, the hit is classified as Unassigned.
A rule matches when all its non-empty patterns match the incoming values. An empty pattern is a wildcard — it matches anything.
Matching is case-insensitive and applied to three fields:
- Source — usually
utm_source(e.g.google,newsletter-june,partnerize). - Medium — usually
utm_medium(e.g.cpc,email,referral). - Campaign — usually
utm_campaign(e.g.summer-sale,brand).
Patterns are regular expressions in RE2 syntax. Lookaheads, lookbehinds, and backreferences are not supported. The dashboard's rule tester uses the exact same engine as the pixel, so if it matches in the tester, it will match in production.
Channel classification happens at ingest time, when the visit is received. Editing, adding, or removing a rule affects future traffic only — historical rows keep the channel they were assigned when they came in.
New rules become live in the pixel within roughly 5 minutes (the pixel refreshes its rule cache on that interval).
The drafts → test → publish workflow
Every rule you create — whether from the form, CSV import, or MCP — is born as a draft (labeled Not live). The pixel only loads live rules, so drafts never affect any traffic. This gives you a safe space to build and validate rules before they touch your reports.
The typical flow:
- Create a rule from the form (or import a CSV, or ask your MCP-connected assistant to draft one).
- Test it against real visit values in the Test a visit panel. Toggle "Include rules that are not live yet" to include drafts in the evaluation.
- When the tester returns the channel you expected, flip the Live switch on the rule. It's live for new traffic within ~5 min.
You can leave rules as drafts indefinitely — good for staging changes you plan to publish later.
Using "Test a visit"
The rule tester is the single most important tool on the Channels tab. Before touching any live rule you should validate it here — the tester uses exactly the same matching engine as the pixel (same RE2 library, same ordering, same case-insensitive comparison), so a match in the tester is a guarantee that the pixel will match the same value in production.
Where to find it
At the top of the Site settings → Channels tab, the Test a visit panel is always visible above the rules list. It's a small form with three inputs and a toggle.
What to type in each field
Enter the raw values you expect the visitor's URL (or referrer) to produce. Do not add regex — this is not a pattern, it's a concrete test value:
- Source — the value that will land in
utm_source. Examples:google,newsletter-june,partnerize,(direct). - Medium — the value that will land in
utm_medium. Examples:cpc,email,referrer,(none). - Campaign — the value that will land in
utm_campaign. Examples:summer-sale-2026,brand,black-friday. Leave empty if the campaign you want to simulate has noutm_campaign.
Two rules of thumb when picking test values:
- Simulate real URLs, not hypothetical ones. If your team never tags campaigns with
utm_source=Google(capitalized), don't test with that value — test what the traffic actually looks like. - For direct traffic, use
(direct)for source and(none)for medium (that's what Sealmetrics normalizes untagged visits to, GA4-style). - For untagged referral traffic (someone linked to you from a third-party site with no UTM), use
referrerfor both source and medium.
The "Include rules that are not live yet" toggle
By default, the tester evaluates only your live rules + the defaults — exactly what the pixel is using right now.
Turn the toggle on to include draft rules in the evaluation. This is how you validate a rule before publishing it: you write the rule as a draft, turn the toggle on, and check that visits classify as expected. When the tester confirms it, you flip the Live switch on the rule.
Turn the toggle off again to double-check that live traffic is not being affected by an old rule you forgot about.
Reading the result
Click Test and the panel shows:
- The channel name the visit would be assigned to (e.g.,
Paid Search Brand). If nothing matches, it shows Unassigned. - Which rule matched — its channel name, its patterns, its priority, and whether it's a custom rule or one of the defaults. This is what tells you why the classification happened.
- Whether the matched rule is live or a draft — highlighted so you can't confuse "would happen if I published" with "is happening today".
If your rule doesn't match a value you expected it to, the fastest way to debug is:
- Test with the toggle off — does it match a live rule you didn't expect (perhaps an old override)?
- Test with the toggle on — does it match your new draft? If not, your pattern is wrong.
- Look at each of your three patterns in isolation: an
ANDis only as forgiving as its strictest field.
Six scenarios worth testing
Before publishing any change, run through the values you actually care about. A short checklist that catches most surprises:
| Scenario | Source | Medium | Campaign | What to check |
|---|---|---|---|---|
| Direct traffic | (direct) | (none) | (empty) | Falls into Direct. |
| Untagged referrer (external site links to you) | referrer | referrer | (empty) | Falls into Referral. |
| Your main paid-search campaign | google | cpc | your usual campaign value | Falls into your intended paid channel. |
| A campaign with a "brand" naming convention | google | cpc | brand | Falls into Paid Search Brand (or wherever your rule points). |
| A social alias your team uses | fb (or whatever alias) | cpc | (empty) | Falls into Paid Social (via your custom rule). |
| An affiliate partner | your affiliate source | (empty) | (empty) | Falls into Affiliates. |
If any of these classify differently than you expect, fix the rules before publishing — the tester is the whole point of the drafts flow.
What the tester does not do
- It doesn't send a real hit. Nothing is stored in your reports; testing has no effect on data.
- It doesn't backfill. Even if the tester says "this visit would be Paid Search Brand", historical visits with those same UTM values keep whatever channel they had at ingest.
- It doesn't validate business logic (e.g., "this campaign should belong to team X") — only the classification. Naming and organizing your channels is up to you.
Using it via the MCP
The same tester is exposed as test_channel_rules in the MCP tools, so you can ask a connected AI assistant to run scenarios in bulk. Example prompts:
- "Test how our top 10 paid-search campaigns would classify with the current rules."
- "For each source/medium pair we've seen in the last week, tell me which channel it maps to."
test_channel_rules is read-only — it does not create or modify anything, no matter what the assistant is prompted to do.
Creating a rule from the form
Click Add rule. Fill in:
- Channel name — free text. If it matches an existing channel (e.g.
Paid Search), the visit rolls up into that channel; if it's new (e.g.Paid Search Brand), a new channel appears in your reports. - Source / Medium / Campaign patterns — leave any of them empty for a wildcard. At least one must be filled (a rule with all three empty would match every visit and is rejected).
- Priority — a number from
0to1000. Only used to order your custom rules against each other. Leave it at50unless you need one rule to win over another. - Live switch — off by default. Turn it on after testing.
Common patterns:
| Goal | Source pattern | Medium pattern | Campaign pattern | Channel name |
|---|---|---|---|---|
| Split brand campaigns from generic paid search | ^(google|bing)$ | ^cpc$ | brand | Paid Search Brand |
Map an internal alias like fb to Paid Social | ^fb$ | ^cpc$ | (empty) | Paid Social |
Legacy adwords/cpc traffic | ^adwords$ | ^cpc$ | (empty) | Paid Search |
| Affiliate partners you use | ^(awin|partnerize)$ | (empty) | (empty) | Affiliates |
| Internal email tools | (empty) | ^(crm|internal-mail)$ | (empty) |
Overriding a default channel
You can't disable, edit, or delete the built-in default rules directly. Instead, Sealmetrics gives you a single, safe mechanism to redirect any default channel: the Override button.
How Override actually works
Under the hood, Override is not "a special edit of the default" — it's just a shortcut to create a custom rule with the same patterns as the default. Because your custom rules are always evaluated before the defaults, that new custom rule wins the match. The default is still there; it's just never reached anymore for those values.
This has three practical consequences you should keep in mind:
- The default is not modified. If you delete your override later, the default automatically takes effect again. There is no "restore defaults" button — because you never actually changed them.
- You can override with different intent: redirect the traffic to another channel, split it into a new channel, tighten the patterns, or make it more permissive.
- Overrides count against your 100-rule quota just like any other custom rule.
Step-by-step
- Open Site settings → Channels.
- Scroll to the Default channels table.
- Find the default row you want to change. Click Override.
- The rule form opens, pre-filled with:
- The default's
source_pattern,medium_pattern,campaign_pattern— you don't have to figure them out. - A copy of the default's
channel_name— the field you'll normally change. - Priority
50and Liveoff— the same defaults as any new rule (born as a draft).
- The default's
- Adjust as needed:
- To redirect the traffic to a different channel: change
channel_nameonly. Leave the patterns as they were. - To split the default in two: narrow the patterns and pick a more specific
channel_name. You can then click Override again on the same default to catch the rest under a different name (see the worked example further down). - To broaden a default: loosen a pattern (e.g. add another engine to the OR list). Bear in mind you're only broadening it for your account — the default itself doesn't change.
- To redirect the traffic to a different channel: change
- Test the values you care about with the "Include rules that are not live yet" toggle on to confirm the classification is what you want.
- Flip Live to publish. Effective in ~5 minutes.
When to use Override vs "Add rule"
- Use Override when you want your rule to catch the exact same values as a default (or a narrower subset of them). Starting from the default's patterns is safer than typing them from scratch.
- Use Add rule when you want to catch values the defaults don't cover: an internal alias, an affiliate partner, an obscure source that currently ends up in Unassigned.
"I want to hide a default channel from my reports"
There is no toggle to disable a default. The supported way to make a default disappear is to override it into another existing channel:
- Don't want an AI channel? Override its default(s) → change
channel_nametoReferral(orOrganic Search, or whatever fits your model). Future AI traffic rolls into that channel and the "AI" name stops appearing. - Don't want Rejoined-style splits? Same idea: Override → redirect into
DirectorReferraldepending on your interpretation.
Redirecting into an existing channel keeps your reports clean (no orphan channels). If you redirect into a brand-new name, that new name will show up in reports instead.
Undoing an override
Just delete the custom rule. The default is untouched, so the moment your override is gone, matches fall through to the default rule again on new traffic (~5 min after the change).
Common mistakes
- Overriding a default without testing first. The default's patterns can be more nuanced than they look (multiple values in an OR list, campaign qualifiers). Always run "Test a visit" for the values you actually care about before publishing.
- Overriding to a name that already exists — with a typo.
Paid searchandPaid Searchare different channels in your reports (channel names are free text, not a fixed enum). If you want the traffic to roll into an existing channel, copy-paste the existing name. - Publishing an override while forgetting the priority. The default priority
50is normally enough. If you have multiple custom rules that could match the same values, remember that within custom rules priority DESC wins — a lower-priority override can be silently shadowed by a higher-priority custom rule of your own.
Creating a rule from the form
Import / Export (CSV)
For bulk changes or version-controlling your rules, use CSV.
Export
Click Export — you get a .csv with all your custom rules. Defaults are not included (they can't be edited anyway).
Import
Click Import and upload a .csv (or .json) file. Import is replace-all and atomic:
- The file becomes your new complete set of custom rules. Anything not in the file is removed. An empty file returns the site to defaults-only.
- If any row is invalid, nothing is imported (all-or-nothing) — you get a report telling you which row is wrong.
- Maximum: 100 rules per site.
Live and draft rules can both be in the file — the is_active column controls it (see below).
CSV format
The header row is mandatory. Order of columns is free, but all six must be present:
channel_name,source_pattern,medium_pattern,campaign_pattern,priority,is_active
Paid Search Brand,^(google|bing)$,^cpc$,brand,110,true
Paid Social,^fb$,^cpc$,,100,true
Affiliates,^(awin|partnerize)$,,,80,false
channel_name— required.source_pattern/medium_pattern/campaign_pattern— RE2 regex. Empty = wildcard. At least one must be non-empty.priority—0–1000. Empty defaults to50.is_active—trueorfalse(case-insensitive). Empty defaults totrue.false= imported as a draft.
Excel-friendly quirks handled automatically:
- Delimiter can be
,(standard) or;(Excel in Spanish/French locales). - Quoted values follow RFC 4180 — a regex containing a comma like
^a{1,2}$needs quoting ("^a{1,2}$"); Excel handles this for you when you paste. - UTF-8 BOM and CRLF line endings are supported.
- The exported CSV includes BOM and CRLF so it opens cleanly in Excel.
Using the MCP
If you've connected Sealmetrics to Claude, ChatGPT, or another MCP-compatible assistant, five tools are available for channel rules:
| Tool | What it does |
|---|---|
test_channel_rules | Run the tester with any source/medium/campaign combination. Read-only. |
create_channel_rule | Create a new rule as a draft. |
update_channel_rule | Edit an existing rule — drafts only. |
delete_channel_rule | Delete a rule — drafts only. |
import_channel_rules | Bulk-import rules as drafts. Defaults to dry_run=true (validates without writing). |
The draft-only invariant
To keep your live classification safe from anything an assistant might do (mistakes, prompt injection, misunderstood context), the MCP is subject to a strict invariant:
- The MCP can never touch a live rule. Editing or deleting is only allowed on drafts. If a rule is live, the API rejects the operation.
- The MCP can never activate a rule. Every rule it creates or imports is born as a draft.
- Publishing is always a human action — you flip the Live switch from the dashboard.
The worst case with the MCP is "too many drafts to review". Your live channels are never changed by an assistant.
To use the write tools, your MCP connection must have an API key with the write scope. Read tools (like test_channel_rules) work with any API key.
Complete worked examples
Each example walks through a real scenario end-to-end: the goal, the rule, the values to test, and how to publish. Follow the same shape when you build your own.
Example 1 — Split "Paid Search" into Brand vs Non-Brand
Goal. Your team runs Google/Bing paid search campaigns. You want to see brand campaigns (utm_campaign contains brand) as their own channel, separate from generic paid search.
Rule to create (click Add rule):
| Field | Value |
|---|---|
| Channel name | Paid Search Brand |
| Source pattern | ^(google|bing)$ |
| Medium pattern | ^cpc$ |
| Campaign pattern | brand |
| Priority | 110 |
| Live | off (draft) |
Priority is bumped to 110 (above the default 50) so this rule wins over any other custom rule you might add later that could also match google/cpc.
Test with the tester (toggle "Include rules that are not live yet" ON):
| Source | Medium | Campaign | Expected result |
|---|---|---|---|
google | cpc | brand-summer-2026 | Paid Search Brand |
google | cpc | nonbrand-generic-terms | Paid Search (default; unaffected) |
bing | cpc | brand-uk | Paid Search Brand |
google | organic | brand | Organic Search (medium doesn't match ^cpc$) |
If all four rows return the expected channel, flip Live on the rule. Wait ~5 min.
Example 2 — Redirect the "AI" channel into "Referral"
Goal. You don't want the built-in AI channel in your reports; you want that traffic to appear as Referral.
Steps:
- In Default channels, find the AI row. Click Override.
- The form opens with the default's patterns pre-filled.
- Change only the
channel_namefromAItoReferral. - Leave priority at
50, leave Live off.
Test (toggle ON):
| Source | Medium | Campaign | Expected result |
|---|---|---|---|
chatgpt.com | referrer | (empty) | Referral (via your override) |
perplexity.ai | referrer | (empty) | Referral (via your override) |
| Any non-AI referrer | referrer | (empty) | Referral (via the built-in Referral default — unchanged) |
Publish. If the built-in AI default is later extended to cover more sources, your override — which uses the same pre-filled pattern — will keep matching whatever the current definition catches. If you want to freeze the behavior to the patterns at the time of override, that's exactly what an override does; if you'd rather track future changes, delete the override and let the default flow through again.
Example 3 — Split a default into two custom channels
Goal. The default Paid Social covers all social networks with a paid medium. You want to split it into Paid Social — Meta (Facebook + Instagram) and Paid Social — Others (everything else).
Steps:
- Click Override on the Paid Social default. The form pre-fills with the full list of social sources.
- Narrow
source_patternto^(facebook|instagram|fb|ig)$. Setchannel_nametoPaid Social — Meta. Priority110. Save as draft. - Click Override on Paid Social again. This time set
channel_nametoPaid Social — Others. Keep the full pre-filled source list. Priority100(lower than Meta so Meta wins first).
You now have two draft rules. Both must be tested before publishing.
Test:
| Source | Medium | Campaign | Expected result |
|---|---|---|---|
facebook | cpc | (any) | Paid Social — Meta |
instagram | paid | (any) | Paid Social — Meta |
linkedin | cpc | (any) | Paid Social — Others |
tiktok | paid | (any) | Paid Social — Others |
Publish both. In your Sources → Channels report you'll now see the two channels instead of a single "Paid Social".
Example 4 — Add a channel for affiliate partners
Goal. You work with two affiliate partners, awin and partnerize. Traffic from them currently ends up in Referral or Unassigned. You want a dedicated Affiliates channel.
Rule to create:
| Field | Value |
|---|---|
| Channel name | Affiliates |
| Source pattern | ^(awin|partnerize)$ |
| Medium pattern | (empty) |
| Campaign pattern | (empty) |
| Priority | 50 |
| Live | off (draft) |
An empty medium/campaign is a wildcard — any medium/campaign from those two sources will be classified as Affiliates. That's usually what you want for affiliate traffic (each partner picks its own medium naming).
Test:
| Source | Medium | Campaign | Expected result |
|---|---|---|---|
awin | affiliate | (any) | Affiliates |
partnerize | (empty) | (any) | Affiliates |
awin | email | (any) | Affiliates (source wins; medium wildcard) |
impact | affiliate | (any) | Referral (source doesn't match) — if you also want Impact, extend the source pattern to ^(awin|partnerize|impact)$ |
Publish.
Example 5 — Track a single big newsletter as its own channel
Goal. Your monthly newsletter drives a lot of revenue. You want to see it as its own channel (not just bucketed with generic Email).
Prerequisite. You have to be tagging the newsletter URLs consistently. In this example, we assume the newsletter uses utm_source=newsletter&utm_medium=email&utm_campaign=monthly-YYYY-MM.
Rule to create:
| Field | Value |
|---|---|
| Channel name | Monthly Newsletter |
| Source pattern | ^newsletter$ |
| Medium pattern | ^email$ |
| Campaign pattern | ^monthly- |
| Priority | 120 |
| Live | off (draft) |
The campaign pattern uses ^monthly- (anchored at the start) so any month/year suffix matches. Priority 120 ensures this wins over any other Email-related rule.
Test:
| Source | Medium | Campaign | Expected result |
|---|---|---|---|
newsletter | email | monthly-2026-07 | Monthly Newsletter |
newsletter | email | monthly-2026-08 | Monthly Newsletter |
newsletter | email | black-friday-launch | Email (default; campaign doesn't match) |
mailchimp | email | monthly-2026-07 | Email (default; source doesn't match) |
Publish.
Example 6 — Bulk migration via CSV import
Goal. You already run a Google Analytics or GA4 property with custom channel groupings and want to bring the same set into Sealmetrics.
Steps:
- In Site settings → Channels, click Export. You get a CSV with your current custom rules (empty on a fresh site).
- Open the file in Excel/Google Sheets. Add the rows you need. Set
is_activetofalsefor everything you want to review before publishing. - Save as CSV (UTF-8). If Excel offers "CSV UTF-8 (Comma delimited)", pick that.
- Back in the dashboard, click Import and pick the file. The dashboard shows a preview.
- Confirm the import. All rules are created as drafts (because you set
is_active=false) and any previous custom rules are replaced entirely (import is replace-all). - Test each rule with the tester (toggle ON). When you're satisfied, flip Live on the ones you want to publish.
Example CSV content:
channel_name,source_pattern,medium_pattern,campaign_pattern,priority,is_active
Paid Search Brand,^(google|bing)$,^cpc$,brand,110,false
Paid Social — Meta,^(facebook|instagram|fb|ig)$,^(cpc|paid|paid-social)$,,110,false
Paid Social — Others,^(linkedin|twitter|x|tiktok|pinterest|snapchat|reddit)$,^(cpc|paid|paid-social)$,,100,false
Affiliates,^(awin|partnerize|impact)$,,,50,false
Monthly Newsletter,^newsletter$,^email$,^monthly-,120,false
After importing, your Channels tab shows five drafts. Review them in the tester and publish the ones you're happy with.
Limits and edge cases
- Maximum 100 custom rules per site (drafts included).
- Cache refresh: ~5 minutes. After you activate or edit a rule, expect a few minutes before the pixel picks it up.
- Not retroactive. Historical hits keep the channel they had at ingest time. A new rule only affects new traffic.
- Regex compile errors are surfaced immediately. If you save an invalid pattern, the form (or import) rejects it with the exact error — you never end up with a rule that silently fails to match.
- Rejoined / rejoined-traffic stays in
Unassignedby design (GA4 parity). If you want to classify it, create your own rule.
Related
- UTM Mapping — if your team uses custom URL parameters (
campaign_id,source_id…), map them to standard UTMs before writing channel rules. UTM Mapping runs first at ingest; channel rules then see the mapped UTMs as if they were explicit. - IP Exclusions — discard traffic from specific IPs (offices, QA, uptime robots) entirely, before any channel classification happens.
- Sources report — where the channels are shown.
- Referral vs direct traffic — how those two default channels are decided.
- MCP Server — how to connect an AI assistant to your Sealmetrics data.