What we learned migrating 50+ properties from UA to GA4
Universal Analytics is dead. But the lessons from migration are still relevant. Here are the patterns that worked and the mistakes we kept making.
Universal Analytics stopped processing data on July 1, 2023. By that date, we had migrated over 50 properties for clients across e-commerce, SaaS, publishing, and lead generation. Some of those migrations went smoothly. Some were painful. A few were genuine disasters that required months of cleanup.
It’s been nearly three years since UA died, and I still think about those migrations regularly. Not because of nostalgia for UA (I don’t miss it), but because the lessons apply to every major analytics platform change. The way we approached those migrations, the mistakes we made, and the things we got right have shaped how I handle every analytics project since.
The biggest mindset shift
The hardest part of moving from UA to GA4 wasn’t technical. It was conceptual. UA and GA4 measure fundamentally different things, and every migration that went wrong started with someone saying “let’s just replicate our UA setup in GA4.”
UA was session-based. Everything revolved around sessions: session duration, pages per session, bounce rate, goal completions per session. Your reports were organized around what happened during a visit.
GA4 is event-based. Everything is an event. A pageview is an event. A scroll is an event. A purchase is an event. There’s no fundamental distinction between a pageview and a button click. Sessions exist in GA4 but they’re calculated after the fact, not baked into the data model.
This difference sounds academic until you try to replicate a UA report in GA4 and realize it doesn’t translate. “Bounce rate” in UA meant the percentage of single-page sessions. GA4 replaced it with “engagement rate” (the inverse of bounce rate, but calculated differently, based on engaged sessions of 10+ seconds). The numbers don’t match. They were never going to match.
The migrations that went smoothly were the ones where the client accepted this early. “We’re building a new measurement plan for a new platform.” The ones that went badly were the ones where stakeholders demanded that GA4 numbers match UA numbers exactly. That’s not a migration. That’s trying to force a square peg into a round hole while management compares the holes.
What we got wrong early
I’ll be honest about our mistakes because they’re probably more useful than our successes.
Mistake 1: Trying to recreate every UA goal in GA4. One client had 34 goals in UA. Some tracked form submissions. Some tracked page visits. Some tracked events with specific category/action/label combinations. We initially tried to recreate all 34 as GA4 conversions. About halfway through, we realized that 20 of them were redundant, outdated, or measuring things nobody cared about anymore. The migration forced a cleanup that should have happened years earlier.
The lesson: migration is the perfect time to audit and simplify. Don’t carry forward every piece of your old setup. Ask “do we still need this?” for every goal, report, and custom dimension.
Mistake 2: Not running GA4 in parallel long enough. For our earliest migrations, we set up GA4 and ran it alongside UA for 2-3 weeks before switching. That wasn’t enough. Data discrepancies between platforms take time to understand. Seasonal patterns need at least a quarter of parallel data. Year-over-year comparisons need a full year.
We eventually standardized on a minimum 3-month parallel period. For clients with strong seasonality (retail, travel), we pushed for 6 months.
Mistake 3: Ignoring the data stream configuration. GA4 has “enhanced measurement” settings that auto-track things like scroll, outbound clicks, site search, video engagement, and file downloads. In our early migrations, we left these on by default without checking them. For several clients, this caused duplicate events because they already had custom GTM tags tracking the same interactions. We had double-counted scrolls, duplicate outbound click events, and conflicting site search tracking.
Now I always review enhanced measurement settings first and disable anything that’s already tracked via GTM.
Mistake 4: Underestimating the reporting transition. We focused heavily on getting the data collection right and assumed reporting would sort itself out. It didn’t. Stakeholders who had been using specific UA reports for years couldn’t find the equivalent data in GA4. The standard reports are organized differently. The custom report builder (Explore) works differently. Simple things like “show me landing pages by conversion rate” require different steps.
We learned to build a GA4 reporting guide for each client: a document mapping their most-used UA reports to their GA4 equivalents, with screenshots. This reduced support requests by 80%.
The data model difference and why it matters
In UA, you had three hit types: pageview, event, and transaction. Events had a rigid structure: Category, Action, Label, Value. If you wanted to track a button click, you’d set Category to “Button,” Action to “Click,” Label to “CTA Header.”
GA4 has one hit type: events. Every event has a name and up to 25 custom parameters. There’s no category/action/label structure. A button click might be an event called “cta_click” with parameters like “button_text,” “page_location,” and “button_position.”
This flexibility is powerful but requires more upfront planning. In UA, the rigid structure forced some consistency (even if it was limiting). In GA4, you can name events and parameters anything you want, which means you need a solid event tracking strategy and naming convention before you start implementing.
We developed a naming convention early and applied it to every migration:
- Event names: lowercase, snake_case, verb_noun format (“generate_lead,” “add_to_cart,” “start_checkout”)
- Parameter names: lowercase, snake_case, descriptive (“button_text,” “form_name,” “content_type”)
- Always use GA4’s recommended event names when they exist (purchase, sign_up, login, etc.)
Properties that followed this convention were clean and usable. Properties where we let different team members name things inconsistently became messy within weeks.
Still struggling with your GA4 setup?I'll audit your configuration and fix the gaps left by a rushed migration.
Book a Free Audit →Custom dimensions: what to migrate, what to abandon
UA custom dimensions were a mixed bag. Most properties we migrated had 15-20 custom dimensions, and at least half of them were unused or broken.
Our process for each custom dimension:
- Is anyone using this in reports? Check by looking at saved reports, dashboards, and segments that reference it.
- Is the data still being populated correctly? Some custom dimensions referenced code that was removed years ago.
- Does GA4 already track this natively? GA4 auto-captures things like page_title, page_location, page_referrer, and screen_resolution that were often set up as custom dimensions in UA.
- If it’s still needed and not available natively, create it as a GA4 custom dimension (event-scoped or user-scoped).
Session-scoped custom dimensions from UA were the trickiest to migrate. GA4 doesn’t have session-scoped custom dimensions. You have event-scoped and user-scoped. If you were using a session-scoped dimension in UA (like “logged_in_status” or “customer_segment”), you need to rethink how to implement it. The usual approach: send it as an event parameter with every event, or set it as a user property if it’s relatively stable.
One thing I learned the hard way: GA4 has limits on custom dimensions. 50 event-scoped and 25 user-scoped for standard properties. We hit these limits on several large enterprise migrations. The solution was ruthless prioritization and using BigQuery for dimensions that didn’t need to be in the GA4 UI.
Historical data: what to export, how to store it, when to let go
Google kept UA data accessible until July 2024, then deleted it. We had a year to export historical data. Here’s what we recommended to clients:
Always export: monthly summary data for key metrics (sessions, users, conversions, revenue) by channel, by page, and by device. This preserves trend data for year-over-year comparisons.
Export if useful: raw hit-level data via the UA BigQuery export (if they had it) or the Google Analytics Reporting API. This is large and expensive to store but invaluable for detailed historical analysis.
Don’t bother exporting: standard reports that can be summarized in a few tables, custom segments (they don’t transfer, and GA4 segments work differently), and real-time data.
For storage, we used BigQuery for raw data and Google Sheets for summary data. BigQuery because it’s cheap for cold storage and you can query it when needed. Google Sheets because stakeholders can access it without technical skills.
The harder conversation: when to let go of historical data. Some clients wanted to compare GA4 data to UA data indefinitely. That comparison is fundamentally flawed because the platforms measure differently. Sessions in UA don’t equal sessions in GA4. Users are counted differently. Conversion attribution works differently.
I advise clients to use UA historical data for broad trend analysis (“were we growing in 2022?”) but never for direct metric comparison with GA4 (“our bounce rate was 45% in UA but our engagement rate is only 60% in GA4, what happened?”). Those numbers are apples and oranges.
After 12-18 months of GA4 data, most clients naturally stopped referencing UA data. The transition happened faster than anyone expected.
What made the difference between smooth and disastrous
After 50+ migrations, patterns emerged. The properties that went smoothly shared certain traits:
Clear ownership. A single person or small team owned the migration end to end. They made decisions, set timelines, and held everyone accountable. Properties where “analytics” was everyone’s responsibility and nobody’s priority dragged on for months.
Stakeholder alignment on expectations. The team agreed upfront that numbers wouldn’t match between UA and GA4. They agreed on a parallel running period. They agreed on a go-live date. Properties where executives expected a seamless, zero-disruption transition were consistently the most painful.
Clean UA implementations to start with. If the UA setup was well-organized, with clear naming conventions, documented goals, and maintained custom dimensions, the migration was straightforward. We knew what to migrate because the existing setup made sense. Properties where UA had accumulated years of undocumented, inconsistently-named tags were nightmares. We spent more time understanding the old setup than building the new one. If your GA4 migration still feels broken, chances are these foundational issues were never resolved.
GTM-based implementations. Properties using Google Tag Manager were dramatically easier to migrate than properties with hardcoded UA tracking. With GTM, we could update tags without code deployments. Without GTM, every change required a developer, a code review, and a production deploy. One client without GTM took 4 months for a migration that would have taken 2 weeks with GTM.
Early BigQuery export setup. Properties that enabled the GA4 BigQuery export early had a safety net. Even if the GA4 UI configuration wasn’t perfect, the raw data was being captured. We could fix reporting later without losing data. Properties that delayed the BigQuery export sometimes lost months of detailed data that couldn’t be recovered from GA4’s aggregated reports.
The disasters shared opposite traits: no clear owner, unrealistic expectations, messy existing implementations, hardcoded tracking, and no BigQuery export.
What I’d do differently
If I could redo those 50+ migrations with what I know now:
Start with a measurement plan, not a migration plan. Instead of “what do we move from UA to GA4,” ask “what do we need to measure in GA4?” Start from business questions, not from existing implementation. This produces a cleaner GA4 setup and naturally eliminates the dead weight from UA.
Invest more in training. We underestimated how much time stakeholders needed to learn GA4’s interface. The reporting is genuinely different. Budget for training sessions, reference guides, and a Q&A period after go-live.
Set up the BigQuery export on day one. No exceptions. Even for small properties. The cost is negligible and the value of having raw historical data from the start of your GA4 journey is immense.
Automate the parallel monitoring. We manually compared UA and GA4 data during the parallel period. In retrospect, we should have built automated discrepancy alerts that flagged when the platforms diverged beyond expected thresholds. We eventually built this for later migrations, and it caught issues days earlier than manual checking.
Why this still matters
UA is gone. But the lessons apply to every platform transition. Google will change GA4 eventually. New privacy regulations will force measurement changes. Server-side tracking will evolve. The ability to plan a measurement migration, manage stakeholder expectations, and execute without losing data is a permanent skill.
If you went through a UA to GA4 migration and your GA4 still feels like a compromised version of UA, it might be worth rebuilding your measurement plan from scratch. Treat GA4 as its own platform with its own strengths. Define what you need to measure today, not what you measured three years ago. The best GA4 implementations I see now are the ones that were designed for GA4, not translated from UA.
Artem Reiter
Web Analytics Consultant