DATA QUALITY 7 min read

The Custom Dimension That Ate Your Report: GA4 Cardinality Explained

LastClarity

The short answer

A dimension with more than 500 unique values in a day is high cardinality in GA4. High-cardinality dimensions push reports toward the daily row limit, and everything beyond it is collapsed into a single (other) row. The data still exists; the report just cannot display that many distinct values.

Somebody registers a custom dimension for page_url_with_params, or transaction_id, or search_query. It works for a week. Then the report fills with a row called (other) that accounts for most of the traffic, and the dimension becomes useless.

Nothing was lost. The report simply cannot show that many distinct values, and the design decision that caused it was made weeks earlier.

The two numbers that govern this

500 unique values per day makes a dimension high cardinality in GA4’s terms.

50,000 rows per day is the report limit on a standard property. (GA4 360 raises it to 1,000,000.) Once a report exceeds that, the overflow is collapsed into a single (other) row.

The connection between them is the part people miss: a high-cardinality dimension does not just make its own report messy, it generates rows, and rows are the shared budget every report draws from.

What is high cardinality in practice

DimensionTypical distinct values/daySafe?
Device category3yes
Countryup to ~200yes
Landing page (clean paths)tens to hundredsusually
Page URL with query stringsthousandsno
Internal search termthousandsno
Transaction IDone per ordernever
User IDone per usernever
Timestampone per eventnever

The bottom three share a property: they are effectively unique per event. That is the maximum possible cardinality, and registering any of them as a reporting dimension guarantees (other).

Query strings are the usual culprit

The most common accidental high-cardinality dimension is not a custom one at all. It is your page path, once UTM parameters, session IDs, filter states and tracking parameters are attached:

/products              →  1 value
/products?utm_source=fb&utm_campaign=spring&fbclid=IwAR3x...
/products?utm_source=fb&utm_campaign=spring&fbclid=IwAR9k...
/products?sort=price&filter=blue&page=2

One page becomes thousands of rows, none of which you want separately. GA4’s pagePath dimension excludes the query string, but if you have built custom tracking on the full URL — or your SPA writes state into the query string — you have manufactured the problem yourself.

Strip parameters before they become dimensions. In GTM, use a variable that returns the path without the query string, and only keep the specific parameters you genuinely report on.

The design rule that avoids nearly all of this: a reporting dimension should answer “which group does this belong to?” If a value identifies one specific thing rather than a group, it is an identifier, not a dimension. Identifiers belong in BigQuery.

Designing parameters that survive

Bucket instead of recording raw values. Do not send time_on_page: 47. Send engagement_bucket: 30-60s. Four values instead of hundreds, and it is what you would have grouped into anyway.

Send price ranges, not prices. price_band: 50-100 rather than price: 87.42.

Cap free text. Internal search terms are genuinely high cardinality and genuinely useful. Accept (other) in the long tail, or analyse them in BigQuery, but do not register them as a dimension expecting complete reporting.

Keep identifiers as parameters, not dimensions. transaction_id should absolutely be on the event — it is needed for deduplication and for BigQuery. It should never be a registered custom dimension.

Getting the detail back

Once (other) dominates, the options are narrow:

  1. Shorten the date range. Limits are per day, so a single day may fit where thirty do not.
  2. Filter the report. Fewer rows in scope, fewer rows to collapse.
  3. Use a lower-cardinality dimension that answers the same question — landing page group instead of full URL.
  4. BigQuery. The export has no row limits, no (other), and no thresholding. It is the only complete answer.

Enabling the BigQuery export costs nothing and takes minutes, but it is not retroactive — it only contains data from the day you turn it on. That alone is a reason to enable it before you need it.

The limit our tool shares

(other) is produced by Google, at query time, in the API. GA4 Simple View reads the GA4 Data API and receives the same collapsed rows the GA4 interface does. We cannot expand them, and no tool reading that API can.

Where we help marginally is in not making it worse: the panels request focused dimension sets with sensible row limits rather than pulling wide, high-cardinality breakdowns, so you hit the ceiling less often than an ad-hoc exploration would. That is a consequence of the reports being fixed, not a clever workaround.

If your analysis genuinely needs per-user or per-transaction granularity, that work belongs in BigQuery — and no dashboard, ours included, is the right tool for it.

Questions people also ask

Each answer stands on its own, so it still makes sense quoted somewhere else.

What is high cardinality in GA4?

A dimension is high cardinality when it has more than 500 unique values in a single day. Examples include page URLs with query strings, user IDs, timestamps, search terms and transaction IDs. High-cardinality dimensions produce many rows, which pushes reports toward their row limit.

What does the (other) row mean in GA4?

It is where GA4 puts everything that did not fit within a report's row limit. Standard properties cap reports at 50,000 rows per day. Once that is exceeded, the remaining values are aggregated into one row labelled (other). Your totals stay correct, but the individual values are no longer visible.

How do I get rid of the (other) row?

Reduce the number of distinct values the report has to handle. Use a shorter date range, apply a filter to narrow the report, choose a lower-cardinality dimension, or strip query parameters from page paths. If you need full granularity, the BigQuery export has no row limits and no (other) row.

Should I send a user ID or transaction ID as a custom dimension?

Not as a registered custom dimension for reporting. Both are essentially unique per event, which is the highest possible cardinality, and they will trigger (other) and can cause sampling. Send them as event parameters for BigQuery analysis, but do not register them as reporting dimensions.

Does the (other) row mean I lost data?

No. The events were collected and stored normally, and your totals remain accurate. Only the report's ability to break those totals down by individual value is affected. The full detail is retrievable through the BigQuery export.

Does high cardinality cause sampling in GA4?

It can. A high-cardinality parameter used as a custom dimension can degrade report performance and introduce sampling as well as the (other) row. This is why parameter design matters before you register a dimension rather than after you notice the reports have degraded.

#GA4#Cardinality#Custom Dimensions#BigQuery#Event Parameters

This is what we built instead

GA4 Simple View puts the numbers in this post on one screen, in one click, without building a report first.

Get the extension