GA4 custom events are events you name and define yourself, for actions GA4 doesn't track out of the box and Google has no recommended event for. Before you create one, check two lists: enhanced measurement (already collecting things like scroll, file_download and form_submit) and Google's recommended events (generate_lead, sign_up, purchase and friends). Only when neither fits do you invent a name.
That order matters more than any naming trick. Most of the messy GA4 properties I audit didn't fail on syntax. They failed because someone invented contact_form_sent when generate_lead already existed, and then a second person invented lead_submit six months later.
- Use a recommended event whenever one fits, because GA4 reports and integrations already expect those names and parameters.
- Event names are case-sensitive, max 40 characters, must start with a letter, and can't use reserved names or the
firebase_,google_andga_prefixes. - Up to 25 parameters per event, each visible in reports only once registered.
- Send events from GTM by default, and keep GA4's "Create event" for small fixes you can't make in the container.
Custom, recommended or automatic: check before you name anything
GA4 has four kinds of events, and only one of them needs your creativity.
| Event type | Who defines it | Examples | Do you need to build it? |
|---|---|---|---|
| Automatically collected | GA4 | first_visit, session_start, user_engagement |
No, they just happen |
| Enhanced measurement | GA4, toggled per data stream | page_view, scroll, click (outbound), file_download, form_start, form_submit, view_search_results, video_start |
No, switch it on in the data stream settings |
| Recommended | Google names it, you send it | generate_lead, sign_up, login, search, purchase, add_to_cart |
Yes, but use Google's exact name and parameters |
| Custom | You | pricing_toggle, calculator_complete, demo_video_cta |
Yes, and you own the naming |
The recommended list is longer than most people think. There are lead-gen events like qualify_lead and close_convert_lead, content events like select_content and share, and the full ecommerce set. If your action is "someone sent a contact form", that's generate_lead. Not contact_form, not lead, not Form Submit.
Why bother? Recommended events come with known parameters (value and currency on generate_lead, method on sign_up) and some reports and integrations expect them. A custom name throws that away for nothing.
Link clicks and YouTube video tracking are their own topic. I wrote up link click tracking with GTM separately, and video gets its own article later in this series.
Naming rules GA4 enforces (and the ones it doesn't)
Some rules are hard limits. Break them and the event is dropped or mangled.
- Up to 40 characters for the event name.
- Starts with a letter. Letters, numbers and underscores only. No spaces, no hyphens.
- Case-sensitive.
Sign_Upandsign_upare two different events in your reports, and GA4 will happily count both forever without telling you anything is off. - Reserved names you can't use, including
session_start,first_visit,user_engagement,first_openanderror. - Reserved prefixes:
firebase_,google_,ga_.
Then there are the rules GA4 doesn't enforce. Those matter more.
Use snake_case, always, because that's what every Google event uses and mixing styles is how duplicates are born. Use an object_action pattern so related events sort together: pricing_toggle, pricing_cta_click, calculator_start, calculator_complete. Keep verbs consistent; don't mix _click, _clicked and _press.
And don't put values in the name. cta_click_header and cta_click_footer should be one event, cta_click, with a cta_location parameter. Otherwise you get 14 events where one would do, and your Events report turns into a wall.
The Grzegorz problem: three names, one action
Grzegorz runs marketing for a B2B software company in Poznań. When I opened his property, the Events report listed Form_Submit with 312 events, form_submit_custom with 118 and formSubmit with 47. All three were the same demo request form.
Three agencies over four years. Each one added its own tag. Nobody deleted the old ones, and two were still firing.
So his "demo requests" key event, which was only Form_Submit, showed 312 for the quarter. The CRM had 389 demo requests. Close enough that nobody questioned it, wrong enough to skew every channel comparison, because the newer tag only ran on the landing pages paid traffic used.
The fix took an afternoon. One event, generate_lead, with a form_name parameter set to demo_request. One GTM tag.
The two dead tags got paused, the duplicate got removed, and the old Form_Submit key event was switched off so nobody would compare it with the new one by accident. Next quarter GA4 showed 402 and the CRM 417, with the gap explained by consent.
The boring lesson: event design is a governance problem first and a technical one second.
Parameters: what to send and what to register
Each event can carry up to 25 parameters. Parameter names follow similar rules to event names: up to 40 characters, and values up to 100 characters on standard properties. Don't use the reserved prefixes there either.
A good parameter answers a question you'll actually ask. For a calculator_complete event that might be calculator_type, result_band and value. For generate_lead it's usually form_name, form_location, plus value and currency if leads have a known worth.
Here's the catch that trips most teams. GA4 accepts and stores every parameter, but it only shows a custom parameter in standard reports and Explorations after you register it as a custom dimension. Event-scoped slots are limited to 50 on a standard property, so pick carefully. I covered the setup, scopes and the 50/25/10 limits in GA4 custom dimensions.
What I wouldn't send as a parameter:
- Anything personal: emails, phone numbers, names. That's against Google's terms, and under GDPR it turns your analytics property into a data protection problem you have to explain to someone.
- Unique IDs you'll never segment by. They belong in BigQuery, not in a report.
- Free text people type. High cardinality, and it often contains personal data anyway.
A small tracking plan that fits on one screen
Every property I set up gets a tracking plan before it gets a single tag. It doesn't need to be a 40-tab spreadsheet. For a typical B2B site, this is roughly the whole thing:
| Event name | Type | Fires when | Key parameters | Key event? | Register as custom dimension |
|---|---|---|---|---|---|
generate_lead |
Recommended | Contact or demo form succeeds (thank-you state, not button click) | form_name, form_location, value, currency |
Yes | form_name, form_location |
sign_up |
Recommended | Account created | method |
Yes | method |
pricing_toggle |
Custom | User switches monthly/annual on pricing page | billing_period |
No | billing_period |
calculator_complete |
Custom | ROI calculator shows a result | calculator_type, result_band |
No | calculator_type, result_band |
cta_click |
Custom | Primary CTA button clicked | cta_location, cta_text |
No | cta_location |
file_download |
Enhanced measurement | PDF or brochure download | built-in file_name, file_extension |
Maybe | None, built in |
Six events. Two key events. Seven custom dimensions. That's enough to answer most questions a marketing director asks, and small enough that someone will actually keep it updated. The day it stops fitting on one screen is the day to ask which rows nobody uses.
Sending from GTM vs "Create event" in GA4
There are two ways to get a custom event into GA4, and they're not interchangeable.
From Google Tag Manager. You build a GA4 Event tag (tag type Google Analytics: GA4 Event), set the event name and parameters, and attach a trigger. Usually that trigger is a Custom Event trigger listening for a dataLayer.push, which I walked through in the GA4 data layer and GTM guide:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'calculator_complete',
calculator_type: 'roi',
result_band: '10k_50k'
});
From the GA4 interface. Go to Admin > Data display > Events > Create event. You define a new event name and matching conditions based on an existing event, for example event_name equals page_view and page_location contains /thank-you. GA4 then creates the new event from matching incoming data.
A property can hold up to 50 created events and 50 modified ones. Plenty for patches, which is all it should be.
I'll be blunt: I use "Create event" as a patch, not a strategy. It isn't retroactive. It lives outside your GTM container, so anyone reading the container won't know it exists. And it inherits every weakness of the source event. Every one.
Beata learned that the hard way. Her team built generate_lead in the GA4 UI from page_view on /thank-you. GA4 reported 1,180 leads in a quarter. The CRM had 860.
Why? People refreshed the thank-you page, bookmarked it, came back to it from email. Every view was a lead.
I moved the event to a GTM tag fired from a dataLayer.push that only happens on a successful form submission. Leads dropped to 874. The CEO wasn't thrilled. The numbers were finally real.
When "Create event" is fine: renaming a legacy event while the GTM fix waits for a release cycle, or splitting one event into a more specific one when you have no container access. Treat it as temporary and write it down.
Marking it as a key event and testing it in DebugView
An event isn't a conversion until you say so. In GA4 go to Admin > Data display > Key events > New key event and type the exact event name, or find the event under Admin > Data display > Events and mark it as a key event there. A standard property allows 30 key events. You won't need more than five.
If you also bid on it in Google Ads, the key event has to be imported there as a conversion. That part trips people up constantly, and the GA4 setup guide covers it.
Then test before you trust anything, because an event that looks right in GTM Preview can still arrive in GA4 with the wrong case, a missing parameter or a duplicate hit. My routine for every new event:
-
Open GTM Preview. Tag Assistant connects and your hits get the debug flag automatically.
-
Trigger the action on the site. In Tag Assistant, confirm the GA4 Event tag fired exactly once, not twice, which is the most common failure when an old hardcoded gtag snippet is still sitting in the page template.
-
Open Admin > Data display > DebugView in GA4. Find your device and click the event.
-
Check every parameter: right name, right case, a sensible value, nothing truncated.
-
Wait 24 to 48 hours and check the Events report. DebugView is real time; standard reports aren't.
If an event shows in DebugView but never in reports, it's usually filtered by an internal traffic or developer traffic filter, or you're looking at the wrong date. The DebugView testing guide goes through the failure modes one by one.
Frequently asked questions
What is a custom event in GA4? A custom event is an event you name and define yourself for an action GA4 doesn't collect automatically and Google has no recommended event for. You usually send it from Google Tag Manager with your own parameters. Check enhanced measurement and the recommended events list first.
What are the naming rules for GA4 events?
Event names can be up to 40 characters, must start with a letter, and may contain only letters, numbers and underscores. They're case-sensitive. You can't use reserved names like session_start or the firebase_, google_ and ga_ prefixes.
How many parameters can a GA4 event have? Up to 25 parameters per event. Parameter values are limited to 100 characters on standard properties. Custom parameters only show in reports after you register them as custom dimensions.
Should I use GTM or "Create event" in GA4? Use GTM by default, because the logic lives in one place you can version and audit. "Create event" in the GA4 interface works for quick fixes and renames, but it isn't retroactive and it's easy to forget it exists.
How do I make a custom event a key event? Go to Admin > Data display > Key events, click New key event and enter the exact event name, or mark it from the Events list. A standard property allows up to 30 key events. Import it into Google Ads separately if you want to bid on it.
Why doesn't my custom event appear in GA4 reports? Standard reports usually take 24 to 48 hours to show new events, so check DebugView first. If it shows in DebugView but not in reports, look for data filters (developer traffic filters exclude debug hits by design) or a case mismatch in the name. Not in DebugView at all? Then it's your GTM tag or trigger.
Next steps
Open Reports > Engagement > Events and sort by event name. Look for near-duplicates: same action, different case, different suffix. Every pair you find is a number someone is reading wrong.
Then write the one-screen tracking plan before you add anything new. Six rows is fine. The plan is what stops the next agency from inventing a fourth name for your demo form.
If you'd like a second pair of eyes on the container itself, the free GTM audit lists every GA4 event tag, the names it sends and the duplicates. And if you want that drift caught before it reaches a board deck, that's what the GA4 monitoring retainer is for.
Sources and further reading - Recommended events (Google Analytics Help) - Event collection limits (Google Analytics Help) - Rename and generate new events (Google Analytics Help) - Set up events (Google for Developers)
Do your GA4 events match what your GTM container actually sends?
The free GTM audit lists every GA4 event tag in your container, flags naming collisions and parameters that never reach a report, and tells you what to fix first.
Start Free GTM Audit