TL;DR, Quick Answer
8 min readGA4 content grouping runs on one event parameter, content_group, which you set in the Google tag config, in a Google Tag Manager RegEx Table variable or on a Firebase screen_view event. GA4 reports the value in the Content group dimension, available in the Pages and screens report and in explorations. Automatically collected events such as session_start and first_visit don't accept the parameter, and an empty value shows as (not set). More groups need custom parameters registered as custom dimensions.
What is GA4 content grouping?
Google Analytics 4 handles GA4 content grouping through one event parameter, content_group, which your tag sends with a page's events so the Content group dimension can report pages in buckets you name. Google's help page on content groups says they "let you categorize pages and screens into custom buckets" so you can "see metrics for related groups of information." Its example puts men's clothing pages in one bucket and women's clothing pages in another. Use it when a report of hundreds of single URLs hides the question you actually ask, such as how the blog performs against the docs or the pricing pages.
Google's current help pages call the feature "content groups." Content grouping is the older name searchers still type, and it describes the same job: a category label per page.
The Data API schema defines the dimension in one line: Content group is "A category that applies to items of published content. Populated by the event parameter content_group." That second sentence is the whole mechanism. GA4 does not read your URL structure or your CMS categories. It reports whatever string your tag sent in that parameter, and nothing when the tag sent nothing.
How do you set content_group with the Google tag?
You set GA4 content grouping with the Google tag by adding content_group to the config command on each page, with the group name as its value. Google's help page gives this pattern for a men's clothing page:
gtag('config', 'G-XXXXXX', {
'content_group': 'mens'
});A women's clothing page gets the same code with 'womens'. The gtag config reference documents a second form that sets the value for every stream on the page, gtag('set', 'content_group', '/news/sports'), with the single-stream form gtag('config', 'STREAM_ID', { 'content_group': '/news/sports' }) beside it.
Order matters. The config reference says send_page_view defaults to true, so the default snippet sends a page_view as soon as config runs. Put the content_group value inside that config call, or call set before it, so the page_view carries the group. In practice, the cleanest source for the value is your page template: the CMS already knows whether a page is a blog post, a docs page or a product page, so print that into the snippet server side.
How do you set content groups in Google Tag Manager?
You set content groups in Google Tag Manager with a RegEx Table variable that matches the page path and outputs a group name, then pass that variable as the content_group field on your GA4 tag. Google's help page lays it out in two stages.
- In Google Tag Manager, go to Variables and click New under User-Defined Variables.
- Choose Variable Configuration, then Regex Table, and name the variable "Content Group".
- Set the Input Variable to
{{Page Path}}. - Add one row per group, with a regular expression as the pattern and the group name as the output.
- Select Set Default Values and enter "Other group" as the default when nothing matches.
- In Advanced Settings, clear Full Matches Only and Enable Capture Groups and Replace Functionality, then save.
- Open your GA4 tag, which Google's page calls the "Google Analytics: GA4 Configuration" tag, and under Fields to Set add a row with Field Name
content_groupand Value{{Content Group}}. - Save and publish the container.
Google's example table maps /mens to "Men's clothing page" and /womens to "Women's clothing page." With Full Matches Only cleared, a pattern like /mens is a partial match, so it also catches a path such as /blog/mens-style. Test each pattern against your real URLs in Preview mode before you publish.
Each variable and field you add is one more line to check when you audit a GTM container, so keep the table short.
Step 5 is the one people skip, and it pays for itself. A default value means every page carries some group, so pages that match no rule show up as "Other group" instead of being left without one.

