Skip to content

Content Groups

Valid as of April 2026, GA4 property interface.

Content Groups are GA4’s built-in way to categorize content above the page-URL level without consuming a custom-dimension slot. If you have ever wanted to see “Blog”, “Product Detail”, “Pricing”, and “Support” as top-level rows in a report instead of hundreds of individual page paths, Content Groups are the intended solution.

They existed in Universal Analytics, disappeared from the initial GA4 release, and returned as a first-class feature. They are underused, partly because the GA4 documentation treats them as an afterthought.

How Content Groups differ from custom dimensions

Section titled “How Content Groups differ from custom dimensions”

Content Groups look like a custom dimension at first glance — a string value you set per event, surfaced as a dimension in reports. The differences matter:

AttributeContent GroupEvent-scoped custom dimension
Per-property limit5 content groups50 custom dimensions
Registration requiredNo — just send the parameterYes — register in Admin before collection
Dimension name in reportsContent groupWhatever you name it
Parameter namecontent_group (exactly)Any valid parameter name
Counts toward 25-parameter event limitYesYes
Available in standard reportsYes, in Engagement → Pages and screensOnly if built into an Exploration or custom report
Retroactive for historical dataNo — only populated for events after you start sending itNo

The practical takeaway: if you are already close to the 50-dimension cap, Content Groups let you categorize pages without using a slot. And because they are a known GA4 field, they integrate naturally into the standard Pages and screens report without explicit custom-report work.

The mechanism is a single event parameter named exactly content_group. Send it with page_view events (and any other events where page context matters — view_item, scroll, custom events, etc.).

<script>
gtag('event', 'page_view', {
page_location: window.location.href,
page_title: document.title,
content_group: 'Blog'
});
</script>

The parameter name is content_group — lowercase, snake_case, no trailing s. GA4 silently ignores contentGroup, content-group, Content_Group, and content_groups. If the dimension is consistently empty in reports, the first thing to check is the parameter name in DebugView.

Values are case-sensitive in reports. Blog and blog will appear as two separate rows. Normalize casing at the tagging layer.

The Reports → Engagement → Pages and screens report has Content group as a selectable primary dimension. Click the dropdown over the first column and pick it. The report then aggregates views, users, and engagement by content group instead of page path or title.

Content group also appears in:

  • Explore — in the dimension picker under the “Page / screen” group.
  • Secondary dimension on any Engagement or Monetization report.
  • Filter on most reports and Explorations.

Use the dimension name contentGroup (camelCase, unlike the parameter name) in Data API calls and in Data Studio via the GA4 connector. The Data Studio connector exposes it automatically once it starts receiving data.

GET https://analyticsdata.googleapis.com/v1beta/properties/123456789:runReport
{
"dateRanges": [{ "startDate": "28daysAgo", "endDate": "yesterday" }],
"dimensions": [{ "name": "contentGroup" }],
"metrics": [
{ "name": "screenPageViews" },
{ "name": "activeUsers" },
{ "name": "userEngagementDuration" }
]
}

In the BigQuery export, content_group is a regular event parameter inside event_params. Unnest it the same way as any other parameter:

SELECT
(SELECT value.string_value
FROM UNNEST(event_params)
WHERE key = 'content_group') AS content_group,
COUNT(*) AS views,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `project.dataset.events_*`
WHERE event_name = 'page_view'
AND _TABLE_SUFFIX BETWEEN '20260401' AND '20260430'
GROUP BY content_group
ORDER BY views DESC;

When to use Content Groups vs. custom dimensions

Section titled “When to use Content Groups vs. custom dimensions”

The recommended pattern is one Content Group per site section, plus event-scoped custom dimensions for finer attributes inside each section. A blog post event might have:

event_name: page_view
content_group: Blog
page_title: "Understanding GA4 Content Groups"
article_author: "Jane Doe" ← custom dimension
article_category: "Analytics" ← custom dimension
article_published_year: "2026" ← custom dimension

This gives you a five-row top-level breakdown in standard reports plus rich filtering in Explorations.

  1. 5 Content Groups per property. Unlike custom dimensions, there is no way to “archive” a content group to free a slot. Once you start sending a value, plan to keep it.

  2. One Content Group dimension. There is a single content_group field, not content_group_1 through content_group_5 as in Universal Analytics. The “5” is the count of distinct values the property will track per session for backwards analysis — but in day-to-day use you send a single string per event.

  3. Standard 25-parameter-per-event limit applies. content_group counts against it.

  4. 500-character limit per value. Keep values short — they are labels, not descriptions.

  5. No retroactive application. Values only populate for events collected after you implement the parameter. Historical events show (not set).

Renaming or restructuring content groups creates a discontinuity in reports. If you change “Blog” to “Articles”, your historical data still reads “Blog” and new data reads “Articles” — they appear as two rows, not as one renamed row.

Best practices:

  • Decide your taxonomy before implementation.
  • Document it — the GA4 interface does not store descriptions for content groups.
  • If you must rename, do it at a clean period boundary (start of quarter/year) and annotate the change so dashboard viewers know what happened. See Annotations.

Sending contentGroup instead of content_group

Section titled “Sending contentGroup instead of content_group”

The most common implementation bug. GA4 does not warn you — it simply drops the parameter silently. Verify in DebugView: the Content group field on any event should show your value. If it is always (not set), the parameter name is wrong.

If you want Content Group to appear on engagement events, key events, and scroll events too, send content_group on those events as well. The easiest approach in GTM is setting it as a global “Event parameter” on the Google tag, which injects it into every outgoing event.

A blog that launches with Tutorials, News, Case Studies, Opinion, Reviews has used all five. If you later add Podcasts, you either retire one of the five or merge it into the nearest existing category. Choose broader categories than you think you need.

content_group: '/blog/2026/04/understanding-content-groups' is not a Content Group — it is a page path. Content Groups are for categorization, not identification. High-cardinality values fragment reports and defeat the purpose.

An event that was collected without content_group is permanently (not set) for that dimension. There is no tool to back-fill. Plan for this when you change taxonomy.