Channel grouping in Google Analytics should be a marketer’s best friend but in most cases it’s very much an underutilised feature.
There is a clear disconnect between analytics teams and marketing teams in how to report on channel performance, not only technically but both teams end up reporting against different objectives. Channel grouping is one way to unite both teams in talking the same language and driving against the same business objectives. A common question may be “which channels drove the most orders last month” the question won’t be “what source/medium drove the most orders last month”
The challenge with reporting on source / medium it becomes too complex for many to understand, and it’s often disjointed from the overall strategy. The one way to get around the complexity is by thinking of channels / channel groupings and how it aligns to the channel mix and marketing strategy.
To take advantage of channel grouping you need to have a consistent UTM tagging approach, past audits I have done 20% of brands had a good UTM tagging approach, which is higher than I would have expected but those 20% were not using the channel grouping feature.
How to manage channel grouping
The 2 ways of managing channel groupings is via the Google Analytics (GA4) interface or via connecting to Big Query for free.
Managing channel groupings within the interface the biggest advantage is that it can split out Google search and paid channels into granular channel groupings i.e., Paid Search v Paid Video v Display. For non-Google channels it’s dependent on a consistent approach UTM tagging otherwise Google Analytics will assign the traffic to the wrong channel grouping.
Managing channel grouping via Big Query provides a lot of flexibility in how channel groupings are defined v how it’s communicated within the marketing teams and the business. The bonus of using Big Query it can connect to Looker Studio where the dashboard created can easily be shared.
Taking into consideration GA4 has a max of 14 months of data retention where Big Query is unlimited starting from the day GA4 is connected to Big Query.
To take advantage of channel grouping either within the GA4 interface or Big Query it requires a smart but consistent UTM tagging approach.
Case Study
Working with a midsized e-commerce brand Q1 2023 deployed Google Analytics (GA4) with a full implementation giving the brand minimum 4 months (got 7 months) of comparative data to GA3. With GA4 + Big Query collecting the data then the focus was on getting better insights the brand was looking to scale but had no real insights to help understand the channel mix.
There was 4 months to nail down how channels are defined and fix how campaigns are tagged.
As a brand they had a good understanding of traffic and sales coming from performance led channels. They had just started investing into awareness channel defined as ‘brand’ on the plans with bigger investment Q3 onwards, it was a grey area in understanding the impact of those channels. This helped shaped how to best structure the campaign tags. Their core focus of measurement was very much based around Google Analytics.
The current set-up of campaign tagging did not align, once deployed it would provide a very different outlook.
At the time channel grouping was not a feature within GA4 so Big Query was the only option available. There is value in setting up channel grouping in both GA4 and within Big Query.
Setting up channel grouping to align to the marketing strategy
How channel groupings are defined is very much open for debate. Below are the steps taken to get to better channel reporting.
For the e-commerce brand the focus was understanding channel performance brand v performance, that was how the marketing plans were split. Which made the process easier in approaching how to set-up UTM tagging and channel grouping.
- Phase 1: Analytics and marketing teams understanding the channel mix and how channels are currently reporting within Google Analytics and how they would like to report on channels within Google Analytics:
- Worked out how to best implement UTM tagging on paid and owned channels
- This took over a course of a month to align to an agreed approach
- Phase 2: Rolled out the changes for paid and owned channels.
- Over a 3 month period there were small changes made to the UTM tagging which only came from understanding the data in the reports.
- Phase 3: Started building out the channel grouping so the different teams can better understand the data and reports.
After 4 months the winning formula for UTM tagging and channel grouping was found and in month 5 the first month no changes were made and there would be a solid base of channel reporting.
This is a snapshot view of how the final UTM tagging was implemented. It allowed the campaign data to be cut and sliced in many ways that was not possible before. The initial focus was on source, medium + campaign, content and term would be looked at once there is trust and consistency with the channel approach.
UTM | Description | Example |
utm_source | Source of the traffic | facebook, guardian, google |
utm_medium | Channel | brandpaidsocial, paidsocial, brandorganicsocial, organicsocial |
utm_campaign | Campaign name | valentines, easter, christmas |
utm_content | Campaign categorisation | n/a |
utm_term | Product categorisation | n/a |
This was implemented for all paid and owned channels including Paid Search which did not link Adwords via auto tagging. For Email there was also a new structure implemented mainly around how campaigns were labelled to provide better insights.
With the structure implemented it provides flexibility in how channel groupings can be configured. Using Big Query multiple dashboard views can be provided to understand:
- All brand channels v All performance channels v Email v Direct v Organic
- Search (Paid + Organic) v Social (Paid + Organic)
- Organic (Search + Social) v Paid (Paid Search + Paid Social + Display etc)
The different views that are now available aligns closer to the business and marketing needs which was not possible before.
Channel Grouping Insights
The insights that came from 3 months of using channel grouping provided a totally different outlook on performance than before.
- Direct traffic was reduced by 30%
- Referral traffic was reduced by 15%
- Organic Social accounted for 20% traffic
- When looking at metric performance in traffic and revenue Social performance was stronger than Search
Using Big Query to report on Channel Grouping
The big advantage of using Big Query for channel grouping it allows huge amount of flexibility:
- For any source or medium in-correctly inputted it can be updated i.e., no more typos, source and medium aligned to the agreed framework
- Once the source and medium have been updated it will allow the channel grouping to be mapped out as per agreed framework
- For any source or medium not recognised it will be reported as attention! so that changes can be made
Updating the Big Query code
- Line 19 input the correct table name
- Line 41 to 69 is where the source and medium can be updated
- Line 84 to 102 is where the channel grouping can be updated
with temp as(
select
concat((select value.int_value from unnest(event_params) where key = 'ga_session_id'), user_pseudo_id) as session_id,
user_pseudo_id as ga_client_id,
array_agg(
if(event_name in('page_view'), struct(
event_timestamp,
lower((select value.string_value from unnest(event_params) where key = 'source')) as source,
lower((select value.string_value from unnest(event_params) where key = 'medium')) as medium,
lower((select value.string_value from unnest(event_params) where key = 'name')) as name,
lower((select value.string_value from unnest(event_params) where key = 'campaign')) as campaign,
lower((select value.string_value from unnest(event_params) where key = 'page_title')) as page,
(select value.int_value from unnest(event_params) where key = 'entrances') as is_entrance,
(select value.int_value from unnest(event_params) where key = 'ignore_referrer') as ignore_referrer
), null)
ignore nulls) as channels_in_session,
countif(event_name = 'purchase') as conversions,
sum(ecommerce.purchase_revenue) as conversion_value
from `enter.tablename_123456.events_*`
group by user_pseudo_id, session_id
),
traffic as(
select
(select t.source from unnest(channels_in_session) as t where t.ignore_referrer is null order by t.event_timestamp asc limit 1) as old_source,
(select t.medium from unnest(channels_in_session) as t where t.ignore_referrer is null order by t.event_timestamp asc limit 1) as old_medium,
(select t.campaign from unnest(channels_in_session) as t where t.ignore_referrer is null order by t.event_timestamp asc limit 1) as campaign,
(select t.name from unnest(channels_in_session) as t where t.ignore_referrer is null order by t.event_timestamp asc limit 1) as name,
(select t.page from unnest(channels_in_session) as t where t.ignore_referrer is null order by t.event_timestamp asc limit 1) as page,
session_id,
count(distinct session_id) as sessions,
sum(conversions) as conversions,
ifnull(sum(conversion_value), 0) as conversion_value
from temp
group by 1, 2, 3, 4, 5,6
),
fin as(
select
old_source,
old_medium,
case
when old_source = 'linkedin' then 'linkedin'
when old_source = 'facebook' then 'facebook'
when old_source = 'tiktok' then 'tiktok'
when old_source = 'twitter' then 'twitter'
when old_source = 'yahoo' then 'yahoo'
when old_source = 'google' then 'google'
when old_source = 'bing' then 'bing'
when old_source = 'criteo' then 'criteo'
when old_source = 'salesforce campaigns' then 'salesforce campaigns'
when old_source = 'awin' then 'awin'
when old_source = 'tradedoubler' then 'tradedoubler'
when old_source is null then '(direct)'
else 'attention!'
end as Source,
case
when old_medium = 'email' then 'email'
when old_medium ='affiliates' then 'affiliates'
when old_medium = 'organic social' then 'organic social'
when old_medium = 'paid social' then 'paid social'
when old_medium = 'display' then 'display'
when old_medium = 'cpc' then 'cpc'
when old_medium = 'referral' then 'referral'
when old_medium = 'organic' then 'organic'
when old_medium is null then 'none'
else 'attention!!'
end as Medium,
session_id,
count(distinct session_id) as sessions,
sum(conversions) as conversions,
ifnull(sum(conversion_value), 0) as conversion_value
from traffic
group by 1, 2,3,4,5
)
select
old_source,
old_medium,
Source,
Medium,
case
when Source ='(direct)' and Medium ='none' then 'Direct'
when regexp_contains(Source, r'^(google|yahoo|bing)$') and regexp_contains(Medium, r'^(organic)$') then 'Organic Search'
when regexp_contains(Source, r'^(google|bing)$') and regexp_contains(Medium, r'^(.*cp.*|ppc|paid.*)$') then 'Paid Search'
when regexp_contains(Source, r'^(youtube|twitter|facebook|fb|instagram|tiktok|ig|linkedin|pinterest)$')
and regexp_contains(Medium, r'^(paid social|paid_social|social_paid|paid-social|social-paid)$')
then 'Paid Social'
when regexp_contains(Source, r'^(twitter|t.co|facebook|fb|instagram|tiktok|ig|linkedin|pinterest)$')
and regexp_contains(Medium, r'^(referral|organic social|organic_social|social_organic|organic-social|social-organic)$')
then 'Organic Social'
when regexp_contains(Medium, r'^(none)$') then 'Direct'
when regexp_contains(Medium, r'^(display)$') then 'Display'
when regexp_contains(Medium, r'^(organic)$') then 'Organic Search'
when regexp_contains(Medium, r'^(organic social)$') then 'Organic Social'
when regexp_contains(Medium, r'^(paid social)$') then 'Paid Social'
when regexp_contains(Medium, r'^(email)$') then 'Email'
when regexp_contains(Medium, r'^(affiliate|affiliates)$') then 'Affiliates'
when Medium = 'referral' then 'Referral'
else '(other)'
end as ChannelGrouping,
sum(sessions) as sessions,
sum(conversions) as conversions,
sum(conversion_value) as conversion_value
from fin
group by 1,2,3,4
order by 6 desc
Once the Big Query code has been updated which will regularly need maintenance will allow to report on source, medium and channel grouping.