GA4 custom dimensions are how you make your own event parameters and user properties show up in reports. You create them in Admin > Data display > Custom definitions > Create custom dimension, pick a scope (event, user or item), and type the exact parameter name you already send. GA4 starts populating the dimension from that moment on, never backwards.

That last part catches almost everyone. So does the limit. A standard property gets 50 event-scoped, 25 user-scoped and 10 item-scoped custom dimensions, and I've seen properties burn half of that on parameters nobody ever opened in a report.

Key Takeaways
  • Sending a parameter isn't enough: until you register it as a custom dimension, it lives only in DebugView and BigQuery, never in reports.
  • Standard properties get 50 event-scoped, 25 user-scoped and 10 item-scoped custom dimensions (GA4 360: 125, 100 and 25).
  • Custom dimensions aren't retroactive, so register them the same day the parameter goes live or lose the history.
  • High-cardinality values like IDs, timestamps and full URLs push data into "(other)" and waste a slot, and the parameter name must match the GTM tag exactly, case included.

What a custom dimension actually is

Here's the mental model I use with clients. GA4 collects events. Each event can carry parameters, small key-value pairs like form_name: "contact" or plan_type: "pro".

GA4 stores all of them. It just won't show them in the interface until you say which ones matter.

A custom dimension is that instruction. It says: take the parameter plan_type, call it "Plan type", and make it available as a dimension in standard reports and Explorations.

No registration, no dimension. The parameter still arrives. You'll see it in DebugView, and if you have the BigQuery export switched on, it's sitting in event_params for every event. But in the reporting UI, it's invisible.

This is the most common "GA4 is broken" ticket I get from teams who built a nice data layer. The data layer is fine. The GTM tag is fine. Nobody registered the dimension.

I covered the data layer side in the GA4 data layer and GTM guide, so here I'll stay on the GA4 side of the fence.

The three scopes, side by side

Scope decides what the value gets attached to. Pick the wrong one and the numbers look plausible but answer a different question than the one you asked.

Scope Attached to Source in your tag Standard limit Typical example Watch out for
Event The single event that carried the parameter Event parameter 50 form_name, cta_location, article_category Value only exists on events that sent it; everything else shows "(not set)"
User The user, applied to their activity after it's set User property 25 customer_tier, account_type, logged_in User property values are capped at 36 characters
Item One product inside the items array Custom key inside an item object 10 item_material, item_season, stock_status Only meaningful with ecommerce events and item metrics

There's no session scope. If you're coming from Universal Analytics, that's the one that hurts. The usual workaround is an event-scoped dimension sent on every event of the session, or deriving the session view later in BigQuery.

Quick rule of thumb. If the value describes what happened, it's event scope. If it describes who the person is, it's user scope. If it describes the product, it's item scope.

How to create a GA4 custom dimension, step by step

Assuming the parameter is already being sent (more on that below), the setup in GA4 takes about two minutes.

  1. Open Admin, and in the property column go to Data display > Custom definitions.

  2. Stay on the Custom dimensions tab (the other tabs hold custom metrics and calculated metrics) and click Create custom dimension.

  3. Dimension name: the label people will see in reports. Write it for humans: "Form name", not form_name_v2_final.

  4. Scope: Event, User or Item. You can't change scope later. Think first.

  5. Description: optional, and the field everyone skips. Write where the value comes from ("set by GTM tag GA4 - form_submit, from DLV form_name"). The next person who audits the property will thank you.

  6. Event parameter (or User property): type the parameter name exactly as it's sent. If GA4 has already received it, the dropdown suggests it. If it hasn't, you can still type it by hand.

  7. Click Save.

You need the Editor role on the property to do this. Viewers and Analysts see the list but can't create anything.

Then you wait. New custom dimensions usually take 24 to 48 hours before they show up with data in standard reports. DebugView doesn't care about registration at all, which is why it's the right place to check that the parameter arrives at all.

Two clients, two very different mistakes

Łukasz runs a SaaS onboarding team in Gdańsk. In March his developers shipped a clean sign_up event with a plan_type parameter: free, starter or pro. Beautiful work. Nobody registered plan_type in GA4 until mid-May, when the CEO asked for a breakdown of signups by plan for the board deck.

