martechdevs has been acquired by Growth and Analytics Partners LLC

Tracking plans and naming

Campaign naming convention

Defines and enforces names for paid campaigns, ad groups, asset groups, ad sets and ads in Google Ads, Performance Max, Meta (Facebook and Instagram) and LinkedIn. One token order and delimiter, fixed vocabularies with a retire-and-alias lifecycle, a YYYYMM launch month and length limits checked per platform. Builds a registry that generates each name from its token columns, a dependency-free lint script, a warehouse parse model that joins on normalised platform IDs, a rename procedure and a weekly exception report ranked by spend.

FreeVersion 0.2.0Reviewed 17 October 2026

Gives every paid campaign, ad group or ad set, and ad a name that people can scan and a parser can split. The output is a rules file, a vocabulary file, a registry, a lint report per launch, a warehouse parse model and a weekly exception report, all proposed for approval.

The rule everything else depends on: the platform object ID is the join key, and the name is a changeable attribute. Never join spend, sessions or CRM records on a name.

When to use

Use this skill when:

  • A Google Ads, Meta or LinkedIn account is being set up and names need a standard before the first launch.
  • Names are inconsistent and a cross-channel spend report cannot group by market, objective, funnel stage or offer.
  • An analyst needs names parsed into reporting columns in BigQuery, Snowflake or dbt.
  • Live campaigns need renaming, or someone asks how to keep naming consistent across people and agencies.
  • A launch wave needs its names checked before build.

Use something else when:

  • Source, medium, non-paid UTM values, the UTM registry and the platform campaign map: utm-convention-and-registry. By its contract, this skill owns only the paid templates for utm_campaign, utm_id and utm_content (step 4).
  • GA4 shows Unassigned, (not set) or literal macro text: ga4-unassigned-not-set-diagnosis.
  • Event names: event-naming-convention.
  • Applying an approved rename or any write through an API or MCP tool: agent-write-safety first.
  • Deciding account structure: b2b-search-campaign-structure if installed; otherwise take the structure from the account owner. This skill names a structure; it does not choose it.
  • Google Ads Editor import files for approved changes: google-ads-editor-import-builder if installed; otherwise hand over the rename change list for manual entry.
  • Rollout and training across teams, or a bulk audit of tagged URLs: utm-governance-and-adoption or utm-link-audit if installed; otherwise the governance loop in references/governance.md and utm-convention-and-registry's link tests.

Inputs

Read these first if they exist (marketing-context-kit creates the folder):

  • martech-context/naming-rules.md and the rules and vocabulary files it points to.
  • martech-context/stack.md: platforms, account IDs, spend connectors, warehouse, owners.
  • martech-context/metrics.md: which reports group spend, and by what.
  • martech-context/data-dictionary.md: existing campaign dimension columns.
  • martech-context/decisions.md: earlier naming or UTM decisions and cutover dates.
  • The UTM registry from utm-convention-and-registry, for initiative names and IDs.

Then gather:

  • Platforms, accounts and object types in use. Performance Max, Demand Gen and LinkedIn Conversation Ads change what can be named or tagged.
  • The cuts people use in spend reports, each tied to a decision someone makes.
  • A read-only export of current names with IDs, parent IDs, status, start date and 90 days of spend in one currency.
  • How spend reaches the warehouse (BigQuery Data Transfer, a connector), the ID format each source uses, and since when daily snapshots exist.

Never ask for, print or store tokens, passwords or customer data. Exports need IDs, names, status, dates and spend only.

Procedure

1. Inventory current names, read-only

  • Google Ads: Google's read-only MCP server, tools list_accessible_customers, search (GAQL), get_resource_metadata, namespaced (search_search) over OAuth. Query campaign, ad_group, asset_group and ad_group_ad; queries in references/platform-reference.md.
  • Meta: Meta's Ads MCP server. Call only ads_get_ad_accounts, ads_get_ad_entities, ads_get_field_context, ads_get_creatives and ads_get_ad_preview. Ask the user to authorise with ads_mcp_management and ads_read, not ads_management; Meta does not document whether that blocks write tools, so the allow-list still applies.
  • LinkedIn: no official MCP server was found on 2026-10-17. Use a Campaign Manager export or the Marketing API with the read-only r_ads permission.
  • Keep every ID as text. Excel keeps 15 significant digits and zeroes the rest.
  • Lint the export with a spend column (step 6). The linter prints the share of spend on failing names per platform. That sizes the cleanup.

