Open the Pages and screens report on any real website and you are looking at hundreds of rows. Every blog post is its own line. Every product detail page is its own line. Pagination, query strings, and trailing slashes splinter what should be one number into ten. The report is technically complete and practically useless: nobody scrolling that list can tell you whether the blog is up this month or whether product pages are quietly tanking.
The question you actually want answered is about sections, not URLs. How is "the blog" doing against "pricing" against "product"? That requires grouping pages that belong together into named buckets. GA4 has a native mechanism for this, and it works, but it asks more of you than most teams expect.
The problem with page-path reports
Raw page paths are the wrong grain for almost every reporting conversation. A path like /blog/ga4-content-grouping tells you about one article. What a stakeholder wants to know is whether content marketing is pulling its weight overall, and you cannot read that off a list of 400 individual posts. You end up exporting to a spreadsheet, writing fragile =IF(LEFT(...)) formulas, and rebuilding the same buckets by hand every month.
Worse, the raw list is dishonest by omission. A category that is collapsing across fifty low-traffic pages never surfaces, because no single URL is big enough to notice. You only see the decline when the pages are summed into one row. Grouping is not a nicety here; it is the difference between seeing a trend and missing it.
GA4's native answer: the content_group parameter
GA4 ships a built-in dimension for exactly this, populated by a parameter called content_group. You set it on the page_view event, and GA4 exposes a "Content group" dimension you can drop into standard reports and Explorations with no custom definition required. It is one of the few reserved parameters that gives you a first-class reporting dimension for free.
| Page | Value to send | What it groups |
|---|---|---|
/pricing |
Pricing |
Every plan and quote page into one row |
/blog/* |
Blog |
All articles into a single "Blog" line |
/products/* |
Product |
Every product detail page together |
/, /about |
Marketing |
Home and top-of-funnel pages |
The value is just a string you decide on a per-page basis. The trick is computing the right string at the moment the page loads, which means your tagging has to know which section the current page belongs to before it fires the view. Here is what that looks like with gtag() directly and as the equivalent dataLayer push for GTM:
// gtag() direct: set content_group on the page_view
gtag('event', 'page_view', {
page_location: window.location.href,
page_title: document.title,
content_group: 'Blog' // computed from the URL/template
});
// Equivalent dataLayer push (for GTM)
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'page_view',
content_group: 'Blog'
});
In GTM you would read content_group from a Data Layer Variable and map it into the GA4 configuration tag's fields. On most sites the value comes from a CMS template name, a body class, or a regex on the path. However you derive it, the value has to be present and correct on every single page before the view fires.
The limits you will hit
The content_group parameter works, but it is strict in ways that catch teams out. None of these are bugs; they are the cost of doing the grouping at collection time rather than at report time.
- It only exists if you set it in code or GTM. There is no admin screen where you draw buckets. Every page must emit the right value, which means a tagging change and, usually, a developer or a GTM build.
- It is not retroactive. The dimension is populated from collected events only. Turn it on today and yesterday stays blank forever.
- Changing the logic restarts history. If you rename "Product" to "Shop" or split "Blog" into "Guides" and "News," the old and new values sit side by side and your trend line fractures at the changeover date.
- It is a single dimension. GA4 gives you one
content_groupslot per page view, so overlapping schemes (by topic and by funnel stage, say) are awkward; you have to pick one or fall back to additional custom dimensions.
Content grouping in GA4 is never retroactive. Whatever you do not tag today is blank forever, and the day you change your grouping rules is the day your historical trend line breaks in two.
If you must use content_group, drive it from a GTM lookup table rather than scattering literal strings across templates. Map a path-pattern variable to group names in one place, and you can adjust the buckets in a single tag instead of hunting through page code every time marketing renames a section.
The maintenance reality
For a team that controls its tagging and ships changes easily, content_group is the right tool. For everyone else, it is a standing tax. Plenty of sites cannot edit their tagging on demand: the GTM container is owned by an agency, the CMS templates are frozen, or every change goes through a release queue that turns a five-minute bucket tweak into a three-week ticket.
That friction has a compounding cost, because grouping is exactly the thing you want to revise often. Marketing launches a new section, you spin up a campaign landing-page hub, the product range gets reorganised. Each of those is a reason to re-cut your buckets, and with native content grouping each one means another tagging change and another break in your history. The mechanism that is supposed to make reporting clearer quietly becomes the thing you avoid touching.
In adop.tools
In adop.tools, content groups are rule-based: you match pages into named buckets by their URL path or page title, so you get Pricing, Blog, and Product rows without editing a single tag or sending a content_group parameter at all. Because the rules run over data already collected, they apply to your full history and you can rewrite them whenever a section changes without breaking the trend. The content breakdown reads straight from those rules, so the grouping you see in the report is the grouping you defined, retroactive and editable on the spot.
Which approach to choose
If you own your tagging, ship freely, and want grouping baked into the raw data that every downstream tool reads, set content_group and accept that it is permanent the moment you turn it on. If you cannot easily edit tagging, or you expect your buckets to keep evolving, do the grouping at report time with rules over the page path instead. Either way, the goal is the same: stop reading four hundred URLs one at a time and start reading the handful of sections your stakeholders actually ask about.