Seven weeks of signups, 2,140 of them, sat in GA4 with no plan attached in any report. Registering the dimension in May filled in May onwards. March and April stayed blank.

The only way back was BigQuery, and the export had been switched on in April. So March was gone. For good.

Dorota had the opposite problem. Her ecommerce team registered everything. Forty-one event-scoped custom dimensions, including transaction_id, session_timestamp, click_text and a full page_url with query strings. When marketing asked for a new dimension for a campaign test, there were nine slots left and the property was littered with "(other)" rows.

I archived 17 dimensions in one afternoon, after checking report usage for each one. Most had zero report usage in the previous six months. The ones carrying unique IDs moved to BigQuery, where they belong.

Neither of them did anything exotic. One registered too late, the other registered too much.

Limits, delays and the "(other)" row

The numbers matter here, so here they are in one place for a standard (free) GA4 property.

  • 50 event-scoped, 25 user-scoped and 10 item-scoped custom dimensions, and in my experience the event-scoped pool is always the first one people run out of.
  • 50 custom metrics. Separate quota.
  • Event parameter names: up to 40 characters. Event parameter values: up to 100 characters, and anything longer is truncated without a warning in the interface.
  • User property names: up to 24 characters. Values: 36.
  • Up to 25 parameters per event.

GA4 360 raises the custom dimension limits to 125 event-scoped, 100 user-scoped and 25 item-scoped. If you're on the free tier and running out, that's rarely a reason to buy 360. It's usually a sign that half your dimensions shouldn't exist.

Archiving frees the slot. In Custom definitions, open the three-dot menu on a row and choose Archive. The Quota information link at the top right shows how many slots you've used.

Two catches. The archived dimension's history stops being available in reports, so archive the useless ones, not the ones someone still reads quarterly. And if you were already at the limit, Google's help center says to expect a 48-hour wait before you can add new ones. Clean up before you need the slot, not the morning a campaign launches.

Now the "(other)" row. Google calls a dimension high cardinality when it has more than 500 unique values in a single day. Those dimensions are a common reason standard reports hit their row limits and start lumping the tail into "(other)".

The report total is still right. The breakdown you wanted is gone.

