Quick answer
Cardinality is the number of distinct elements in a set. In analytics it usually means how many distinct values a field or property holds (low for device type, high for user IDs or raw URLs); in data modeling it describes one-to-one, one-to-many or many-to-many relationships.
What is cardinality?
Cardinality is the number of distinct elements in a set. In data and analytics it has two everyday meanings:
- Column or property cardinality: how many distinct values a field holds.
device_type(desktop, mobile, tablet) has low cardinality;user_idor a full page URL has high cardinality. - Relationship cardinality in data modeling: how many rows in one table relate to rows in another, written one-to-one (1:1), one-to-many (1:N) or many-to-many (N:M).
In mathematics, cardinality is simply the size of a set, written |A|. The analytics meanings are applications of the same idea.
Low vs high cardinality
Sample event properties from a mid-sized product over 30 days (sample data):
| Property | Distinct values | Cardinality | Good as a report dimension? |
|---|---|---|---|
device_type | 3 | Low | Yes |
browser | 31 | Low | Yes |
event_name | 64 | Low–medium | Yes |
country | 187 | Medium | Yes |
page_path (template, e.g. /product/:id) | 420 | Medium | Yes |
page_url (raw, with query strings) | 186,000 | High | No |
user_id | 92,000 | Very high | No, filter or count instead |
session_id | 1,400,000 | Very high | No |
The rule of thumb: group by low and medium cardinality, filter or count by high cardinality. Nobody can read a bar chart with 186,000 bars, and a breakdown where every row has one visit says nothing.
Why high cardinality causes problems
- Unreadable reports. Breakdowns get truncated to the top values plus an "Other" bucket, and the long tail disappears.
- Slower queries and higher cost. Grouping by a field with millions of values means sorting and hashing millions of keys. Columnar stores compress low-cardinality columns very well and high-cardinality ones poorly.
- Fragmented metrics. If
/pricing?utm_source=xand/pricingare different values, page metrics split across thousands of rows. - Privacy risk. Free-text and ID fields with unique values can identify people. Do not put emails or names into properties.
Fixing high cardinality in tracking
- Normalize URLs into templates. Strip query strings and replace IDs:
/order/83721→/order/:id. Keep campaign data in UTM fields, not in the path. - Bucket continuous values. Send
price_band: "50-100"alongside the exact amount if you need a dimension. - Keep IDs as identifiers, not dimensions. Use
user_idto count distinct people and to identify users, not to group charts. - Use enumerations in your tracking plan. Define allowed values for each property so typos ("Mobile", "mobile ", "mob") do not create new values. See data taxonomy and data dictionary.
Counting distinct values: exact vs approximate
"How many unique users?" is a cardinality question. Exact COUNT(DISTINCT user_id) must remember every value it has seen, which is expensive at scale and cannot be added across days: a person active on Monday and Tuesday is one weekly user, not two. That is why weekly and monthly actives are computed over the whole window rather than summed from daily numbers; see DAU, WAU and MAU.
Many analytics databases offer approximate algorithms such as HyperLogLog, which estimate cardinality from a small fixed amount of memory. The typical relative error is about 1.04 ÷ √m, where m is the number of registers: with 16,384 registers that is roughly ±0.8%; with 4,096 it is ±1.6%. For dashboards that is usually fine; for billing or compliance counts, use exact counts.
Relationship cardinality in data models
| Type | Example in analytics data | Watch out for |
|---|---|---|
| One-to-one (1:1) | A user and their profile record | Rare; often merged into one table |
| One-to-many (1:N) | One user has many sessions; one session has many events | Joining events to users repeats user fields on every event row |
| Many-to-many (N:M) | Users and the accounts or workspaces they belong to | Needs a link table; naive joins double-count revenue |
Database query planners also estimate "cardinality" in the sense of how many rows a step will return. Bad estimates lead to slow plans, which is why keeping statistics up to date matters.
In TapCub
TapCub merges page rows by path template in the heatmap list, groups breakdown charts into the top values plus "Other", and in event analysis shows only the more common values when a property has many. Distinct counts (visitors, people, active users) are computed over the selected window rather than summed per day. Under Data › Data quality, the High cardinality tab compares each property’s distinct values over the last 7 days with a threshold, lists keys that are already about halfway there, and lets you mark a property Export only so it stays in raw exports but out of report breakdowns. Tiered decay can also clear high-cardinality columns such as properties and referrer URL on old event rows while trends and funnels keep working. When you design properties, keep report dimensions low-cardinality and put IDs in identity fields. To add your own dimensions for grouping, see custom dimensions.
Sources
- Flajolet, P., Fusy, É., Gandouet, O. and Meunier, F. (2007). HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm.
- PostgreSQL documentation. Statistics used by the planner.
- Wikipedia. Cardinality (data modeling)).
Was this explanation clear?
We use your answers to fix and expand this page.
Couldn’t send. Please try again in a minute.
Thanks for the feedback. We’ll use it to improve this page.You’ve already sent feedback on this page. Thanks.

Technical Engineer
Focuses on tracking code, SDKs, and API integrations, with practical guidance on implementation checks and troubleshooting.