Skip to main content

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

  1. Open Site settings (gear icon, top right).
  2. Go to the Channels tab.

You'll see three areas:

  • Test a visit — a live tester that classifies a source / medium / campaign combination 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:

  1. Your custom rules first, sorted by priority (highest first).
  2. Then the default channels, also by priority.
  3. The first rule that matches wins — its channel_name is stored with the hit.
  4. 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.

Changes are not retroactive

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:

  1. Create a rule from the form (or import a CSV, or ask your MCP-connected assistant to draft one).
  2. 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.
  3. 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 no utm_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 referrer for 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:

  1. Test with the toggle off — does it match a live rule you didn't expect (perhaps an old override)?
  2. Test with the toggle on — does it match your new draft? If not, your pattern is wrong.
  3. Look at each of your three patterns in isolation: an AND is 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:

ScenarioSourceMediumCampaignWhat to check
Direct traffic(direct)(none)(empty)Falls into Direct.
Untagged referrer (external site links to you)referrerreferrer(empty)Falls into Referral.
Your main paid-search campaigngooglecpcyour usual campaign valueFalls into your intended paid channel.
A campaign with a "brand" naming conventiongooglecpcbrandFalls into Paid Search Brand (or wherever your rule points).
A social alias your team usesfb (or whatever alias)cpc(empty)Falls into Paid Social (via your custom rule).
An affiliate partneryour 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 0 to 1000. Only used to order your custom rules against each other. Leave it at 50 unless you need one rule to win over another.
  • Live switch — off by default. Turn it on after testing.

Common patterns:

GoalSource patternMedium patternCampaign patternChannel name
Split brand campaigns from generic paid search^(google|bing)$^cpc$brandPaid 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)Email

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

  1. Open Site settings → Channels.
  2. Scroll to the Default channels table.
  3. Find the default row you want to change. Click Override.
  4. 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 50 and Live off — the same defaults as any new rule (born as a draft).
  5. Adjust as needed:
    • To redirect the traffic to a different channel: change channel_name only. 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.
  6. 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.
  7. 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_name to Referral (or Organic 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 Direct or Referral depending 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 search and Paid Search are 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 50 is 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.
  • priority01000. Empty defaults to 50.
  • is_activetrue or false (case-insensitive). Empty defaults to true. 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:

ToolWhat it does
test_channel_rulesRun the tester with any source/medium/campaign combination. Read-only.
create_channel_ruleCreate a new rule as a draft.
update_channel_ruleEdit an existing rule — drafts only.
delete_channel_ruleDelete a rule — drafts only.
import_channel_rulesBulk-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):

FieldValue
Channel namePaid Search Brand
Source pattern^(google|bing)$
Medium pattern^cpc$
Campaign patternbrand
Priority110
Liveoff (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):

SourceMediumCampaignExpected result
googlecpcbrand-summer-2026Paid Search Brand
googlecpcnonbrand-generic-termsPaid Search (default; unaffected)
bingcpcbrand-ukPaid Search Brand
googleorganicbrandOrganic 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:

  1. In Default channels, find the AI row. Click Override.
  2. The form opens with the default's patterns pre-filled.
  3. Change only the channel_name from AI to Referral.
  4. Leave priority at 50, leave Live off.

Test (toggle ON):

SourceMediumCampaignExpected result
chatgpt.comreferrer(empty)Referral (via your override)
perplexity.aireferrer(empty)Referral (via your override)
Any non-AI referrerreferrer(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:

  1. Click Override on the Paid Social default. The form pre-fills with the full list of social sources.
  2. Narrow source_pattern to ^(facebook|instagram|fb|ig)$. Set channel_name to Paid Social — Meta. Priority 110. Save as draft.
  3. Click Override on Paid Social again. This time set channel_name to Paid Social — Others. Keep the full pre-filled source list. Priority 100 (lower than Meta so Meta wins first).

You now have two draft rules. Both must be tested before publishing.

Test:

SourceMediumCampaignExpected result
facebookcpc(any)Paid Social — Meta
instagrampaid(any)Paid Social — Meta
linkedincpc(any)Paid Social — Others
tiktokpaid(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:

FieldValue
Channel nameAffiliates
Source pattern^(awin|partnerize)$
Medium pattern(empty)
Campaign pattern(empty)
Priority50
Liveoff (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:

SourceMediumCampaignExpected result
awinaffiliate(any)Affiliates
partnerize(empty)(any)Affiliates
awinemail(any)Affiliates (source wins; medium wildcard)
impactaffiliate(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:

FieldValue
Channel nameMonthly Newsletter
Source pattern^newsletter$
Medium pattern^email$
Campaign pattern^monthly-
Priority120
Liveoff (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:

SourceMediumCampaignExpected result
newsletteremailmonthly-2026-07Monthly Newsletter
newsletteremailmonthly-2026-08Monthly Newsletter
newsletteremailblack-friday-launchEmail (default; campaign doesn't match)
mailchimpemailmonthly-2026-07Email (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:

  1. In Site settings → Channels, click Export. You get a CSV with your current custom rules (empty on a fresh site).
  2. Open the file in Excel/Google Sheets. Add the rows you need. Set is_active to false for everything you want to review before publishing.
  3. Save as CSV (UTF-8). If Excel offers "CSV UTF-8 (Comma delimited)", pick that.
  4. Back in the dashboard, click Import and pick the file. The dashboard shows a preview.
  5. 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).
  6. 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 Unassigned by design (GA4 parity). If you want to classify it, create your own rule.
  • 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.