GA4 Custom Dimensions: Scopes, Setup and Missing Values

GA4 custom dimensions make selected custom event parameters, user properties and item attributes available for analysis. Choose the scope that matches the fact, send the value, register the exact field and validate fresh data after processing. Registration does not create a value that tracking omitted. Treat it as a reporting setup step, not a way to backfill an earlier measurement gap.

Jafrin Akter AloLast updated 15 min read
On this page
A white rotary index holds blank lime cards with a pink front divider beside GA4 Dimensions Pick the Scope.

What is a custom dimension, and which scope should you choose?

A custom dimension is a descriptive field you register for reporting. Its scope determines whether the field describes an event, a user or an ecommerce item. A custom metric instead measures a numerical quantity, such as the number of rows exported. Custom dimensions and metrics

What is a custom dimension, and which scope should you choose?
ScopeIllustrative fieldMeaning to preserve
Eventexport_format=csvThe format of this particular successful export
Userlearning_track=technicalA person-level learning preference
Itemprint_finish=matteThe finish of this particular item in an ecommerce event

These are example custom fields, not built-in GA4 dimensions. Use a predefined dimension when it already answers the question. A second custom definition for a transaction ID or standard page dimension consumes a slot without improving the underlying measurement. Definition guidance

GA4's custom-definition scopes are Event, User and Item. There is no custom Session scope in that schema. A value you send on a session's first event does not automatically become a session-wide custom dimension. CustomDimension resource

Keep historical event context separate from current user state. If someone exports a report from a Team workspace and later moves to Enterprise, plan_at_export=team should still describe that export. Sending the workspace plan as a user property is also ambiguous when one person belongs to several workspaces.

The GA4 implementation service can scope the collection, definitions and report checks together. The useful deliverable is a trustworthy breakdown of a defined outcome, rather than a longer list of fields.

What should you name and document before implementation?

Document the question, parameter key, scope, permitted values, expected events and owner in one register. Keep the display name separate from the field that the application sends.

What should you name and document before implementation?
Register entryExampleValidation
Report questionWhich export formats are used after successful completion?Count completed exports, not button clicks
Display nameExport formatReadable label in GA4
Parameter and scopeexport_format, EventExact match to the event payload
Allowed valuescsv, pdfOne spelling and meaning per category
Expected eventreport_exportedThe parameter must exist on this event
Owner and acceptanceAnalytics owner; successful and failed-export testsEvidence links and registration time retained

The Admin API defines a maximum parameter-name length of 40 characters for event scope and 24 for user scope, with letters, numbers and underscores and a leading letter. Its display-name rules are different. The UI instructions permit spaces and underscores in display names but not hyphens. Scope and parameter mapping are immutable after creation. Definition fields, UI field rules

Use the event naming convention and its naming skill to keep the vocabulary and destination mappings consistent. Check vendor-reserved names separately; a short, syntactically valid name is not automatically an allowed custom field.

Keep values categorical where the question is categorical. Google warns that numeric-looking text can be interpreted as a number. An opaque code such as 00123 is a poor category if preserving its exact text is essential. Prefer an approved label such as tier_standard when that represents the business fact honestly. Numeric-looking values

How do you send and register an event-scoped dimension?

Send the parameter on the intended event, then register that exact parameter under Event scope. Creating the definition does not install tracking code or add the field to future requests by itself.

This example assumes an existing Google tag and an application callback that runs once after an export succeeds:

JavaScript
gtag('event', 'report_exported', {
  export_format: 'csv',
  plan_at_export: 'team'
});

Do not install a second Google tag to add these fields. If GTM owns collection, configure the equivalent parameters on its existing GA4 event tag and inspect the final outbound request. Google's parameter guide separates sending parameters from registering them for reporting. Event parameter setup

In the correct GA4 property:

  1. Open Admin > Data display > Custom definitions.
  2. Select Custom dimensions, then Create custom dimension.
  3. Enter Export format as the display name.
  4. Select Event as the scope.
  5. Enter export_format as the event parameter and add a useful description.
  6. Save, then record the definition and its creation time in the register.

