A migration is mostly a sequencing problem: archive what you have, run the new tool next to the old one, prove the numbers, then delete the old tag. Here is the whole path, including what you will lose on the way.
There is no importer. GhostMetrics history begins the day its tag goes live. Whatever you want to keep from Google Analytics 4 has to be exported and stored by you before you leave.
data-gm-event attribute or a window.ghostmetrics.track() call. There is no automatic translation.Ready to start? Open a free GhostMetrics account (one site, unlimited pageviews, no card), or look at the live demo first.
Every migration guide that promises a "seamless import" is describing a tool that reads GA4 data through the Data API and rewrites it into its own schema. GhostMetrics does not do that. It is a cookieless tracker with its own event store, and the only way rows enter it is a visitor's browser sending a beacon to gm.js's endpoint. So on cutover day your GhostMetrics dashboard is empty and fills forward from the moment the tag loads.
That has three practical consequences. First, your GA4 history is an archive, not a baseline that lives in the new tool. Year-over-year comparisons will happen in a spreadsheet or a database you own, not in the GhostMetrics dashboard. Second, the earlier you install the tag, the earlier your new history starts, which is the argument for doing the install step this week and the cleanup step later. Third, the definitions differ, so a line that crosses from GA4 numbers into GhostMetrics numbers on a chart will show a step change that is methodology, not traffic.
What does carry over is your knowledge of the site: which pages matter, which campaigns you run, which buttons count as conversions. That is the input to the mapping step below. If you are still deciding whether to leave at all, our Google Analytics alternatives comparison covers the field, and the GDPR question is the reason many teams start this process.
Do this before you install anything, because it is the only irreversible step. GA4's standard properties retain user-level and event-level data for either 2 or 14 months depending on the retention setting, while aggregated standard reports keep longer. Check the retention setting in your property's data settings, then assume that anything older than that window in an exploration is already gone. Anything you have not exported when the window rolls over is not recoverable.
BigQuery export. GA4 offers a free export of raw events to BigQuery. It only fills forward from the day you link it, so it will not backfill months you have already lost, but if you link it today you capture everything from here until the day you finish the migration. It is the closest thing GA4 has to a complete, queryable archive, and it is the right choice if you have a lot of event-level data or want to run SQL against it later.
Report exports. Every standard report and exploration has an export control that downloads what you are looking at as CSV or to Sheets. This is the low-effort route and it is enough for most small sites. Export the reports you actually use: traffic acquisition, pages and screens, landing pages, events, conversions, geography and tech. Pick the widest date range GA4 lets you, and export once per year of data if the report row limit truncates a longer range.
The Data API. For scheduled pulls into your own database, the GA4 Data API returns any report as JSON; it needs a service account and a short script.
Most confusion during a migration comes from words that mean different things in the two tools. This table maps the concepts you are used to onto what GhostMetrics actually has.
| GA4 concept | GhostMetrics equivalent | Difference that matters |
|---|---|---|
| Users / active users | None. Visitors are counted per session | No cookie and no identifier, so no returning-visitor concept |
| Session | One browser tab, held in sessionStorage | Closing the tab ends it; coming back tomorrow is a new session |
| Engaged session / engagement rate | Bounce rate and time on page | A bounce is a single-page session in that tab, the classic definition, not GA4's engaged-session rule |
| Events (automatic and custom) | Custom Events panel: event name, count, last fired | You define every event yourself; only section is stored as metadata |
| Key events / conversions | A custom event you decide to watch | No numeric value or revenue field |
| Traffic acquisition | Referrers plus source types: search, social, direct, referral | No referrer header means "direct"; typed URLs and stripped referrers look the same |
| Campaign reports (UTMs) | UTM Breakdown: source, medium, campaign, visits | utm_term and utm_content are not stored; attribution is first-touch within the session |
| Pages and screens | Top pages, entry pages, exit pages | Same idea, plus a scroll-depth funnel and time-on-page distribution |
| Demographics, tech, geography | Country and city, browser, OS, device | No age, gender or interest data; location comes from the request without storing an IP address |
| Core Web Vitals (via other tools) | Vitals panel: FCP, LCP, CLS, TTFB from real users | INP is not captured |
| BigQuery export | CSV or JSON export of every stored row | Available on every plan, with a manifest.json describing every column |
| Audiences, Google Ads links | No equivalent | Not a feature of a cookieless tool |
| Explorations | Dashboard views and the raw export | Deeper slicing means exporting and using a spreadsheet or SQL |
Read the second column as a shopping list of what you can measure after the switch, and the third as the list of habits to unlearn. The one that catches people is users. GA4 reports a user count by tying visits together with a cookie. GhostMetrics deliberately does not, so it will never produce a "returning visitors" number, and any goal you had built on that number needs to be rephrased in terms of sessions, pages or events.
Do not remove anything yet. The point of the overlap is that both tools observe the same traffic over the same days.
<head>. It works on any HTML page on any host, with no plugin, tag manager or build step:
<script defer src="https://ghostmetrics.nullagency.io/gm.js" data-site="YOUR-SITE-ID"></script>pushState or popstate navigation counts as a new pageview, so you do not need a router hook.The tag is roughly 3 KB compressed on the wire (10 KB uncompressed), served from Cloudflare's edge. For scale, our own measurement of gtag.js came to about 150 KB compressed. That difference is a small performance win you collect at the end of the migration when gtag is gone, and it is the reason the overlap period will temporarily make your pages a little heavier, not lighter.
One privacy behavior to know before you compare numbers: GhostMetrics honors Global Privacy Control and Do Not Track by collecting nothing from those browsers. GA4, depending on how your consent setup is wired, may count some of those visitors. This is a real source of small gaps between the tools.
Take the event list you exported in step 1 and sort it into three piles: events you actively use in decisions, events that are automatic noise, and events nobody has looked at in a year. Migrate the first pile, drop the third. GA4's automatic events (page views, scrolls, outbound clicks, file downloads, site search) are collected out of the box in GA4 and are not created for you in GhostMetrics, so decide which of them you still want and add them deliberately. Scroll depth is the exception: it is already in the dashboard as a funnel.
Declarative: add data-gm-event to any element and clicks on it are recorded. A single delegated document listener does the work, so buttons rendered after page load, by a client-side router, a modal or a widget, are tracked without re-binding anything.
<a href="/pricing" data-gm-event="pricing-click">See pricing</a>
<button data-gm-event="signup-click">Create account</button>
Programmatic: call the tracker from your own code. This is the equivalent of gtag('event', ...) and the right choice for events that are not clicks, such as a form that validated and submitted.
// GA4
gtag('event', 'generate_lead', { form_id: 'contact', value: 40 });
// GhostMetrics
window.ghostmetrics.track('generate_lead', { section: 'contact' });
Notice what dropped out: GA4 accepted arbitrary parameters and a numeric value. GhostMetrics stores the event name, the page path, any session UTM, and a single metadata field called section. If your old events carried five parameters, decide which one becomes section and which ones become part of the event name. A pragmatic pattern is to encode the distinction in the name itself: signup-click-header and signup-click-footer instead of one signup_click with a location parameter. Our guide to custom events without Google Analytics goes deeper on naming.
Your existing campaign links do not need to change. GhostMetrics reads utm_source, utm_medium and utm_campaign from the landing URL, keeps the first set it sees in sessionStorage for that tab, and attaches it to every later pageview and event in the session. If your links use utm_term or utm_content, they stay valid for other tools but those two values are not stored. The UTM parameters guide covers naming conventions worth standardizing while you are here.
Two to four weeks is the right window for most sites. It gives you at least two complete weekly cycles, and it should include one of every recurring thing you do: a newsletter send, a campaign, a product release.
Bounce rate deserves a specific warning. GhostMetrics counts a bounce as a single-page session in that tab, the classic definition. GA4 replaced bounce rate with engagement rate, where a session is engaged if it lasts 10 seconds, has a conversion, or has two or more pageviews. The two are not convertible into each other, so do not try to reconcile them; pick one going forward and note the switch date.
When the reconciliation is stable, the removal is quick, but do it in an order that does not create a gap.
gtag('config', ...) calls from your layout, or delete the GA4 tag from Google Tag Manager if that is how it was loaded. Search the codebase for the measurement ID (the G- string) to catch strays in templates and third-party embeds.A cookieless tool is not a lighter GA4. It is a different product with a smaller job description, and pretending otherwise leads to regret in month three. Here is the honest list.
And to be fair to GA4, it is genuinely the right tool where those things drive the business: paid acquisition on Google's ecosystem, large ecommerce stores, product analytics that need user-level joins. It is free, and its data model is powerful. The question is whether you use that power. If your weekly review consists of "how many visits, which pages, which sources, did the signup button get clicked", you are paying with a consent banner, a 150 KB script and a confusing interface for reports you barely open. A side-by-side of the wider field lives in Google Analytics vs Plausible vs GhostMetrics.
GhostMetrics is cookieless web analytics we run on this site. The free plan is free forever: one website, unlimited pageviews, real-time dashboard, every view, full history, and no card. That is enough to run the whole parallel-test step without paying anything.
Need several sites or a public dashboard URL? Pro is $9.99/mo flat with unlimited pageviews and unlimited websites (fair-use ceiling of 250), with a 30-day free trial: a card starts the trial, nothing is charged for 30 days, and you can cancel anytime. Raw export as CSV or JSON is on every plan, including free, so you are never locked out of your own data.
Start free, install in one tag See the live demoDisclosure: GhostMetrics is built by Null Agency and we use it on this site, so we are not a neutral party about our own product. We have kept the claims to what the free and paid plans actually do, and pointed to Google Analytics where it genuinely fits better. Details of third-party products, including GA4 retention settings and export limits, can change; check Google's current documentation before you rely on them.