AI UTM Generator

The UTM_Parameter.xlsx spreadsheet, finally retired

A multi-tenant UTM and tracking-taxonomy platform that replaces the fragile team spreadsheet with governed, validated data entry and live, paste-ready GA4/CRM code.

Every marketing team ends up with the same file: a UTM_Parameter.xlsx with tabs for verticals, form types, page types, funnel stages, lead magnets. It works until it doesn't - no access control, no validation, copy-paste errors in campaign URLs, no single source of truth for what utm_cv actually means, and no audit trail for who changed what. AI UTM Generator is that spreadsheet's replacement: a proper multi-tenant web app built to run on the same kind of affordable shared hosting a spreadsheet-era team already has, not a $50/month SaaS stack.

What It Is

A multi-tenant PHP/MySQL web app where each company gets its own login and manages its own landing pages, UTM and event taxonomy, campaign UTM links, and auto-generated GA4/CRM tracking snippets - turning a fragile spreadsheet workflow into governed, validated, auditable data entry with live-rendered code output.

Built to Be Universal, Not Hardcoded

The original spreadsheet had nine fixed categories - verticals, services, page types, form types, form locations, funnel stages, events, lead magnets, traffic types. Rather than force every future tenant into those exact nine buckets, a Custom Variables system lets any tenant add their own data-layer keys - an A/B test variant, a partner code, an ad format - as either a fixed list or free text, and those become usable everywhere in the app.

Paired with tenant-defined Naming Conventions, a real customer's spreadsheet formula was reproduced exactly, without a spreadsheet formula in sight:

PA-------PA1-DT-CPQ-GA-RSA-Traffic-Aug2026-V1

The deliberate design call here: we rejected rewriting the nine existing modules into a more "pure" generic EAV structure, because that would mean migrating working code for no functional gain. Adding a variables layer on top shipped faster and reused patterns already proven elsewhere in the app - additive over architecturally elegant, when elegance doesn't actually buy anything.

The Bug That Only Shows Up at Click-Time

Google and Bing Ads use placeholders like {keyword}, {device}, and {matchtype} in ad URLs, substituted live the moment someone clicks the ad - but only if they appear literally unencoded. PHP's http_build_query() percent-encodes { and } like any other character, silently turning utm_term={keyword} into utm_term=%7Bkeyword%7D. Google Ads simply doesn't recognise the encoded version, and the literal string %7Bkeyword%7D shows up in analytics instead of the actual keyword someone searched.

It's the kind of bug that passes every code review and only surfaces once real ad spend hits it. Fixed with a matching PHP and JavaScript unencode step at the point URLs get built and rendered, plus a one-time data migration that retroactively repaired every URL already saved before the fix shipped.

Tenant Isolation at the Data Layer, Not Per-Controller

Rather than trusting every controller to remember to add WHERE tenant_id = ?, a shared BaseModel class enforces tenant scoping centrally - every model that extends it automatically gets tenant-scoped queries. One shared MySQL database, practical on shared hosting where you often get exactly one; the tenant is resolved from the logged-in user rather than the subdomain, so no wildcard DNS is needed. A bug in any one controller cannot leak another company's data, because the isolation lives one layer down in the data models, not scattered across application logic in fifteen different controllers.

Deliberately Boring Deployment

No Docker, no Composer, no build step, no Node in production. Plain PHP 8 and PDO, deployed via cPanel's native Git Version Control - the kind of hosting a small agency or a two-person marketing team can actually afford and self-manage, instead of assuming everyone has a cloud platform and a DevOps person on staff. Boring tech, deliberately, because the people actually using this tool are marketers, not infrastructure engineers.

Real, Paste-Ready Code Output

Snippet Templates use substitution to produce live GA4 dataLayer pushes and CRM lead objects per landing page, so a non-technical marketer configuring a landing page in the UI gets back the exact JavaScript block their dev team pastes into GTM - not a data export someone still has to translate into code.

The Campaign/UTM Link Builder works the same way for campaign URLs: pick a channel - Google Ads Search, Meta, LinkedIn, Email, and more - and it recommends the GA4-correct source/medium combination most marketers don't have memorised, reveals channel-specific extra parameters, and live-previews the final URL before anything gets copied.

Built for How Marketing Teams Actually Work

Role-based access runs Owner > Admin > Editor > Viewer, with invite links so a teammate can self-onboard into the right company workspace with their own password instead of an admin hand-typing every account. It maps to how a real marketing org chart is structured, not a generic permissions system bolted on afterward.

Full Feature List

  • Landing Pages module with CSV bulk import - rows are matched to other modules by human-readable name, not internal ID, so a typo in a reference warns instead of silently failing the whole row
  • Tracking Configurations linking a landing page to the taxonomy, auto-building a unique form_id and rendering live snippets, with two CSV export modes (basic + snippets, full + snippets)
  • Campaign/UTM Link Builder with channel-aware defaults and live preview
  • Ad Channels as tenant-editable presets, not hardcoded into the app
  • Custom Variables and Naming Conventions - the universal layer described above
  • Per-tenant editable Snippet Templates, each toggleable for whether it applies to Tracking Configs
  • CSV exports that resolve every foreign key to a real name - no raw database IDs in exported spreadsheets
  • Super Admin back office for the platform operator, including the ability to suspend or reactivate tenant workspaces
  • Clean URLs (/campaigns/edit/3, not /index.php?r=...)

Get in touch if your team is still living in a UTM spreadsheet and you want to see what replacing it actually looks like.