You need Editor or Administrator access at the property level. Check the property selector before saving. A definition in a staging property cannot make a production parameter reportable. Event-scoped setup

Generate a fresh controlled success and a failed attempt. The success should contain the chosen category; the failure should not produce report_exported. If a report on plan at export is also required, register plan_at_export separately. Collecting an extra parameter does not oblige you to spend a reporting slot on it.

Marking the event as a GA4 key event is a separate decision about its business importance. It does not repair a missing parameter or register a dimension.

What changes for user-scoped and item-scoped dimensions?

User scope reads a user property; Item scope reads a custom property inside each relevant entry of the ecommerce items array. Moving the same name between those locations changes its meaning and reporting contract.

For learning_track, collect a genuine person-level preference and register User scope with that exact user-property name. Google provides a separate user-property card in Realtime for inspecting collection. User-scoped setup

A current user property is not a reliable substitute for a historical event snapshot. Google's Measurement Protocol guidance says Analytics uses the most recent user-property value and advises timestamping past changes so they do not override newer updates. If the report asks which plan, role or state applied to a particular action, send the relevant action context as event parameters. User-property timestamps

For a stationery shop, two items in one cart might have different finishes. Put print_finish on each item, not once beside the items array. Register it as Item scope only if the predefined item dimensions do not already meet the requirement.

Google's item collection guide allows up to 27 custom item parameters, while registration allows 10 on standard properties or 25 on 360. Item-scoped custom dimensions can be used in Explorations and audiences; Google says they cannot be added to standard reports. Item-scoped setup and limits

Measurement Protocol has a separate transport limit: its sending guide lists a maximum of 10 custom parameters for item data. Check the collection path before applying the 27-parameter figure to a server request. Measurement Protocol sending limits

Test a cart containing one matte item and one gloss item. A report or query should keep those attributes attached to their own items. Repeating the event-level value on both rows would produce a tidy table with the wrong answer.

How many custom dimensions can a property have?

The registration quotas apply per property and differ by scope. They are separate from the number of parameters a collection request can send.

How many custom dimensions can a property have?
Custom dimension scopeStandard propertyAnalytics 360 property
Event50125
User25100
Item1025

Use Quota information in Custom definitions to inspect actual consumption. If the limit has been reached, Google says to allow 48 hours after removing definitions before adding replacements. Custom-definition quotas

Keep a consumer list for each field: reports, Explorations, audiences, dashboards and API jobs. Archive only after those dependencies have a replacement or an agreed retirement. Archiving is irreversible and can invalidate dependent reports and audiences. Archiving behavior

A quota review is a design review. A timestamp, session identifier and one-off diagnostic token can each consume a definition while making reports harder to use. Retain a field because a named decision needs it, not because the payload happens to contain it.

When will a new dimension appear, and what happens to earlier data?

Plan for a prospective reporting window after both collection and registration are correct. Google says event- and user-scoped custom dimensions become available for reports after 24 to 48 hours from when the data was sent and the definition was created. Reporting availability, user-scoped availability

A new registration is not a historical recovery method. Keep the creation time with the test evidence and validate a completed period containing new, correctly collected values. Do not promise that selecting an older date range will populate the new dimension for that earlier period.

For example, suppose the parameter was deployed on Monday but the definition was created on Wednesday. Use fresh Wednesday-or-later collection for the acceptance test, then allow processing. Investigate Monday's values in an existing raw export if they were collected and retained there. Do not replay Monday's business actions as new events to make the report look complete.

There are three different absences to record: the parameter was never sent, it was collected but not available through the needed custom reporting definition, or it exists in a raw dataset that the report does not query. Registering a definition cannot recreate unsent data. Turning on an export later is also not proof that the missing period exists in the warehouse.

Why does a custom dimension show `(not set)`?

