Migrate from Google Analytics 4 to Statable
Switching from GA4? You don't have to start at zero. Statable pulls historical reports from any GA4 property you own, stores them next to events your tracking script collects from now on, and stitches the two together so the dashboard shows one continuous timeline.
This guide walks through the import end-to-end: prerequisites, the click-by-click flow, what comes across, what stays native-only, how to replace or remove imported data later.
(screenshot placeholder, Site settings → Import landing screen)
Before you start
You need:
- A Statable site with the tracking script installed. Imported data lives next to native data, so the site must exist first. New here? Start with Add your first website and Install the tracking script.
- A Google account with Edit access to the GA4 property you want to import. Statable requests the
analytics.readonlyscope. Viewer-level permissions are sometimes refused at consent time. - Patience for API quota. Google enforces a hard 10,000-token-per-day limit per GA4 property. A high-traffic site spanning multiple years can take more than one day. The job picks up where it left off after the quota window resets.
The Import tab is only available on paid plans. Hobby tier (.edu / .github.io / .gitlab.io) doesn't show the menu item.
What is imported
Statable pulls aggregated daily reports from GA4, not raw event-level data, because Google does not expose raw events through the Admin API for ordinary properties. That's enough to reconstruct every dashboard metric except the few items in the native-only section.
The flow
The whole flow lives in Site settings → Import. No other entry points.
(screenshot placeholder, Site settings sidebar with Import highlighted)
Step 1, open the Import tab
Empty state shows "No imported data yet" with one button: Import from GA. The button starts the OAuth handshake on the backend.
Step 2, authorize Google
Clicking Import from GA redirects to Google's consent screen. Statable asks for the https://www.googleapis.com/auth/analytics.readonly scope and nothing else. Read-only, no write or admin permissions.
After approval, Google redirects back to Statable. The backend stores OAuth tokens against your account, then bounces you to the Import tab with ?connection_id=N in the URL. The setup dialog opens automatically.
(screenshot placeholder, Google consent screen with the read-only scope)
Step 3, pick a GA4 property
The dialog opens on "Import data from GA". Two fields:
- GA property. Dropdown of every GA4 property your Google account can read. Statable auto-selects the first. The list comes from the GA4 Admin API. If you don't see what you expect, check account permissions in Google.
- Date range. Two radio options:
- Import all available data (default). Pulls every day the property has data for, from earliest record to today.
- Choose a custom date range. A two-month calendar opens. Click start, then end. Both endpoints are inclusive.
Helper text under the property selector reminds you: We use read-only access.
(screenshot placeholder, Import dialog with property + date range)
Step 4, start the import
Click Import. The dialog closes, a toast confirms "Import started successfully", and the import lands in a table on the same page.
The job runs as a background worker. You can safely close the tab or browser window. The import keeps going server-side and resumes on its own after each daily quota reset.
Step 5, watch progress (or don't)
The Imports table polls every 5 seconds while a job runs. Each row shows:
| Column | What it means |
|---|---|
| Import source | Property name + a spinner while running, a check mark when done |
| Date Range | The window you picked in Step 3 |
| Progress | Up to: <date> is the latest day Statable has finished importing. Advances as days complete |
| Actions | Cancel button (visible only while running), Remove button (after completion) |
A blue info banner sits above the table while the import runs:
This may take some time. Large imports can take hours to process. You can safely leave this page while the import runs.
When done, Statable shows an "Import completed" toast and the spinner switches to a check mark. Data is immediately visible in every report that supports mixed data (list below).
(screenshot placeholder, running import row with progress indicator)
What's imported
Statable queries 12 dimensions plus a geo cube from the GA4 property, day by day:
| Dimension | GA4 source | Goes into |
|---|---|---|
| Page paths | pagePath | Top Pages, Folders¹, page-level breakdowns |
| Entry pages | landingPage | Entry Pages report |
| Browsers | browser | Tech Insights → Browsers |
| Operating systems | operatingSystem | Tech Insights → OS |
| Device categories | deviceCategory | Tech Insights → Devices |
| Sources | sessionSource | Traffic Sources → Sources |
| Channels | sessionDefaultChannelGroup | Traffic Sources → Channels |
| Mediums | sessionMedium | Traffic Sources → UTM Mediums |
| Campaigns | sessionCampaignName | Traffic Sources → UTM Campaigns |
| UTM content | sessionManualAdContent | Traffic Sources → UTM Contents |
| UTM term | sessionManualTerm | Traffic Sources → UTM Terms |
| Country / Region / City | countryId, region, city | Geo Analytics |
Metrics on every dimension: active users → Visitors, sessions, screen page views → Pageviews, average session duration → Session Duration, bounce rate.
¹ Folders are reconstructed from imported page paths automatically.
What's native-only
Some reports can't use imported data because GA4 either doesn't export the field or the metric is Statable-specific. Until you collect enough native data, these stay empty for the imported period:
- Exit Pages. GA4 doesn't expose per-page exit rates through the API.
- Status Codes / Errors. HTTP response codes come from your tracking snippet, not GA4.
- Scroll depth. GA4 doesn't export it. Imported pages show
0. - Engagement Time. GA4 reports only session-level
averageSessionDuration(which Statable maps to Session Duration). Engagement Time is reconstructed from the SDK's heartbeat protocol, so it stays empty for imported days. - Custom Events and Custom Properties (
prop_*). Sent by your own tracking calls, no GA4 equivalent. - Goals. Statable goals are evaluated on native events. Conversions you tracked in GA4 don't carry over.
- Real-time view. Last-30-minute counters need live events.
How mixed data shows in the dashboard
Statable splits the timeline at the day your tracking script first sent data. Call this Stats Start:
- Before Stats Start. Every supported report fills in from imported data.
- From Stats Start onward. Every report fills in from native events, with the full feature set (custom events, goals, scroll depth, engagement time).
When a date range straddles both sides, Statable runs both queries and merges them. Sums (Visitors, Sessions, Pageviews) are added. Averages (Bounce Rate, Session Duration) are weighted by sessions, so a quiet imported month doesn't dilute a busy native week and vice versa.
If a date range falls entirely before Stats Start, only imported data is queried. The dashboard makes no visual distinction. Chart and tables look identical.
One filter at a time on imported data
Reports that mix native + imported data accept a single filter (e.g. Country = Germany, or Page contains /blog/). Stacking two filters such as Country + Browser is a native-only feature. Set two filters and imported rows drop out of the report. The filter dropdown only lists fields the import understands: page, entry page, source, channel, browser, device, OS, country, region, city, the five UTMs.
Replacing an existing import
To re-import a property (different date range, fix a permissions issue, rotate a token), open the Import tab and click Import from GA again. Because data already exists, Statable opens a confirmation dialog:
Replace existing GA import. You already have data imported from Google Analytics. Importing again will remove the previously imported data and replace it with the new date range.
Click Continue to go through the OAuth flow and pick a fresh property + date range. Statable deletes the previously imported rows during the import job, so during the run the imported period appears empty until the new data lands.
Removing imported data
To delete imported data without re-importing, click the trash icon in the completed import row:
Remove GA import. This will remove all data imported from Google Analytics for the selected date range. This action cannot be undone.
Type remove into the input field and click Remove import. Statable issues a DELETE against the imported tables and resets the site's import flags. The dashboard reverts to native-only data immediately.
A success dialog confirms: GA import removed.
Cancelling a running import
Click the X next to a running import. A dialog asks:
Stop GA import? The current import will be stopped. Any data already imported will remain available.
Click Stop import. Statable cancels the worker, leaves whatever was already written in place, and the row switches to a non-running state. Start a fresh import any time after.
Troubleshooting
I clicked Import from GA and Google says I don't have permission
The OAuth scope Statable requests is analytics.readonly. If your Google account is only a Marketer or Viewer at the GA4 account level, Google sometimes refuses the consent. Ask the GA4 admin to grant you Editor access (or higher) on the property, then restart.
The property I want isn't in the dropdown
The list comes from the GA4 Admin API for the Google account you authorized. If a property is missing, you most likely authorized the wrong Google account, or the property belongs to a different account altogether. Sign out of Google in the OAuth window and start again.
The progress hasn't moved for an hour
Statable retries on transient GA4 API errors and pauses when the per-property quota is exhausted (10,000 tokens/day). For large imports, the worker can spend a chunk of the day waiting for quota to reset. The job is not stuck. It just won't have anything to show until tomorrow.
Will my dashboard be empty during the import?
Native data continues to flow as normal. Imported data lands as each daily chunk completes. Today and Yesterday are populated immediately by your live tracking. The long historical tail fills in over hours or days.
Can I keep GA4 running in parallel while I evaluate Statable?
Yes. Both can collect from the same site at the same time. They don't interfere. Many teams run GA4 alongside Statable for a month before turning GA4 off.
Can I import from Universal Analytics (UA)?
No. Google retired the UA API in mid-2024. The Statable importer only speaks to the GA4 Data and Admin APIs.
How accurate is the imported data versus raw GA4?
The metrics Statable imports are the same numbers GA4 returns through its Reporting API. Discrepancies versus the GA4 UI are the same ones you'd see comparing the GA4 UI to the GA4 API directly, usually small thresholding differences on low-traffic properties and timezone handling.
What about Custom Dimensions or User Properties from GA4?
Statable doesn't import them. Custom event properties only land natively. Once your tracking sends window.statable.t('Event', { plan: 'pro' }), the prop_plan filter shows up in the dashboard automatically.
After the import
- Set up Goals matching the conversions you measured in GA4, see Goals. Goals only fire on native events, so they start counting from the moment you create them.
- Recreate Custom Events that matter, see Custom events.
- Configure a Public Dashboard to share traction publicly, see Public dashboard & sharing.
- Cancel GA4 when you're confident Statable has the data you need. No rush. Keeping both running has no downside.
Ready to take control of your web analytics? Try Statable free for 30 days — no credit card required, full feature access, GDPR-compliant by default. Start your free trial or view a live demo.