Skip to content
Home » Reference » Event Schema Versioning: How to Change Tracking Without Breaking Reports

Event Schema Versioning: How to Change Tracking Without Breaking Reports

The most common analytics disaster I get called in to fix isn’t broken tracking — it’s tracking that used to work and silently changed. Someone renamed an event, repurposed a parameter, or split one event into two. None of that broke the dashboard immediately. The numbers just started lying. By the time anyone noticed, three months of reports were unreliable, and nobody could remember which version of the schema produced which row.

The fix is event schema versioning: a small amount of discipline that lets you change tracking without breaking history. This guide covers the model I use, the rules that prevent the worst migrations, and the code patterns I’ve seen survive multi-year evolution.

Why “Just Rename It” Is Always Wrong

Every analytics event you’ve ever shipped is part of a contract between your product code, your warehouse, and every dashboard, report, alert, and downstream process that reads from it. When you rename an event from checkout_started to checkout_initiated, you’ve quietly broken that contract for every consumer you don’t know about.

The dashboard probably has a hardcoded reference to the old name. The data warehouse has a transformation that joins on it. The marketing automation tool has a trigger configured by someone who left the company. Any one of these will fail silently — they’ll just show zero, which is the worst possible failure mode because zero looks like a valid number.

The Three Rules of Schema Versioning

Rule 1 — Add, Don’t Change

When you need to evolve an event, the default move is to add a new event alongside the old one, not to modify the existing one. The old event keeps firing for downstream consumers that rely on it. The new event captures the new data shape. Both run in parallel until you know the old one can be retired.

This rule has saved me from rollbacks more times than I can count. The cost is a slightly larger event volume during the migration window. The benefit is that nothing breaks while you transition.

Rule 2 — Version the Schema, Not the Event Name

Don’t put a version number in the event name. checkout_started_v2 looks fine until you have v3 and v4, at which point your dashboards become a maze of OR clauses. Instead, add a schema_version parameter to every event:

{
  "event": "checkout_started",
  "schema_version": "2",
  "cart_value_eur": 84.50,
  "items_count": 3,
  "currency": "EUR"
}

The event name stays stable. The version parameter tells every downstream consumer which schema to expect. Your dashboards filter by version when they need to, or aggregate across all versions when the change was additive and safe.

Rule 3 — Document the Diff in the Plan

Every schema version change goes into your measurement plan with a date, a reason, and a list of affected downstream consumers. This is the only documentation that survives long enough to be useful when someone six months later asks “why does this report show different numbers before and after April?”

The Migration Pattern

Here’s the four-phase pattern I follow for any breaking schema change. It takes longer than just renaming, but the longest “what broke?” debug session it’s ever caused me is about ten minutes.

  1. Phase 1 — Dual emit. The product code emits both the old and new event for every action. Schema version is set on each. No consumers change yet.
  2. Phase 2 — Migrate consumers. Update each dashboard, query, and downstream integration to read from the new event. Verify each one against the old event during the migration to catch divergences.
  3. Phase 3 — Stop emitting old. Once every known consumer is on the new event, remove the dual emit from the product code. Keep the schema version logic — you’ll need it for the next change.
  4. Phase 4 — Delete old data. After your retention window passes (typically 14 months), drop the old event from your data warehouse to save storage. Document the deletion in the measurement plan.

I usually budget 4 to 6 weeks for the full migration of a moderately-used event. Critical events take longer because the consumer audit is bigger. Don’t rush — the savings from rushing aren’t worth a single broken Q3 report.

Common Schema Changes and How to Handle Them

Change typeRisk levelHow to handle
Add new optional parameterLowAdd it. Bump schema_version. No migration needed.
Add new required parameterMediumAdd as optional first, backfill, then make required.
Rename a parameterHighAdd new param alongside old. Migrate consumers. Drop old.
Change a parameter typeHighAdd new param with new type. Don’t reuse the old name.
Split one event into twoHighDual emit pattern. Both events for two months.
Merge two events into oneHighEmit the new merged event. Keep old events firing until consumers migrate.
Rename an eventCriticalDon’t. Use the dual emit pattern with two distinct names.

Testing Schema Changes Before Production

Every schema change should go through three checks before it hits production:

  • Lint the schema. Check that event names and parameter names match your naming conventions, that types are consistent, and that no required parameters are missing. A simple JSON Schema validator works fine.
  • Compare against staging traffic. Run the new schema against staging for at least a day. Check that the volume of the new event matches the old one within 1%. Divergence usually means a code branch was missed.
  • Dry-run downstream queries. Take your three most important reports, swap in the new event, and confirm the numbers match. Mismatches at this stage are cheap to fix; mismatches in production are expensive.

Common Mistakes I See

  • Renaming events to “match a new convention.” The cleanup feels good. The reality is you broke six dashboards. Add new events that follow the convention and let the old ones decay naturally.
  • Reusing parameter names with new meanings. If cart_value used to mean cents and now means euros, your historical reports just became indecipherable. New meaning gets a new name.
  • Skipping the schema_version field “because we’ll know.” You won’t. Six months from now, nobody will remember when the change happened, and nobody will be able to filter the data accordingly.
  • Migrating consumers in parallel with emission changes. Always finish dual-emit and verify volume parity before any consumer switches over. Otherwise you can’t tell what broke when something does.

FAQ

How long should I run dual emit before deleting the old event?

At least one full reporting cycle for your slowest report. For most teams that’s a quarter. If your finance team relies on a yearly report that joins on the event, wait a full year before deleting.

What if I can’t find all the downstream consumers?

Audit them properly before you start the migration. Search your warehouse query logs for references to the event name, ask each team to confirm their dashboards, and check your marketing automation triggers. Skipping this audit guarantees a surprise outage later.

Should the schema version be a number or a string?

String. Numbers tempt people to do version comparisons (“v > 2”) that don’t make sense — schema versions aren’t ordered in any meaningful way. Strings force you to use exact match, which is what you actually want.

Do I need versioning if I’m a small team with simple events?

You’ll need it the day you don’t have it. Add the schema_version field on day one, even if you only ever ship “1.” It costs nothing and saves the entire painful migration the first time you actually need to change a schema.

Conclusion

Schema versioning is a small habit with an enormous payoff. The discipline of “add, don’t change” plus a schema_version parameter on every event eliminates the entire class of silent-breakage bugs that dominate analytics post-mortems. Set it up once, document it once, and it’ll keep paying off for years.

The worst migration I’ve ever done took six weeks. The worst un-versioned mistake I ever inherited took four months to untangle. The math is on the side of doing it right the first time.

Leave a Reply

Your email address will not be published. Required fields are marked *