First inspect a fresh event that should carry the value, its exact registration and the report's population. (not set) means GA4 lacks information for that dimension in the reported context; it is not one universal implementation error. Google's missing-value guidance

Why does a custom dimension show (not set)?
ObservationCheck nextRepair boundary
Parameter absent from the intended outbound eventApplication state, tag mapping and consent-dependent pathFix collection before changing the definition
Parameter exists, but a similarly named definition is emptyExact spelling, casing and scopeA display label does not rename the payload key
New definition with recent trafficCreation time and the processing intervalUse a completed post-registration test window
Value exists on exports but not page viewsReport event filter and field contractExclude unrelated events from the completeness denominator
Browser values work but server values do notFinal server payload and its nested locationInspect each producer independently
Field is unavailable only in one reporting toolSupported scope, metadata and metric compatibilityChoose a compatible reporting surface

An export_format dimension need not have a value on page_view. Filter the validation report to report_exported before estimating the defect rate. The broader GA4 (not set) guide covers missing acquisition, landing-page and advertising dimensions; the diagnosis skill helps keep collection faults separate from reporting artifacts.

Do not replace every missing value with unknown solely to improve the dashboard. Use that category only when it is a real, documented business state. Otherwise, the default conceals which producer failed to send its required context.

How is `(other)` different from `(not set)`?

(other) groups less common dimension combinations when a reporting table exceeds its row limit. It can appear in reports, Explorations and Data API results. (not set) concerns missing dimension information. Those diagnoses need different remedies. The (other) row

Google describes more than 500 distinct values in one day as high cardinality. That is a warning about report complexity, not a rule that the 501st value is automatically rejected. Multiple dimensions multiply the possible combinations. Cardinality

Keep categories small enough to answer the decision. export_format with csv and pdf is useful; a unique download URL or generated filename for each export usually belongs in a controlled operational log. Avoid personal details, free text and secrets in ordinary custom dimensions.

Inspect the report's data-quality indicator and simplify its dimensions or query scope. A filter can hide the visible (other) row while the underlying limitation still affects the result. If detailed permitted values are needed, inspect an existing raw export rather than assuming a new custom dimension will make every combination visible. Row-limit diagnosis

How do you send custom dimension values with Measurement Protocol?

Send event-scoped values under the event's params object and user-scoped values under top-level user_properties, using a nested value. An item value belongs inside the relevant item. The custom definition still needs the corresponding scope and exact name.

This fictional web-stream payload illustrates an event and a user property together:

JSON
{
  "client_id": "123456789.1234567890",
  "user_properties": {
    "learning_track": {"value": "technical"}
  },
  "events": [
    {
      "name": "report_exported",
      "params": {
        "export_format": "csv",
        "plan_at_export": "team"
      }
    }
  ]
}

Use the real originating web client ID in an authorized implementation. Keep the measurement ID and API secret in the server's endpoint configuration, not in the event properties or browser code. This example makes no session-engagement claim; do not invent engagement time or reuse an unrelated session merely to make a debugging view populate. Measurement Protocol request structure

Measurement Protocol permits 25 user properties per request, with names up to 24 characters and values up to 36. It also has event-parameter limits independent of the registration table. A 360 property's larger definition quota is not permission to ignore the request schema. Measurement Protocol limits

Run protocol validation through /debug/mp/collect with validation_behavior set to ENFORCE_RECOMMENDATIONS, then inspect the returned validation messages. That endpoint does not populate reports and does not validate the API secret. A production collection 2xx is also insufficient proof of processing. Follow the Measurement Protocol guide for identity, timing and controlled test-property delivery. Validation boundary

What can you check safely before sending anything?

Compare a proposed payload with the definition register and the expected category values. The Python helper below performs those local checks only. It does not emulate GA4 processing, user-property persistence, attribution or reporting delays.

Save the helper as check_mapping.py. Each allowed-category list must be nonempty and contain nonblank strings. Requirements describe which fields should be present in this particular request; do not require a persisted SDK user property on every later request just because it was sent once before.

