Google Analytics 4 does support offline data import.
But most implementations aren’t compatible with it — not because GA4 is limited, but because the tracking foundations weren’t designed with offline reconciliation in mind.
And offline import in GA4 is nothing like Universal Analytics.
If you don’t understand the data model shift, you’ll never get attribution, merging, or enrichment to work properly.
This guide explains everything in detail:
- What GA4 offline import actually is
- The only reconciliation key GA4 accepts
- Why your current implementation is almost certainly not compatible
- How to design a tracking architecture that supports online → offline fusion
- How to use purchase_id as event_id for conversions
- How to build the full client → server → CRM → GA4 import pipeline
- What Google’s documentation doesn’t tell you
Let’s go deep.
1. What Offline Import Really Means in GA4
Offline import in GA4 is not about “creating events that happened elsewhere.”
GA4 can already collect server-side hits via the Measurement Protocol (MP).
Instead, offline import is designed for enriching events that already exist online.
Examples:
- Adding margin or internal product attributes after a purchase
- Adding CRM campaign information after lead qualification
- Adding call-center conversion outcomes
- Adding store data for in-store purchases
- Adding refund or payment information
- Adding corrected transaction amounts after reconciliation
This is a merge operation, not a “new event” process.
GA4’s data import system looks like this:
Online Event (with event_id)
↓
Offline File or API Import (same event_id)
↓
GA4 matches the two → merges → enriched event
If GA4 cannot match the offline record to an online event, it simply creates a new isolated event that has:
- no attribution
- no session
- no campaign data
- no user lifetime context
In other words: useless for marketing analytics.
2. The GA4 Data Model: Why Offline Import Needs a Perfect Key
GA4 has an event-based model.
Every hit is an event.
Every event has parameters.
There is no session-level or hit-level merging mechanism.
GA4 is strict because it uses an indexing engine internally.
That means:
For GA4 to merge an offline import with an existing event,
it needs a perfect, unique, immutable key.
And in GA4, that key is:
→ event_id
Not:
- user_id
- client_id
- transaction_id
- pseudo_id
- timestamp
- order_number
Only event_id works.
The offline import engine in GA4 literally uses event_id as the primary key.
If event_id matches → GA4 enriches.
If event_id doesn’t match → GA4 creates a brand-new event.
No fuzzy matching.
No alternative.
No fallback.
No smart mapping.
3. “But My GA4 Doesn’t Have an event_id” — Exactly. That’s the Problem.
GA4 does not generate an event_id for you.
It expects you to generate it.
Most implementations don’t generate an event_id at all:
- GTM client-side? → No event_id by default
- gtag? → No event_id by default
- Shopify (native GA4) → No event_id by default
- WooCommerce plugins → No event_id by default
- Server-side GTM → No event_id unless you send one
- Backend APIs → No event_id
So 99% of GA4 setups cannot do real offline reconciliation.
This is why most “offline conversions” fail or end up as isolated events in GA4.
4. The Rules for event_id (How GA4 Uses It Internally)
GA4 expects:
✔ One event_id per event
Every hit must have a unique event_id.
Two hits with the same event_id are treated as duplicates → one is discarded.
✔ event_id must be stored somewhere outside GA4
You need it later for offline imports.
✔ event_id must be identical online and offline
Same exact string.
Same casing.
Same characters.
No transformations.
✔ event_id cannot be rebuilt unless you created it from deterministic data
If you don’t store it → you cannot import offline.
5. How to Generate event_id (Client-Side, Server-Side, Hybrid)
Client-side (JavaScript)
const event_id = crypto.randomUUID();
gtag("event", "purchase", {
event_id: event_id,
transaction_id: "A12345",
value: 200,
currency: "USD"
});
Google Tag Manager (web) – custom variable
function() {
return crypto.randomUUID();
}
Use that variable as event_id in each GA4 event tag.
Server-side (GTM SS or MP)
Two scenarios:
Scenario 1 — You are forwarding client events
→ Reuse the event_id from the client payload.
Scenario 2 — You are generating events server-side
→ Generate a new event_id per event:
{
"client_id": "123.456",
"events": [{
"name": "purchase",
"params": {
"event_id": "uuid-xxxxxx",
"transaction_id": "A12345"
}
}]
}
6. The Special Case: Using purchase_id (or order_id) as event_id
This is one of the only safe shortcuts.
If:
- your purchase order_id is unique
- the same value exists online + offline
- the same order_id is stored in your backend
Then:
You can reuse order_id as event_id for purchase events.
Example:
Online:
event_id = "ORDER_12345"
purchase_id = "ORDER_12345"
Offline:
event_id = "ORDER_12345"
margin = 42.5
store_location = "Paris 09"
GA4 merges the two → perfect offline enrichment.
This works ONLY for purchase events because they naturally carry a stable identifier.
It does NOT work for:
- add_to_cart
- generate_lead
- view_item
- begin_checkout
- any other event
Those events do not have a natural stable ID.
7. The Full Architecture: How to Build an Online → Offline Reconciliation Pipeline
Here’s the complete, real-world architecture used by companies that actually succeed with GA4 offline import.
Step 1 — Generate an event_id for each event
Client or server, but consistent.
Step 2 — Send the event to GA4 (web, app, server-side)
Include event_id.
Step 3 — Forward event_id to your backend
Store it with your business identifiers.
Example table:
| event_id | transaction_id | user_id | timestamp | amount |
|---|---|---|---|---|
| uuid1 | ORDER_12345 | 98 | 2025-02-01 | 120.00 |
Step 4 — Collect offline data (store, CRM, call-center)
Associate it with the correct transaction_id or other business ID.
Step 5 — Build an import file
CSV or API Admin import.
Structure:
event_name,event_id,margin,store_id,payment_method
purchase,ORDER_12345,41.8,STORE_09,POS
Step 6 — Upload via GA4 Data Import
GA4 detects matching event_id → merges → enriched event.
Full attribution stays intact.
8. What Happens If You Don’t Have event_id?
You can still import offline data.
GA4 will accept it.
But it will never merge with online events.
You get:
- events with no source/medium
- no funnel
- no attribution
- no user-level metrics
- no LTV
- no link to existing users
- no session context
- broken reporting
In practice, offline import becomes useless.
9. Other Types of GA4 Data Import (and Their Keys)
GA4 supports several import types with different reconciliation keys.
Item Data (product enrichment)
Key: item_id
source=https://support.google.com/analytics/answer/13833010
User Data (CRM segmentation)
Key: user_id
source=https://support.google.com/analytics/answer/13096259
Cost Data (Meta, TikTok, Snap, Pinterest…)
Keys: source + medium + campaign + date
source=https://support.google.com/analytics/answer/13703687
Event Data (offline)
Key: event_id
source=https://support.google.com/analytics/answer/13306719
These imports are not interchangeable.
Only event import uses event_id.
10. Common Mistakes That Break Offline Import
Mistake 1 — Using transaction_id instead of event_id
Doesn’t merge.
Mistake 2 — Using user_id as event_id
Duplicates or merges unrelated hits.
Mistake 3 — Not storing event_id in the backend
Impossible to import offline later.
Mistake 4 — Generating an event_id that uses timestamp
Offline timestamps never match exactly → mismatch → no merge.
Mistake 5 — Generating UUID only on the server
Then client event and server event don’t match → duplication.
Mistake 6 — Relying on GTM auto-generated parameters
GTM does not generate event_id for you.
11. Final Recommendations (The “If You Do Nothing Else, Do This” Section)
If you want GA4 to support offline reconciliation:
1. Add event_id to every event
Not just purchases.
2. Store event_id in your backend
If you don’t store it, you cannot reconcile.
3. For purchases, reuse order_id as event_id if possible
It’s stable and perfect for offline sales.
4. Use Measurement Protocol server-side when needed
But keep the same event_id.
5. Build a deterministic mapping table for import
Event_id → transaction_id → CRM → offline data.
6. Never rely on user_id or client_id for reconciliation
GA4 simply doesn’t allow it.
12. Conclusion: GA4 Offline Import Works — If You Design for It
GA4 is strict, but powerful.
Offline import works beautifully only if your online tracking was designed to support it.
That means:
- event_id for each event
- proper persistence in your backend
- deterministic mapping
- consistent values between systems
- careful import logic
- correct GA4 schema usage
Without event_id → offline stays isolated.
With event_id → GA4 becomes a true online/offline unified dataset.
If you’re implementing server-side tagging, building CRM integrations, or preparing advanced e-commerce analytics, this is one of the most important architectural decisions you’ll ever make in GA4.