WPForms attribution often starts as a few UTM values in cookies or localStorage, then grows to include click IDs, landing pages, referrers, consent state, session IDs, and touch history. Changing that data shape without a schema version can make old visitors look direct, map values into the wrong hidden fields, or retain data that should have been purged.
Use this before changing a UTM capture script, storage key, hidden-field mapping, consent model, or attribution plugin on a site with active paid and organic lead campaigns.
Quick answer
Add an explicit schema version and write an idempotent migration that reads the old record, validates consent and expiration, maps known fields, preserves source provenance, and writes the new record only after validation. Test fresh, returning, expired, revoked-consent, duplicate-tab, and partially corrupted records before release.
What to check first
- Inventory every current storage key, field name, type, expiration rule, consent dependency, and WPForms hidden-field destination.
- Define old-to-new mappings for UTM values, click IDs, landing page, referrer, first touch, latest touch, session, and timestamps.
- Preserve a migration marker and source version so the same browser record cannot be transformed twice.
- Reject malformed values, unknown fields, unsafe URLs, and records beyond the approved retention window.
- Prove the migrated browser record and submitted WPForms entry share a stable journey or lead identifier.
Test scenarios to run
Run the same controlled fixture across these branches. Write down the expected result before testing so a surprising response is easy to identify.
| Scenario | Fixture | Expected result |
| Fresh visitor | No prior storage and a tagged landing URL | Versioned record is created and fields reach one test entry |
| Returning visitor | Valid version 1 record | Migration preserves first touch and updates only fields allowed by policy |
| Revoked consent | Old record followed by consent withdrawal | Attribution storage is purged and hidden fields remain empty |
| Corrupt record | Invalid JSON or wrong field types | Migration fails closed, records a safe diagnostic, and does not submit mixed data |
Decision rule
Release only when every supported old version migrates once, revoked or expired data is removed, and submitted hidden fields match the approved schema. Stop if migration changes first-touch policy, consent meaning, or identifier linkage without an owner decision.
Safe fix order
Use a sequence that makes each result easy to prove. Stop when new evidence changes the scope or owner of the problem.
- Document the current and target schemas with privacy and retention owners.
- Build a pure migration function with validation, version guards, and safe failure behavior.
- Run the full fixture matrix in isolated browser profiles and duplicate tabs.
- Release behind a version flag and monitor migrated versus rejected records.
- Verify WPForms entries, analytics events, and CRM records retain the intended journey ID.
Diagnostic table
Use this table to connect the observed behavior to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Document the current and target schemas with privacy and retention owners. | Inventory every current storage key, field name, type, expiration rule, consent dependency, and WPForms hidden-field destination. | Each supported record reaches the target schema exactly once and keeps its source version. |
| Build a pure migration function with validation, version guards, and safe failure behavior. | Define old-to-new mappings for UTM values, click IDs, landing page, referrer, first touch, latest touch, session, and timestamps. | Expired, revoked, malformed, and unknown-version records fail according to policy. |
| Run the full fixture matrix in isolated browser profiles and duplicate tabs. | Preserve a migration marker and source version so the same browser record cannot be transformed twice. | WPForms hidden fields and the stored record share the same journey ID and approved values. |
| Release behind a version flag and monitor migrated versus rejected records. | Reject malformed values, unknown fields, unsafe URLs, and records beyond the approved retention window. | Rollback restores the previous reader without corrupting records already migrated. |
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
{
"schema_version": 2,
"journey_id": "j_8d291",
"first_touch": {"utm_source": "google", "landing_path": "/service"},
"latest_touch": {"utm_source": "newsletter"},
"consent_state": "granted",
"expires_at": "2026-11-08T14:00:00Z",
"migrated_from": 1
}
Production verification checklist
- Each supported record reaches the target schema exactly once and keeps its source version.
- Expired, revoked, malformed, and unknown-version records fail according to policy.
- WPForms hidden fields and the stored record share the same journey ID and approved values.
- Rollback restores the previous reader without corrupting records already migrated.
Why this usually happens
- Browser storage has no built-in schema migration, so a script update must manage old records explicitly.
- Different plugins use similar field names with different meanings, timestamps, and attribution rules.
- Consent and retention changes can make an old technically valid record no longer permissible to use.
Field notes
- Keep raw advertising identifiers out of logs and screenshots. Use masked examples or disposable test values.
- Migrations should be idempotent and reversible during a controlled release window.
- Do not let an unknown future version fall back to an older parser that silently drops fields.
Mistakes to avoid
- Do not rename storage fields in place without a version and migration path.
- Do not migrate expired or consent-revoked data simply because it parses.
- Do not test only a fresh browser profile.
- Do not write full click IDs or customer fields into diagnostic logs.
What to tell the client or owner
Provide old and new schemas, field mappings, consent and retention rules, fixture results, migrated and rejected counts, rollout flag, rollback plan, and joined WPForms entry evidence.
Questions teams ask during testing
Do I need a schema version for five fields?
Yes when those fields persist across releases or feed business reporting. A version makes changes and failures explicit.
Should first touch change during migration?
Only if the approved attribution policy says so. A technical migration should not silently rewrite business logic.
What happens with an unknown future version?
Fail safely and preserve the record for a newer reader instead of downgrading it into an older shape.
When HandL WP should help
Bring in help when this affects leads, checkout, search visibility, security, paid media reporting, or a client production site. HandL WP can trace the issue through WordPress, hosting, cache, tracking, and Search Console, then verify the workflow after the technical fix.
If this is active on a production site, protect WPForms attribution during a schema change.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references