2. Choose the tokens

A token earns its place only when both hold:

  • a recurring report or decision groups spend by it, and
  • the platform does not store it as a flat field the spend connector exports. Campaign type, bid strategy, budget, status, geo targets, devices, owner and end dates are fields. Keep them out.

Exception: a field-backed token may stay when the field is nested or missing from the team's spend connector, or when buyers need it in the platform's list view. That is why the defaults keep targeting, Meta placement and LinkedIn format.

Default grammar (definitions and values in references/grammar-and-vocabulary.md):

  • Initiative level (Google Ads campaign, Meta campaign, LinkedIn campaign group): market_objective_funnel_audience_offer_launch, for example us_leads_bofu_nonbrand_demo_202610.
  • Targeting level: Google Ads ad group and asset group targeting_theme; Meta ad set targeting_theme_placement; LinkedIn campaign targeting_theme_format.
  • Ad level: format_concept_variant for Meta ads and named Google Ads ads, concept_variant for LinkedIn creatives. Responsive search ads have no name field, so their concept and variant live in the registry against the ad ID.

Decision rules:

  • Broadest grouping first, launch month last. Never reorder after go-live: parsers read by position.
  • Children never repeat parent tokens. The warehouse joins child to parent by ID.
  • launch is the YYYYMM of first serving and never changes. A relaunch as a new object (a duplicate, or an experiment converted to a new campaign) gets a new launch month; budget and bid changes do not.
  • "Spans several" values only where needed: market global, audience all, placement auto, targeting broad. No vocabulary has other or misc.
  • Free text only in theme and concept: a hyphenated slug of at most 30 characters.
  • A term with two meanings gets two values, and on Search two ad groups and two landing pages.

3. Fix the delimiter, characters and length

  • _ between tokens, - inside a token, lowercase a-z and 0-9 only, so one SQL function splits them.
  • Reject pipes, spaces, capitals and emoji even where a platform accepts them. Meta names support emoji.
  • House maximum: 100 characters at initiative level, 60 below. Platform limits checked on 2026-10-17: Google Ads campaign 256 characters, ad group under 255, asset group 128; Meta ad set 400; LinkedIn campaign group 200 bytes UTF-8. Meta campaign and ad names and LinkedIn campaign and creative names have no published limit.

4. Set the paid UTM templates

utm-convention-and-registry's contract gives this skill the paid templates for utm_campaign, utm_id and utm_content; that skill supplies source and medium and checks the templates.

  • utm_id: the initiative-level ID by macro: {campaignid}, {{campaign.id}}, LinkedIn CAMPAIGN_GROUP_ID. utm_content: the ad ID by macro.
  • utm_campaign, default: the registry initiative name (2026_10_pipeline_webinar), typed, identical across platforms and owned channels of one initiative. A platform name would split one initiative into a row per platform.
  • utm_campaign where cost reaches GA4 through an automated connector (Meta): the platform name by macro, as that skill's cost step requires. Name before first publish; never rename while the connector runs.
  • Each initiative-level registry row holds the platform ID, the generated name, initiative_id and the utm_campaign its links send, and feeds that skill's campaign map.
  • Per-platform strings and resolved-URL checks: references/utm-mapping.md.

5. Draft the rules, vocabulary and registry

  • Draft from assets/naming-rules.yaml and assets/naming-vocab.csv, the single source of approved and retired values (also the warehouse seed). Show the diff and write to martech-context/ only after the user approves; record owners in naming-rules.md.
  • Start the registry from assets/campaign-registry-template.csv: one row per initiative-level object and per responsive search ad.
  • Generate each name from its token columns, never type it: =LOWER(TEXTJOIN("_",TRUE,I2:T2)) in the template's column order, or take the linter's suggestion. The generated name is the only approved name.

6. Lint before launch and after build