Python
def check_mapping(payload, definitions, requirements):
    registered = set()
    for definition in definitions:
        scope = definition['scope']
        name = definition['parameterName']
        if scope not in {'EVENT', 'USER', 'ITEM'} or not isinstance(name, str) or not name:
            raise ValueError('Invalid definition in the supplied register')
        key = (scope, name)
        if key in registered:
            raise ValueError('Duplicate definition in the supplied register')
        registered.add(key)

    issues = []
    for rule in requirements:
        scope, name = rule['scope'], rule['parameterName']
        if scope not in {'EVENT', 'USER', 'ITEM'}:
            raise ValueError('Unsupported scope in the test contract')
        allowed = rule.get('allowed')
        if (not isinstance(allowed, list) or not allowed
                or any(not isinstance(value, str) or not value.strip() for value in allowed)):
            raise ValueError('Allowed categories must be a nonempty list of nonblank strings')
        if (scope, name) not in registered:
            issues.append(f'{scope}:{name}: definition missing or wrong scope')
        if scope == 'USER':
            raw = payload.get('user_properties', {}).get(name)
            containers = [raw if isinstance(raw, dict) else {}]
            value_key = 'value'
        else:
            events = [event for event in payload.get('events', [])
                      if event.get('name') == rule['event']]
            if not events:
                issues.append(f'{scope}:{name}: expected event missing')
                continue
            containers = []
            for event in events:
                params = event.get('params', {})
                if scope == 'EVENT':
                    containers.append(params)
                else:
                    items = params.get('items', [])
                    if not isinstance(items, list) or not items:
                        issues.append(f'{scope}:{name}: expected items missing')
                    else:
                        containers.extend(items)
            value_key = name
        for index, container in enumerate(containers):
            value = container.get(value_key) if isinstance(container, dict) else None
            if not isinstance(value, str) or not value:
                issues.append(f'{scope}:{name}[{index}]: category missing or not a string')
            elif value not in allowed:
                issues.append(f'{scope}:{name}[{index}]: category outside the contract')
    return issues

With the previous JSON loaded into a Python variable called payload, this is a complete local check for its two reportable example fields:

Python
from check_mapping import check_mapping

definitions = [
    {'scope': 'EVENT', 'parameterName': 'export_format'},
    {'scope': 'USER', 'parameterName': 'learning_track'}
]
requirements = [
    {'scope': 'EVENT', 'parameterName': 'export_format',
     'event': 'report_exported', 'allowed': ['csv', 'pdf']},
    {'scope': 'USER', 'parameterName': 'learning_track',
     'allowed': ['technical', 'business']}
]
issues = check_mapping(payload, definitions, requirements)
assert issues == [], issues

Change export_format to Export_Format, remove the user-property wrapper, or change the registered Event scope to User and repeat the check. Each should fail for a different reason. For Item scope, test two items with different values and remove the value from only one item. The failing item should remain identifiable.

The supplied register is an input to this exercise. Replace it with reviewed actual definitions before using the result as implementation evidence. A local pass checks name, location and allowed categories; vendor-reserved names, complete protocol limits and actual collection still need their own checks.

How do custom parameters appear in BigQuery?

BigQuery stores the collected event data using repeated parameter records rather than creating a separate column for every custom definition. Custom event parameters appear in event_params, user properties in user_properties, and custom item parameters in items.item_params. Their value records preserve typed fields such as string_value and int_value. Export schema

Google explicitly describes using collected parameters in BigQuery without registering them as custom dimensions. That can preserve useful detail without adding high-cardinality fields to GA4's reporting tables. It does not authorize collecting unnecessary sensitive data. Unregistered parameter use

This read-only GoogleSQL example inspects the two event fields on exported success events. Replace the illustrative project, property dataset and completed date range with the intended export:

SQL
SELECT
  event_date,
  event_name,
  (SELECT value.string_value
   FROM UNNEST(event_params)
   WHERE key = 'export_format') AS export_format,
  (SELECT value.string_value
   FROM UNNEST(event_params)
   WHERE key = 'plan_at_export') AS plan_at_export