Which setup method fits your site?
The right setup method depends on where your page categories live: in your templates, in your URL paths or in your app code. Google documents three methods.
| Method | Where you set the value | Best fit | Google's example |
|---|---|---|---|
| Google tag (gtag.js) | content_group in the config call, or gtag('set', ...) | Sites where the template knows the page type | 'content_group':'mens' |
| Google Tag Manager | RegEx Table variable on {{Page Path}}, passed in Fields to Set | Sites whose URL paths already separate sections | /mens outputs "Men's clothing page" |
| Firebase SDK (apps) | content_group parameter on a screen_view event | Mobile apps | No code sample on the content groups page |
Path-based rules in Tag Manager are the quickest to ship, and they break the day someone changes a URL structure. Template-based values in gtag take a developer's time once and then follow the content wherever it moves. Pick the method that matches where the truth about a page lives.
Where do content groups show up in GA4 reports?
Content groups show up in the Content group dimension, which Google says you select in the Pages and screens report or add to an exploration. In the Pages and screens report, selecting Content group as the dimension gives one row per group instead of one row per page. In an exploration, add Content group as a dimension and pair it with metrics such as views, or with page path to see which URLs sit in each group. A group row answers section-level questions. For one page, a landing page analysis that starts from entry pages answers more.
Read group metrics with the same care as page metrics. A group's views are page_view counts, while sessions and users are counted differently. The difference is laid out in pageviews vs sessions vs users, and it applies to a group row exactly as it does to a single page.
Flowsery
Start Your 14-Day Free Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
Content groups only cover data collected after you add the parameter. The dimension is populated by the event parameter, and Google's help page describes no way to assign groups to events that were sent without it. Ship the tag change before the reporting period you care about starts.

Why does the Content group dimension show (not set)?
The Content group dimension shows (not set) in two cases Google documents: when you combine it with automatically collected events such as session_start and first_visit, and when an event sends content_group with an empty value. Google's (not set) article explains the first case: "automatically collected events don't accept the content_group parameter. Thus, there's no valid data for this combination." For the second, it gives the example content_group: "".
That second case is an exception worth remembering. For most dimensions, an empty value shows as a blank, and only a missing value shows as (not set). Content group reports both as (not set), as covered in not set in GA4. Two fixes follow:
- Don't read Content group against session_start or first_visit counts. Pair it with page_view-based metrics instead.
- Never send an empty string. Set a default group, such as Google's "Other group," for pages that match no rule.
- Pages that match no rule are left without a group
- An empty content_group value reports as (not set)
- Set Default Values holds Other group
- Every page carries some group
- Unmatched pages show as Other group
How do you add more than one content group?
You add more content groups by creating your own custom parameters, such as content_group2 and content_group3, and registering each one as a custom dimension. Google's example uses a top-level group for Men's clothing, then content_group2 for Apparel and content_group3 for Shirts.
Only content_group feeds the built-in Content group dimension. The extra levels are ordinary event-scoped custom dimensions, so each one spends a slot from the quota explained in GA4 custom dimensions, and each one starts empty until the parameter is sent and the dimension is registered. Keep the values low-cardinality: a handful of section names splits a report cleanly, while a value per article turns the group into a second copy of page path.
How does Flowsery report pages without a content group parameter?
Flowsery reports pages directly from its script, with top pages, entry pages and filters by page, source, campaign or goal, and its funnels are built from "the pages or events" you choose as steps. The landing page analytics page describes comparing "pages by qualified visits, conversion rate, drop-off point, and revenue." Flowsery's revenue tracking attributes purchases to the campaigns, pages and referrers that drove them. Flowsery's product pages do not list a content group parameter, so the way to compare sections there is to filter by page or to add those pages as funnel steps, not to send a category label.
Frequently asked questions
Is content grouping available in GA4?
Yes. GA4 calls the feature content groups and runs it on the content_group event parameter. You set the parameter in the Google tag, in Google Tag Manager or on a Firebase screen_view event, and read it in the Content group dimension.
Where do I find content groups in GA4?
Select the Content group dimension in the Pages and screens report, or add it to an exploration. The dimension only holds values from events that carried the content_group parameter.
Why is my GA4 content group showing (not set)?
Google documents two causes. The dimension shows (not set) when combined with automatically collected events such as session_start and first_visit, which don't accept the parameter. It also shows (not set) when an event sends content_group as an empty string.
Do GA4 content groups apply to past data?
The Content group dimension is populated by the content_group event parameter, so events sent before you added the parameter carry no group. Google's help page describes no way to assign groups afterwards. Add the parameter before the period you want to report on.
How many content groups can GA4 have?
GA4 has one built-in Content group dimension fed by content_group. For more levels, Google says to create custom parameters such as content_group2 and content_group3 and register them as custom dimensions. Each one uses a custom dimension slot.
Can I set GA4 content groups without editing code?
Yes, with Google Tag Manager. Create a RegEx Table variable on {{Page Path}}, set a default value such as "Other group", and add it as the content_group field on your GA4 tag. Publish the container to start sending it.
What is the content_group parameter in GA4?
It is the event parameter that fills the Content group dimension. Your tag sends it with a page's events, and GA4 reports whatever string it carries. GA4 does not read your URL structure or CMS categories.
Is content grouping the same as content groups in GA4?
It is the same feature under two names. Google's current help pages say "content groups," while content grouping is the older name people still search for. Both mean a category label per page, set through the content_group parameter.
Flowsery
Start Your 14-Day Free Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
Does GA4 content grouping work in mobile apps?
Yes. With the Firebase SDK, you send the content_group parameter on a screen_view event. Google's content groups page gives no code sample for it, and you read the result in the Pages and screens report.
Why does my Tag Manager content group match the wrong pages?
With Full Matches Only cleared, a RegEx Table pattern is a partial match. A pattern like /mens also catches a path such as /blog/mens-style. Test each pattern against your real URLs in Preview mode before you publish.
Was This Article Helpful?
Let us know what you think!
See us more often in Google
One click marks Flowsery as a preferred source, so our articles sit higher in your Top Stories, AI Mode, and AI Overviews.
Before you go...
Flowsery
Revenue-first analytics for your website
Track every visitor, source, and conversion in real time. Simple, powerful, and cookie-free.
Real-time dashboard
Goal tracking
Cookie-free tracking
Related Glossary Terms


