Produces three things: naming rules with a controlled vocabulary (martech-context/naming-rules.md), a linted event and property list with the final name each destination receives, and, when a live name must change, a rename plan that keeps history readable and counts each action once.
When to use
Use this skill when:
- New events need names, or a developer's proposed list needs review before release.
- A team needs naming rules, an event taxonomy or an event dictionary, or wants existing events cleaned up.
- Observed data shows one action under several names (
Sign Up,sign_up,signUp) or one name meaning two moments. - One plan feeds GA4 plus Mixpanel, Amplitude, PostHog or a CDP, and names must survive every destination, tag and connector.
- An event or property must be renamed, merged or retired without breaking trends, funnels or key events.
Use something else when:
- The trigger, identifiers, typed contract and acceptance tests of an event are the question: use the tracking-plan-builder skill. This skill names; that skill specifies.
- Campaign or UTM values: utm-convention-and-registry. Ad platform object names: campaign-naming-convention.
- Choosing which outcomes become GA4 key events or Ads conversions: conversion-goals-and-key-events.
- Moving history from one analytics tool to another: analytics-migration.
- Auditing a GTM container beyond its event names: gtm-container-audit.
- Writing SDK code or editing a vendor's tracking plan: hand off to the vendor's own skill or MCP server (see Boundaries).
If a skill named here is not installed, stop at that decision and hand it to the user with the evidence gathered.
Inputs
Read these first if they exist, before asking anything:
martech-context/naming-rules.md: existing conventions and vocabulary. Extend it; never start a second one.martech-context/stack.md: every destination, CDP, tag manager and connector in the path, and every field that rewrites names (such as the Lowercase Event Name field on each Segment GA4 Custom Event mapping).martech-context/tracking-plan/anddata-dictionary.md: existing events and properties, so a new name does not duplicate one.martech-context/decisions.md: earlier naming exceptions.
Then gather what is missing:
- The raw names as emitted or observed, unedited: code, a GA4 events report, Mixpanel Lexicon or Amplitude Data export, or a warehouse
event_namelist with producer and app version. - For GA4 on web: a GTM container export, or a read-only list of GA4 Event tags with their Event Name and triggers (web and server containers). The name GA4 receives is usually set there.
- For each name: who emits it (browser, server, iOS, Android, CDP route, GTM tag) and the moment it fires.
- Property names with types, from a sample payload of a test account.
- For a rename: the consumers of the old name and the release dates or app versions available.
Never ask for, print or store credentials or customer records. Sample payloads come from test accounts or are redacted first.
Procedure
1. Decide whether to change the convention at all
- Keep the existing taxonomy when at least 95% of distinct names, or of event volume, already follow one pattern (house default; agree it with the data owner). Map it per destination, fix the rest as individual renames, and lint the final names. Do not migrate a working Title Case or camelCase taxonomy only for style.
- Below that, or with no convention, adopt the default below and write it down.
- Default for a new multi-tool implementation: lowercase ASCII snake_case,
<object>_<past-tense action>, 40 characters at most, starting with a letter. It passes GA4 unchanged and fits Mixpanel's and Amplitude's object-verb guidance. Title Case becomes the display label. Vendor styles (Title Case with spaces, PostHog's colon) are compared in references/platform-constraints.md.
2. Write the vocabulary before naming anything
- Objects: singular nouns from the product's domain (
workspace,report_export,member_invitation), each with a one-line definition. Two words only when one is ambiguous. - Actions: past-tense verbs for completed facts, each with a definition. Start from assets/actions.txt; see assets/example-acme-objects.txt for an object list.
- One term per concept. List forbidden synonyms (
removedwhendeletedis chosen,cancelledwhencanceledis chosen) so they are not re-added. - Fill assets/naming-rules-template.md as the proposed
naming-rules.md. For the lint script, copy each vocabulary section's backticked terms into temporaryobjects.txtandactions.txtfiles outsidemartech-context/, one per line, plus aforbidden: removed=deleted, ...line.
3. Name each event from the fact it records
- Name the committed state change, not the gesture. The click is
report_export_requestedat most;report_export_succeededis the outcome. - Split
_requested,_succeededand_failedonly when the distinction drives a decision; join them with a job or attempt ID property. Otherwise one event. - Variants are properties:
report_export_succeededwithexport_format: pdf, not one event per format. Same for plans, steps, locations, versions, dates, locale, interaction method (a shortcut and a button share one event) and actor (actor_typekeeps admin actions out of customer activation). - Names come from the vocabulary, never from UI copy or a translated label. One counting unit per name: a batch job and the files it produces are two events.
- No destination, environment or release words in names (
ga_,test,new,v2). - A name already used by another producer for a different moment is a defect, not a naming choice. Ask each producer when it fires.
- Map to a GA4 recommended event (
sign_up,purchase,generate_lead) only when the trigger matches Google's meaning and the required parameters exist (purchaseneedstransaction_idanditems;currencywhenevervalueis set). Keep the business name as canonical and record the GA4 name as a destination mapping.
4. Name and type the properties
Rules, context properties and per-tool reserved names: references/property-naming.md. The ones that break reports most often:
- One property name, one type and one meaning across all events and producers.
- Suffixes carry meaning:
_id(string),_at(UTC timestamp),is_orhas_(boolean), units for durations and sizes, money as amount plus ISO 4217currency. - Enumerated values are listed lowercase codes with an explicit unknown policy; unknown is never silently mapped to a real value.
- Event-time copies of profile traits get explicit names (
plan_at_activation). Mixpanel joins the latest profile value onto past events; Amplitude records user properties at event time. - A parameter name valid in GA4 can still be reserved elsewhere (
bucket,time,distinct_idin Mixpanel;revenue,value,currencyin Segment).
5. Map each destination and record the final names
- For each canonical event, record the name each destination actually receives after every tag, connector and transformation (GTM web and server containers, Segment mappings, Protocols transformations).
- GTM: record the dataLayer event and the GA4 Event Name as separate columns (the script ignores extra columns) and lint the Event Name values from the container. An Event Name of
{{Event}}forwards raw dataLayer names. - Segment's GA4 Cloud destination sends through the Measurement Protocol. Its Custom Event action replaces spaces with underscores and lowercases only where that mapping's Lowercase Event Name field is true.
- Route an event only to destinations with a named use.
- Write the mapping as a CSV (
canonical_name,destination,destination_name); example: assets/example-acme-mapping.csv.
6. Lint
Run the rule set over the raw list, the property list and the mapping. Call the script by the absolute path of this skill's scripts/ folder, with the vocabulary files from step 2. Rules, severities and output format: references/linter-rules.md.
python3 <skill folder>/scripts/lint_event_names.py names.txt --objects objects.txt --actions actions.txt
python3 <skill folder>/scripts/lint_event_names.py properties.txt --kind property
python3 <skill folder>/scripts/lint_event_names.py mapping.csv --kind mapping --objects objects.txt --actions actions.txt
- The script needs only Python 3 and changes nothing; its reserved lists are dated. If it cannot run, apply the rules by reading the list and count characters with code.
- Then apply the manual rules R01 to R07 (wrong fact, two meanings, intent, variants, synonyms, personal data, style-only migrations).
- Optional GA4 check: send each GA4 destination event with its mapped parameters to the Measurement Protocol validation server (
/debug/mp/collect, which collects nothing) with placeholder IDs. Pass: emptyvalidationMessages. Details in the platform reference. - Approval rule: zero unresolved errors; every warning fixed or given a one-line reason in the registry.
7. Review
Walk references/review-checklist.md with the person who knows where success is committed in code and the person who owns the decision the event serves. Confirm one received test payload per destination before approval: DebugView for gtag.js, GTM and Firebase; the validation server, then Realtime or BigQuery, for Measurement Protocol senders such as Segment GA4 Cloud.
8. Rename or merge live names safely
Classify first: label only, raw rename with the same meaning, duplicates, semantic change, or retirement. Per-platform procedures: references/renames-and-migrations.md.
- Label only: a display name in Mixpanel Lexicon or Amplitude Data (UI only).
- Raw rename or duplicates: inventory consumers, add the new name to every blocking schema first, switch each producer at a recorded boundary (deploy time, GTM version publish time, app version), then pick the history method with the overlap test.
- Overlap test, before any Mixpanel merge, Amplitude transformation, PostHog action or warehouse union (each adds the two series for all history). Evidence: one recent full week of daily
count(old),count(new)and their sum against the source-of-truth table, plus an entity-ID join.- Disjoint (house default: the sum within 2% of the source of truth every day, no entity ID under both names): merge.
- Overlapping, and the authoritative series has always fired (a backend event): keep it, repoint reports, then hide the duplicate or label it "(duplicate, retired)". Never merge.
- Overlapping, and the new series starts at the boundary: date split; exclude old-version traffic after the boundary.
- GA4 never rewrites history: report old before the boundary and new after. Copy key-event status, counting method and default value to the new name before release. Change a GTM-set name in a new container version and a Segment GA4 Cloud name in its mapping; Modify event is a client-side bridge that never applies to Measurement Protocol traffic. Never use Create event to rename.
- Default is no dual emission. If a consumer forces it, route the legacy copy only to that consumer, set an end date and give each copy its own vendor dedupe key (details in the reference). GA4 deduplicates only
purchasewith the sametransaction_idon web streams; never send an emptytransaction_id. - Semantic change: a new name and an annotated break, never the old name with a new meaning.
9. Propose the files
Show the user the proposed changes and wait for approval before writing:
martech-context/naming-rules.md(rules and vocabulary)- registry or tracking-plan entries with display names, destination names, producers and lint exceptions (example: assets/example-acme-registry.yaml)
decisions.mdentries for exceptions and convention changes- for a rename: the rename plan from the renames reference, with the overlap result
Common failure modes
- Case and separator variants of one action (
Report Created,report_created,reportExported). Detect: N17 on the observed list; one action split across events in each tool. - One name, two moments (click on web, committed record on backend). Detect: the event to source-of-truth ratio above 1.05 for 7 days (house default); volume split by producer.
- Values or UI copy in names (
plan_selected_pro,onboarding_step_3_completed, a translated label). Detect: N13 and N11; distinct names growing with the catalogue; one object under several labels after a copy or language change. - GTM passthrough: a GA4 Event tag whose Event Name is
{{Event}}or a lookup table sends dataLayer names into GA4, and renaming a dataLayer event silently stops its Custom Event trigger. Detect: a variable in an Event Name field of the export; unplanned camelCase names in GA4; zero volume after a dataLayer change. - Default or autocaptured events duplicating a custom one (GA4 enhanced measurement
form_submitbesideform_submitted). Detect: each destination's enabled default events listed beside custom events with the same meaning; keep one, recorded indecisions.md. - GA4 silent drops and reserved names: names or parameter names over 40 characters, the 26th parameter,
page_viewreused for a product event,Purchase,ga_,firebase_,$. Detect: N04, N08, N09, M09, M10; the name or parameter missing in GA4. - Display name masking a bad raw name. Detect: Mixpanel Data Standards shows compliant while raw names fail the lint.
- Rename that dropped the event, doubled counts or froze charts. Detect: zero volume for the new name under a plan that drops unplanned events (Amplitude, Segment, RudderStack); a merge, action or metric over names that failed the overlap test; saved charts still filtered on the old raw name after cutover.
Worked example
Acme Reports (fictional) sends events from a web app (Google tag, Segment with GA4 Cloud), an iOS app and a backend to Mixpanel and GA4. Full review: assets/example-acme-review.md; the raw list assets/example-acme-events-input.txt gives 8 errors and 10 warnings. Points worth copying:
Sign Up(click),signup_completed(iOS screen load) anduser_registered(backend commit) were three names for two moments. The overlap test showedsignup_completedduplicatesuser_registered, which has always fired, so iOS stops sending it and it is hidden, never merged.Report Created(web) overlappedreport_created(backend) the same way.report_exported_pdfandreportExportedbecomereport_export_succeededwithexport_format, read by date split.subscription_cancelled(button) andsubscription_canceled(webhook) were two facts, not a spelling clash.- The new mapping lints with zero errors and two warnings, each with a reason; the key-event question goes to the conversion owner.
Acceptance checks
- Naming rules:
naming-rules.mdstates the pattern, length budget, spelling, object and action vocabularies with definitions, forbidden synonyms and the change process. Pass: no template placeholder remains, and the vocabulary files used for linting list exactly the same terms. - Lint: the raw list, property list and mapping were linted. Pass: zero unresolved errors; every warning has a fix or a one-line reason in the registry.
- Reserved lists: the GA4 reserved names page and the destinations' limits were fetched on the day of approval. Pass: URL and date recorded; no difference from the script's lists, or the script lists were updated.
- Destinations: every canonical event has the final received name per destination, including GTM Event Name values. Pass: no M-rule errors; one received test payload per destination matches the planned name and property types.
- Meaning: every event has one producer moment and a counting unit. Pass: no name is emitted by two producers at different moments.
- Renames: each has a classification, consumer inventory with owners, boundary per producer and per-tool history plan. Pass: the rename plan is complete and approved, no metric counts both names, and every merged pair has a disjoint overlap result with its evidence.
- Approval: the user approved the files before they were written. Pass: nothing in
martech-context/or any vendor tool changed without approval.
Boundaries
- This skill proposes names, rules, mappings and rename plans. It does not change code, tags, GTM containers, Lexicon, Amplitude Data, GA4 admin settings or CDP transformations. Every live change is a draft change list that stops for human approval.
- Display-name edits, merges, blocks, deletes and transformations change shared configuration for every user; data sent while a Mixpanel or Amplitude block is active is never stored.
- Hand-offs, with read-only modes where they exist (tool lists in the platform reference):
- GA4: Google's GA4 MCP server (Experimental,
analytics.readonlyscope) for event names and custom dimensions. Modify event, key events and custom definitions are changed in the GA4 interface by a person with the required role. - GTM: the gtm-container-audit skill, or the Tag Manager API with the
tagmanager.readonlyscope. Changes go into a workspace for a person to publish. - Mixpanel: MCP read tools
Get-Events,List-Properties; write tools only from an approved change list (no read-only mode is documented). Mixpanel'smanage-lexiconskill cleans Lexicon metadata. - Amplitude: MCP with a read role (
get_amp_taxonomy,get_transformations); taxonomy changes on a branch. Itstaxonomyandtracking-plan-auditskills audit naming. - PostHog: MCP in read-only mode (
x-posthog-read-only: true). - Segment: Twilio's MCP only searches docs; transformations and GA4 Cloud mappings are changed in the Segment app by a workspace owner or source admin.
- GA4: Google's GA4 MCP server (Experimental,
Live docs
Platform settings, limits and menu paths change. Before stating any parameter name, limit, quota or UI path:
- Fetch the current page from the vendor docs MCP server or llms.txt listed in
sources.yaml, or open the canonical URL. - If the live page disagrees with this skill, follow the live page and tell the user what changed.
- Cite the URL you used.
Most used: the GA4 naming, limits, modify event, key events and validation pages; GTM event tag, trigger and versions; Mixpanel Lexicon and Data Standards; Amplitude transformations and data settings; PostHog best practices and capture events; Segment's GA4 destination and transformations. Every limit here was checked on 2026-10-17. Verify at run time: whether GTM Custom Event triggers match case sensitively, whether the validation server accepts a placeholder measurement_id, and whether Create event applies to Measurement Protocol traffic.