python3 scripts/lint_names.py --rules martech-context/naming-rules.yaml --names launch-names.csv --out lint-report.csv
python3 scripts/lint_names.py --rules martech-context/naming-rules.yaml --registry martech-context/campaign-registry.csv
  • Names columns: platform, level, name, plus optional account_id, object_id, parent_id, status, start_date, spend. assets/example-names.csv shows every result code.
  • Registry mode fails a current row whose name differs from its token columns, and lints the rest like names.
  • Any fail blocks the build. A warn (duplicate where the platform allows it, launch month off, legacy retired value, ID format) needs an owner note in the registry.
  • Run it on the planned names, then on the platform export after build: names get retyped and duplicated objects keep old launch months.

7. Parse names in the warehouse

  • Normalise IDs in staging and in the registry load: text, digits only. Google Ads 123-456-7890 becomes 1234567890, Meta act_1234567890 becomes 1234567890, LinkedIn URNs keep the trailing number. Test that every ad-platform registry ID matches ^[0-9]+$.
  • Build the directory, name history, vocabulary seed, registry, parse model and dim_paid_campaign: SQL in references/warehouse-parsing.md.
  • Attribute precedence: the registry row for the ID, then a name that parses cleanly, then unknown. Unknown spend stays visible in every report.
  • Spend joins on platform, account ID and object ID. Test that the join leaves row count and total cost unchanged, and report the registry match rate apart from the parse rate.
  • Sessions: session_traffic_source_last_click.google_ads_campaign.campaign_id for Google Ads, session_traffic_source_last_click.manual_campaign.campaign_id (utm_id) for Meta and LinkedIn. collected_traffic_source is event-scoped; use it only for URL checks.

8. Handle renames

  • Rename only to fix a wrong name (change_type correction, reported as is). If what runs changes market, objective, funnel or audience, launch a new object with predecessor_id; when that is not possible, record an attribute_change (reported as was).
  • Every rename goes on assets/rename-change-list-template.csv, a human applies it, and the registry row is updated the same day. Reports restate only after that.
  • Before renaming, list everything that selects the object by name: automated rules, scripts, report filters, bid tools.
  • Google Ads ad names are immutable: correct the registry. In Google Ads Editor's Replace text, leave Make changes in duplicate items unchecked; copies get new IDs.
  • Name history covers only days with snapshots. Other rename evidence: weekly section 5 in references/governance.md.

9. Run the governance loop

  • Generated name, registry row and a clean lint before build; object IDs added within one business day of launch.
  • A weekly exception report over the last seven complete days, ranked by spend. Escalate when unparsed or unregistered spend is above 5% of a platform's weekly spend in one currency.
  • Vocabulary changes go through naming-vocab.csv: add, alias, retire; never edit in place. Never add a value to make a name pass: list it as a candidate with the names and spend that use it, for the approvers named in naming-rules.md.
  • Report SQL, approvals, renames and cleanup: references/governance.md.