How to Build GA4 Calculated Metrics Inside a Five-Slot Quota
Google caps GA4 calculated metrics at 5 per standard property. Learn the formula syntax, the units, where they appear and what a formula can't use.


Google Lists Seven Separate Causes of not set in GA4
Google's docs give not set in GA4 a different cause per dimension, from a missing session_start to an empty content_group. Here is each cause and its fix.


Why Unique Visitors Meaning Changes From Tool to Tool
The unique visitors meaning depends on the tool: GA4 estimates it, Matomo refuses to compute it on long ranges, Adobe dedupes it across the whole report.


Reading Engagement Rate in Google Analytics 4
GA4 reports engagement rate as engaged sessions divided by total sessions. A session counts as engaged at 10 seconds, one key event, or two page views.


Why CNAME Cloaking No Longer Hides Trackers From Safari or Brave
Trackers used CNAME cloaking to pose as your subdomain. See how the DNS trick works, why Safari caps its cookies at 7 days and how Brave and uBlock uncloak it.


How Cookie Syncing Matches Ad IDs Across Websites
Ad-tech firms use cookie syncing to swap user IDs through redirects and pixels. See what Safari, Firefox and Chrome do about it and why analytics skips it.
Related Articles


What User Agent Client Hints Send, and What Analytics Still Sees
Chrome's user agent client hints split browser data into Sec-CH-UA headers. See low vs high entropy, Accept-CH, the reduced UA and what analytics reads.


How CHIPS Partitioned Cookies Give Each Site Its Own Jar
Setting CHIPS partitioned cookies takes Secure, SameSite=None and one more attribute, and the browser keeps a separate copy per top-level site.


Reversibility decides pseudonymisation vs anonymisation under the GDPR
Reversibility decides pseudonymisation vs anonymisation. Article 4(5) data stays personal data. Recital 26 anonymous data leaves the GDPR for good.