FROM `example_project.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20261028' AND '20261029'
  AND event_name = 'report_exported';

These scalar subqueries keep one result row per exported event. Do not cross-join event_params, user_properties and all items into one flat query without controlling the resulting row multiplication. Inspect unexpected duplicate keys rather than arbitrarily choosing one value.

Historical analysis depends on what the export actually retained. Check the link's start, selected streams and excluded events before promising recovery. Google's setup guide says data starts flowing after linkage and describes conditions that can leave export gaps. The GA4 BigQuery export guide covers the wider extraction and reconciliation process. Export setup

How do custom dimensions work in the Data API?

Use the registered definition's API name, then check the requested dimensions and metrics together. The display label used in the interface is not the Data API field name.

How do custom dimensions work in the Data API?
ScopeCore Data API nameExample
EventcustomEvent:parameter_namecustomEvent:export_format
UsercustomUser:parameter_namecustomUser:learning_track
ItemcustomItem:parameter_namecustomItem:print_finish

The current Core schema lists all three forms. Old event-scoped definitions registered before October 2020 can have a legacy event-name suffix; use returned metadata rather than constructing that suffix by guesswork. Core API schema

First query GET /v1beta/properties/PROPERTY_ID/metadata on analyticsdata.googleapis.com with the actual property ID. The metadata response includes property-specific custom definitions. If the field is missing, inspect registration and the selected property before repeatedly issuing the same report request. Metadata method

A corresponding runReport body can look like this, after replacing the dates with the validated reporting period:

JSON
{
  "dateRanges": [{"startDate": "2026-10-28", "endDate": "2026-10-29"}],
  "dimensions": [{"name": "customEvent:export_format"}],
  "metrics": [{"name": "eventCount"}],
  "dimensionFilter": {
    "filter": {
      "fieldName": "eventName",
      "stringFilter": {"matchType": "EXACT", "value": "report_exported"}
    }
  }
}

Run checkCompatibility with the same dimensions, metrics and filters for a Core report. Incompatible combinations fail; item-level and event-level measures should not be assumed interchangeable. Compatibility method

Realtime has a different schema: its API lists user-scoped custom dimensions only; event-scoped custom dimensions are explicitly unsupported. A value visible in a UI debugging card does not establish that the same field can be queried through the Realtime API. Realtime API schema

What should pass before the dimension is released?

Accept the dimension only after the intended value survives collection, definition mapping and the chosen reporting surface. Keep each failure attached to its own repair.

How the workflow fits together
Check collection and registration

The fresh-data step continues to reporting compatibility in the next view; these are the same nodes and branches as the full diagnosis.

Repair a missing collected value and retest collection. Register a missing mapping and recheck its exact scope and field before using fresh data after processing.
Validate the reporting surface

This view starts at the shared fresh-data step after collection and definition checks have passed.

Allow processing on fresh data, then check report compatibility. After choosing a different reporting surface or raw export, repeat compatibility validation before comparing expected categories and counts.
Read diagram as text
  • Choose a required category and scope to Correct value collected?.
  • Correct value collected? to Repair the producer and retest: No.
  • Repair the producer and retest to Correct value collected?.
  • Correct value collected? to Exact definition exists?: Yes.
  • Exact definition exists? to Register the correct field and scope: No.
  • Register the correct field and scope to Exact definition exists?.
  • Exact definition exists? to Use fresh data and allow processing: Yes.
  • Use fresh data and allow processing to Report combination supported?.
  • Report combination supported? to Choose a compatible report or raw export: No.
  • Choose a compatible report or raw export to Report combination supported?.
  • Report combination supported? to Compare expected categories and counts: Yes
Open full diagram

After repairing collection or registration, repeat that check. If you change the reporting surface, verify its supported fields before comparing the result.

Checklist

  • A named decision needs the custom field rather than a predefined dimension.
  • Scope, exact key, meaning and allowed values are documented.
  • The field is present on every event or item where the contract requires it.
  • User state and event-time context are not being confused.
  • Successful, failed, missing-value and wrong-case fixtures behave as expected.
  • Registration time and the accepted reporting period are recorded.
  • Quota and cardinality risks have been reviewed.
  • Browser and server producers are checked separately.
  • Reports, API combinations and any raw-export query use the intended scope.
  • A named owner maintains dependencies and approves future changes.

The USD 99 audit includes a written assessment and a one-hour specialist call. For the tagging, custom definitions and report validation, request a detailed GA4 implementation scope.

Keep reading

Browse all Tracking & Attribution guides

Questions people ask

Can one registered parameter describe several event names?

Yes. An event-scoped custom dimension can report the same parameter across multiple events in the property, so you do not need a separate definition for each event. Keep its meaning and categories consistent across producers, and filter each analysis to the relevant event population. Reusing status for unrelated business processes would make the shared definition ambiguous. Property-wide definitions

Does changing the display label rename the field sent by the app?

No. The display label controls how the definition appears to a reader; the underlying parameter mapping is a separate field. Changing a label does not update your tag, server payload or downstream query. Scope and parameter name cannot be changed on an existing definition, so a mapping correction needs a reviewed replacement and dependency update. Definition fields

Does archiving a dimension stop the application from sending it?

No. Archiving changes the reporting definition, while the application or tag remains responsible for collection. Review the sender separately if the field should stop being collected. Before archiving, inspect affected reports, Explorations and audiences and arrange replacements; the definition cannot be restored, and dependent audience membership can stop growing. Archive effects

Should an account's plan be a user-scoped dimension?

Only when that field genuinely describes the person under the agreed identity model. If one person belongs to several workspaces, one current user property cannot describe every workspace at once. Send the relevant workspace's plan on the action when the question concerns that moment, and retain the account relationships in the business dataset used for account-level analysis.

Should unique customer IDs become custom dimensions for debugging?

Avoid turning each customer or session identifier into a registered custom dimension. Unique values create cardinality pressure and are usually poor reporting categories. Use GA4's supported User-ID feature where appropriate, and keep necessary diagnostic references in access-controlled operational records. Neither approach permits placing emails, tokens or other inappropriate personal data into ordinary analytics fields. Identifier guidance

Sources

  1. Google: Custom dimensions and metrics
  2. Google: CustomDimension resource
  3. Google: Create event-scoped custom dimensions
  4. Google: Set up event parameters
  5. Google: Create user-scoped custom dimensions
  6. Google: Send user properties
  7. Google: Create item-scoped custom dimensions
  8. Google: Archive custom dimensions and metrics
  9. Google: What (not set) means
  10. Google: The (other) row
  11. Google: Cardinality
  12. Google: Measurement Protocol reference
  13. Google: Validate Measurement Protocol events
  14. Google: BigQuery export schema
  15. Google: Set up BigQuery export
  16. Google: Core Data API dimensions and metrics
  17. Google: Data API metadata
  18. Google: Data API compatibility
  19. Google: Realtime API schema
  20. Google: Measurement Protocol sending limits
Portrait of Jafrin Akter Alo

Written by

Jafrin Akter Alo

Data Engineer and Co-founder at Martechdevs and Growth and Analytics Partners

Jafrin writes practical guides to marketing technology, customer data, analytics and AI workflows. Martechdevs is a Growth and Analytics Partners company.

View LinkedIn profile

Book a Free Call

Thirty minutes on your stack and what it needs. Free, and no pitch.

Thirty minutes, and you leave with a plan

We look at what you have, what it is costing you and what to do about it first.

  • 30 minutes
  • Video call, link on booking
  • No obligation

What we'll cover

  • Your current stack and where it hurts
  • Quick wins we can ship first
  • An integration roadmap
  • Timeline, scope and next steps

Calendar not loading? Open it in a new tab or email hello@martechdevs.com.