Things that are almost always high cardinality:

  • Anything that's an ID: transaction_id, user_id, session_id, client_id.
  • Timestamps.
  • Full URLs with query strings, or search terms people type.
  • Free-text form fields. (Also a privacy problem. Don't send these.)

When NOT to create a custom dimension

I'll be blunt: most properties I audit would be better with fewer custom dimensions, not more. Before you spend a slot, check these.

GA4 already has it. Plenty of parameters map to predefined dimensions on their own. Enhanced measurement already gives you Link URL, File name and Video title, and ecommerce parameters such as item_name, item_category and coupon have their own dimensions too.

Registering them again creates a duplicate. Same data, worse name.

It's a unique identifier. Transaction IDs, order numbers, user IDs. They're perfect for BigQuery joins and terrible as report dimensions. If you need user_id for cross-device stitching, send it as the User-ID field in your Google tag configuration, not as a custom dimension.

Nobody will look at it. If you can't name the report or the question it serves, don't register it. "We might need it someday" is how Dorota ended up with 41.

It's personal data. Email addresses, phone numbers, names. Google's terms prohibit sending PII to GA4, and under GDPR it's your problem, not Google's. It shows up more often than you'd think. Usually it's a form field captured by a careless trigger.

You only need it once. For a one-off investigation, the raw parameter in BigQuery answers the question without using a slot. I'd rather spend 20 minutes on a query than permanently spend one of 50.

Sending the parameter from GTM

The custom dimension only works if the parameter actually arrives. In Google Tag Manager, that happens in the GA4 Event tag (tag type Google Analytics: GA4 Event).

For an event-scoped dimension, add it under Event Parameters. Parameter name on the left, value on the right, usually a Data Layer Variable:

window.dataLayer = window.dataLayer || [];
        window.dataLayer.push({
          event: 'form_submit_custom',
          form_name: 'contact',
          form_location: 'footer'
        });
        

In the tag: parameter form_name with value {{DLV - form_name}}, parameter form_location with value {{DLV - form_location}}. In GA4: two event-scoped custom dimensions with the event parameter fields set to form_name and form_location.

For a user-scoped dimension, use the User Properties section of the same tag, or set it once in your Google tag configuration so every event carries it. Values like customer_tier: "gold" fit there.

For item-scoped dimensions, the custom key goes inside each object in the items array of your ecommerce push, next to item_id and item_name. Something like item_material: "merino", and then you register item_material as an item-scoped dimension in the same Custom definitions screen.

One trap worth repeating. Form_Name, form_name and formName are three different parameters. GA4 is case-sensitive and won't warn you. The registration silently waits for a parameter that never comes, and the dimension shows "(not set)" forever.

Naming that survives the next audit

A few conventions I use on every property, because they make audits ten times faster.

  • snake_case for parameters, always: form_name, cta_location, plan_type. It matches Google's own recommended events.
  • Human labels for dimension names: "Form name", "CTA location", "Plan type".
  • No version suffixes. Ever. If form_name_v2 exists, someone will eventually send form_name_v3, and now you have three half-populated dimensions.
  • Use the description field to record which GTM tag sends the value. It's free documentation and it lives where people actually look.
  • One parameter, one meaning. Don't reuse label for button text on one event and product category on another. A dimension can only mean one thing in a report.

Once the dimensions exist and have data, you can build them into custom GA4 reports or break them down in Explorations. That's where the work pays off.

Frequently asked questions

Are GA4 custom dimensions retroactive? No. A custom dimension only fills in data from the moment you create it. Events collected before that keep the parameter in BigQuery (if the export was on), but reports and Explorations will never show it for older dates.

How many custom dimensions can I have in GA4? A standard property allows 50 event-scoped, 25 user-scoped and 10 item-scoped custom dimensions, plus 50 custom metrics. GA4 360 raises the dimension limits to 125, 100 and 25. Archiving a dimension frees its slot.

Why does my new custom dimension show no data? Usually one of three things: it's been less than 24 to 48 hours, the parameter name doesn't match exactly (case matters), or the parameter isn't being sent at all. Check DebugView first. If the parameter isn't there, the problem is in GTM, not in GA4.

What's the difference between an event-scoped and a user-scoped custom dimension? Event-scoped values describe a single event, like which form was submitted. User-scoped values describe the person and apply to their later activity, like their customer tier. Use event scope for actions and user scope for attributes of the user.

Why do I see "(other)" in reports with my custom dimension? The report has hit its row limits, and high-cardinality dimensions are the usual cause. Google treats more than 500 unique values per day as high cardinality. Remove IDs, timestamps and raw URLs from custom dimensions, or move that analysis to BigQuery.

Can I change a custom dimension's scope after creating it? No. Scope is locked once you save. You'd have to archive the dimension and create a new one with the right scope, and the new one starts collecting from zero.

Next steps

Open Admin > Data display > Custom definitions right now and read the list. For every row, ask one question: which report uses this? If nobody can answer, it's a candidate for archiving.

Then do the reverse check. Open DebugView, trigger your key events and look at the parameters arriving. Anything you'd actually want to segment by that isn't registered yet is data you're losing every day. Register it today, because tomorrow it's a day late.

If you'd rather have someone check the GTM side, tags, parameters and whether they match what GA4 expects, the free GTM audit does exactly that. And if you want this kind of drift caught every month, that's what the GA4 monitoring retainer is for.


Sources and further reading - Custom dimensions and metrics (Google Analytics Help) - Configuration limits in GA4 (Google Analytics Help) - Event collection limits (Google Analytics Help) - Set up events with Google Tag Manager (Google for Developers)

Are your event parameters actually reaching GA4 reports?

The free GTM audit checks your GA4 event tags, the parameters they send and whether anything is firing into a void. You get a written list of what to fix.

Start Free GTM Audit
Piotr Litwa

Piotr Litwa

GTM & Analytics Specialist

Piotr monitors GTM containers and GA4 properties for businesses across Europe, catching tracking issues before they cost you conversions. 120+ clients, 10+ years, zero outsourcing.