Common failure modes

  • Name used as a join key. Detect: spend drops or doubles after a rename; cost differs before and after the attribute join.
  • IDs in different formats (UI dashes, act_, URNs, scientific notation). Detect: bad_id warnings; registry match rate far below parse rate.
  • Registry columns disagree with the name. Detect: registry_mismatch; weekly section 4.
  • Duplicated campaign keeps the old launch month. Detect: launch_mismatch; launch month earlier than first spend.
  • Platform name macro in utm_campaign off a connector route. Detect: GA4 campaign values equal to platform names; one manual_campaign_id with several names.
  • Literal macros reach GA4. Detect: campaign values containing {{, %7B%7B or {_.
  • Vocabulary drift (lead, leads, leadgen). Detect: vocab and retired_value results; new values in the weekly report.
  • Tokens parsed by position after a reorder. Detect: market values in the objective column.
  • Duplicate rows in the vocabulary seed. Detect: spend multiplied after the vocabulary join; uniqueness test.
  • A renamed campaign drops out of an automated rule or a dashboard filter. Detect: rules and filters that match on name text.
  • Objects created outside the registry: boosted posts (including ads_boost_ig_post), experiments converted to new campaigns, platform default or copy-suffixed names, buying tools' templates. Detect: spend IDs with no registry row; a new ID whose first spend date equals a paused sibling's last spend date; default or copy name patterns seen in the export.

Worked example

Acme, a fictional B2B software company, runs a pipeline webinar in October 2026. Its UTM registry initiative is 2026_10_pipeline_webinar. Cost is joined in the warehouse and imported to GA4 by file from the campaign map, so every platform takes the default route.

  • Meta: campaign uk_leads_tofu_smb_pipeline-webinar_202610, ad set lal_customers-1pct_auto, ad vid_founder-story_v2. URL parameters type utm_campaign=2026_10_pipeline_webinar with utm_id={{campaign.id}} and utm_content={{ad.id}}.
  • LinkedIn: campaign group uk_leads_mofu_ent_pipeline-webinar_202610, campaign job_revops-leaders_doc with static utm_campaign=2026_10_pipeline_webinar and dynamic CAMPAIGN_GROUP_ID and CREATIVE_ID.
  • Newsletter: utm_campaign=2026_10_pipeline_webinar, utm_id=cmp_2026_104.
  • GA4 shows one campaign value for all three. The registry links the Meta campaign, the LinkedIn group and the newsletter to ini_2026_014, so the warehouse reports the webinar's spend and sessions by offer and launch month.
  • In week two the team sees the Meta campaign targets mid-market, so smb was wrong. The registry row is closed and replaced with audience mm and change_type correction; the platform rename follows from the generated name. Spend stays on the same ID, reports restate under mm, the name history keeps both periods, and GA4 is untouched because utm_campaign never carried the platform name.
  • The lint of the build export catches a duplicated ad group name, a campaign still named 202609, and an ad exported with account act_1234567890.

Acceptance checks

  • Rules and vocabulary: every level used in the accounts has tokens, vocabularies and a house maximum below the platform limit. Pass: the linter loads them without a rules error.
  • Lint: run on the full export. Pass: zero fail rows outside exempt_ids, or a dated cleanup plan for each.
  • Registry: registry-mode lint. Pass: zero registry_mismatch and registry_tokens rows.
  • IDs: the ID format test and the registry match test in the warehouse. Pass: no rows from either; the registry match rate is reported per platform.
  • Spend coverage: share of 90-day spend whose attributes come from the registry or a clean parse. Pass: at least 95% per platform, the rest visible as unknown.
  • Join integrity: spend row count and total cost before and after the attribute join. Pass: identical.
  • UTMs: one resolved landing URL per platform. Pass: Meta and LinkedIn show no literal macros, utm_id equal to the initiative-level ID and utm_campaign equal to the registry row; Google Ads keeps gclid after redirects, and manual values resolve when used.
  • GA4: a BigQuery query of manual_campaign_id for paid social. Pass: every ID matches a directory row, with one campaign name each.
  • Renames: name history for the last 30 days against the change list. Pass: every rename has a change-list row and an updated registry row.
  • Owners: rules owner, vocabulary approvers and report owner are named in naming-rules.md. Pass: a dated entry in decisions.md.
  • Approval: the user approved the rules, vocabulary, registry and any rename list before they were written or applied. Pass: nothing in martech-context/ or a platform changed without it.

Boundaries

  • Read-only. The skill proposes rules, vocabulary, registry rows, lint reports, SQL and rename lists. It never renames, creates or edits platform objects; a human applies changes in the platform UI, Google Ads Editor or an approved API call, after agent-write-safety's checks when an agent is involved.
  • Never call Meta Ads MCP write tools: any ads_create_*, ads_update_* or ads_delete_* tool, ads_activate_entity or ads_boost_ig_post.
  • It does not set source, medium or non-paid UTM values, account structure, bidding or budgets.
  • Hand-offs:
    • Google Ads: Google's read-only Google Ads MCP server to read names and IDs; google-ads-editor-import-builder, if installed, to prepare approved changes for Editor.
    • Meta: Meta's Ads MCP server, the read tools in step 1 only.
    • LinkedIn: Campaign Manager exports or the Marketing API with r_ads. The Microsoft Learn MCP server searches LinkedIn's API docs.
    • UTMs: utm-convention-and-registry for source, medium, the UTM registry, the campaign map and its channel and cost-join checks.
    • Warehouse: run SQL through a read-only role, for example the BigQuery MCP server's execute_sql_readonly tool. Model changes go through the team's code review.

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.

The entries that matter most here: the Google Ads API system limits page and resource definitions, the ValueTrack and custom parameter pages, the BigQuery Google Ads transfer page, Meta's URL tags guide and Ads MCP tools page, LinkedIn's campaign group and dynamic UTM tracking pages, and GA4's default channel group and BigQuery export schema pages. Every limit in this skill and its references was checked on 2026-10-17.

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.