GA360 Standard
The Google Analytics 360 export to BigQuery as ten Data Marts: sessions at the hub, with the page views, events and purchases that join them and the locations, devices, traffic sources, users, pages and event details behind them.
A ready-made reporting layer over the Google Analytics 360 export to BigQuery. It turns the daily ga_sessions_* tables into ten analytics-ready tables: sessions, page views, events and purchases, plus the locations, devices, traffic sources, users, pages and event details they point at by hash. Two staging tables sit between the export and most tables: _temp_objects feeds page views, events, pages and event details, and _temp_transactions feeds purchases, on Transactions and on Sessions.
The SQL that builds the tables is part of the model, in references/sql-transformation, with a runbook for the first load and the daily run. It is written for the OWOX Transformations plugin in the BigQuery (GoogleSQL) dialect, and you can adapt it to your needs.
Sessions are the hub, one row per session of the export. Page views, events and purchases join them on date and sessionId together. The dimension tables carry no date: each run appends the same hashes again, so deduplicate them before joining in your own SQL. Revenue is in millionths, as Google's export stores it: divide by 1,000,000.
Example Questions
- Which sources and campaigns bring the
sessionsthat end in a purchase? - Which landing pages bring the most purchase revenue on mobile?
- Which
pagesdo visitors from each country view most?
Devices
The device a session ran on: category, browser and its version, operating system and its version, one row per combination, as the GA 360 export records them. Sessions point here through deviceHash, a FARM_FINGERPRINT of the five values. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
deviceHash | STRING | Device Hash | PK. FARM_FINGERPRINT of the five device values in the order listed here, joined without a separator, with an empty value in place of NULL. Unique within one run; repeats across daily runs. |
deviceCategory | STRING | Device Category | The device category, such as desktop, mobile or tablet. |
browser | STRING | Browser | The browser, such as Chrome or Safari. |
browserVersion | STRING | Browser Version | The version of the browser. |
operatingSystem | STRING | Operating System | The operating system, such as Windows, iOS or Android. |
operatingSystemVersion | STRING | Operating System Version | The version of the operating system. |
Event Info
The category, action and label behind event hits, one row per combination, as the site sent them. Events point here through their pageHash column, which despite its name holds this table's eventHash, a FARM_FINGERPRINT of the three values. Each run adds the combinations of its own window. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
eventHash | STRING | Event Hash | PK. FARM_FINGERPRINT of category, action and label, joined without a separator, with an empty value in place of NULL. Unique within one run; repeats across daily runs. Events carry it as pageHash. |
eventCategory | STRING | Event Category | The event category the site sent. |
eventAction | STRING | Event Action | The event action the site sent. |
eventLabel | STRING | Event Label | The event label the site sent. Empty when the event had none. |
Events
Every event hit of the GA 360 export, one row each, tied to the session it fell in. Join to Sessions on date and sessionId together. Despite its name, pageHash holds the event hash: it joins Event Info, which carries the event's category, action and label. hitId identifies an event: a rerun of the same window gives the same value, a different window does not, and Pageviews numbers its hits separately. time is a timestamp in milliseconds since 1970-01-01 UTC; date is the day in the property's time zone.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
date | DATE | Date | PK. The day of the export table the event was read from, in the property's time zone. |
sessionId | STRING | Session ID | PK. The session the event belongs to: the full visitor ID and the visit ID, joined by _. Join to Sessions on this and date together. FK to Sessions |
hitId | STRING | Hit ID | PK. MD5 of the session ID, the hit's time in the session and its order among the session's events. Stable for a rerun of the same window, not across different windows. |
time | INTEGER | Event Time | Timestamp of the event, in milliseconds since 1970-01-01 UTC: the session start plus the hit's offset. |
events | INTEGER | Events | Always 1. Sum it to count events. |
pageHash | STRING | Event Hash | Despite its name, the event hash: FARM_FINGERPRINT of the event's category, action and label. It joins eventHash in Event Info, not Pages. FK to Event Info |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Sessions | date = date, sessionId = sessionId | N:1 | The session the event fell in. |
| Event Info | pageHash = eventHash | N:1 | The event's category, action and label; the hash repeats across runs. |
Geo
Where a session came from: country, region and city, one row per combination, as the GA 360 export records them. Sessions point here through geoHash, a FARM_FINGERPRINT of the three values. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
geoHash | STRING | Geo Hash | PK. FARM_FINGERPRINT of country, region and city, joined without a separator, with an empty value in place of NULL. Unique within one run; repeats across daily runs. |
country | STRING | Country | The session's country, as the export records it. |
region | STRING | Region | The session's region or state, as the export records it. |
city | STRING | City | The session's city, as the export records it. |
Pages
The pages behind page views: host name, path and title, one row per combination. The path is cut at the first ?, # or ;, so query strings and anchors are dropped. The title is part of the key, so one path with two titles is two pages. Page views point here through pageHash, a FARM_FINGERPRINT of host, path and title. Each run adds the pages of its own window. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
pageHash | STRING | Page Hash | PK. FARM_FINGERPRINT of host name, path and title, joined without a separator, with an empty value in place of NULL. Unique within one run; repeats across daily runs. |
hostName | STRING | Host Name | The host name of the page, such as www.example.com. |
pagePath | STRING | Page Path | The path of the page, cut at the first ?, # or ;. |
pageTitle | STRING | Page Title | The title of the page, as the browser sent it. |
Pageviews
Every page view hit of the GA 360 export, one row each, tied to the session it fell in. Join to Sessions on date and sessionId together, and to Pages on pageHash for the host, path and title: the table holds no page path itself. hitId identifies a page view: a rerun of the same window gives the same value, a different window does not, and Events numbers its hits separately. time is a timestamp in milliseconds since 1970-01-01 UTC; date is the day in the property's time zone.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
date | DATE | Date | PK. The day of the export table the page view was read from, in the property's time zone. |
sessionId | STRING | Session ID | PK. The session the page view belongs to: the full visitor ID and the visit ID, joined by _. Join to Sessions on this and date together. FK to Sessions |
hitId | STRING | Hit ID | PK. MD5 of the session ID, the hit's time in the session and its order among the session's page views. Stable for a rerun of the same window, not across different windows. |
time | INTEGER | Page View Time | Timestamp of the page view, in milliseconds since 1970-01-01 UTC: the session start plus the hit's offset. |
pageview | INTEGER | Pageviews | Always 1. Sum it to count page views. |
pageHash | STRING | Page Hash | FARM_FINGERPRINT of the page's host name, path and title. FK to Pages |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Sessions | date = date, sessionId = sessionId | N:1 | The session the page view fell in. |
| Pages | pageHash = pageHash | N:1 | The host, path and title of the page viewed; the hash repeats across runs. |
Sessions
One row per session of the GA 360 export, with its landing page, engagement, purchases and the keys to its location, device, traffic source and user. A row is identified by date together with sessionId; page views, events and purchases join on both. visitStartTime is in seconds since 1970, and timeOnSite is in whole seconds with the fraction cut off, so a one-hit session shows 0. Purchases are deduplicated the same way as in Transactions. transactionRevenue is in millionths, as Google's export stores it: divide by 1,000,000. cost, impressions and clicks are always 0, slots for ad cost blended in later.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
date | DATE | Date | PK. The day of the export table the session was read from, in the property's time zone. |
sessionId | STRING | Session ID | PK. The full visitor ID and the visit ID, joined by _. Pair it with date: page views, events and purchases join on both. |
landingPage | STRING | Landing Page | Path of the session's first hit marked as an entrance, or of its first hit when none is, cut at the first ?, # or ;. |
landingHost | STRING | Landing Host | Host name of the same hit as landingPage. |
visitStartTime | INTEGER | Session Start Time | When the session started, in seconds since 1970-01-01 UTC, as the export records it. |
visitNumber | INTEGER | Session Number | The visitor's session count as Google Analytics reports it: 1 for a first visit. |
touchpoint | STRING | Touchpoint | Always WEB. |
dataSource | STRING | Data Source | The export the session was read from, as project.dataset.ga_sessions_*. |
hits | INTEGER | Hits | All hits in the session as the export counts them (totals.hits), hit types other than page views and events included. |
pageviews | INTEGER | Pageviews | Number of page view hits in the session. |
events | INTEGER | Events | Number of event hits in the session. |
bounces | INTEGER | Bounces | 1 when the session has at most one hit that is a page view or an interactive event, otherwise 0. |
timeOnSite | INTEGER | Time on Site (seconds) | Time from the session's first hit to its last, in whole seconds with the fraction cut off. 0 for a session with one hit. |
userHash | STRING | User Hash | FARM_FINGERPRINT of the session's client ID; the other user identifiers are empty. When the export has no client ID, every session has the same hash. FK to Users |
geoHash | STRING | Geo Hash | FARM_FINGERPRINT of the session's country, region and city. FK to Geo |
deviceHash | STRING | Device Hash | FARM_FINGERPRINT of the session's device category, browser and version, operating system and version. FK to Devices |
trafficSourceHash | STRING | Traffic Source Hash | FARM_FINGERPRINT of the session's source, medium, campaign, keyword and ad content. FK to Traffic Sources |
transactions | INTEGER | Purchases | Purchases in the session, deduplicated by transaction ID the same way as in Transactions. 0 when none. |
transactionRevenue | FLOAT | Purchase Revenue (millionths) | Revenue of those purchases, multiplied by 1,000,000 as Google's export stores it; divide by 1,000,000 for the amount. 0 when none. |
impressions | INTEGER | Impressions | Always 0. A slot for ad impressions blended in later. |
clicks | INTEGER | Clicks | Always 0. A slot for ad clicks blended in later. |
cost | FLOAT | Cost | Always 0. A slot for ad cost blended in later. |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Geo | geoHash = geoHash | N:1 | Where the session came from; the hash repeats across runs. |
| Devices | deviceHash = deviceHash | N:1 | The device the session ran on; the hash repeats across runs. |
| Traffic Sources | trafficSourceHash = trafficSourceHash | N:1 | The session's source and campaign; the hash repeats across runs. |
| Users | userHash = userHash | N:1 | The browser behind the session, by client ID; one shared hash when the export has none. |
Traffic Sources
The source, medium, campaign, keyword and ad content Google Analytics attributed a session to, one row per combination. They are read as they are from the export's trafficSource record, such as google / organic, (direct) / (none), or the UTM tags of a campaign. Sessions point here through trafficSourceHash, a FARM_FINGERPRINT of the five values. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
trafficSourceHash | STRING | Traffic Source Hash | PK. FARM_FINGERPRINT of source, medium, campaign, keyword and ad content, joined without a separator, with an empty value in place of NULL. Unique within one run; repeats across daily runs. |
source | STRING | Source | Where the session came from, from trafficSource.source, such as google or (direct). |
medium | STRING | Medium | The kind of traffic, from trafficSource.medium, such as organic, cpc, referral or (none). |
campaign | STRING | Campaign | The campaign name, from trafficSource.campaign. |
keyword | STRING | Keyword | The keyword or search term, from trafficSource.keyword. |
adContent | STRING | Ad Content | The ad variant, from trafficSource.adContent. |
Transactions
One row per purchase, deduplicated by transaction ID: when the export records the same ID more than once within the deduplication window (7 days in the runbook's setup), only the earliest is kept, so there is at most one row per ID per deduplication window. transactionRevenue is in millionths, as Google's export stores it: divide by 1,000,000. status is always empty and touchpoint is always WEB; both are slots. Join to Sessions on date and sessionId for the source, device and location behind each order. The purchase counts on Sessions are deduplicated the same way.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
date | DATE | Date | PK. The day of the export table the purchase was read from, in the property's time zone. |
sessionId | STRING | Session ID | PK. The session the purchase was made in: the full visitor ID and the visit ID, joined by _. Join to Sessions on this and date together. FK to Sessions |
transactionId | STRING | Transaction ID | PK. The order ID the site sent with the purchase. At most one row per ID per deduplication window: the earliest. |
transactionRevenue | FLOAT | Revenue (millionths) | Revenue of the purchase, multiplied by 1,000,000 as Google's export stores it; divide by 1,000,000 for the amount. |
status | STRING | Status | Always empty. A slot for an order status from another source. |
touchpoint | STRING | Touchpoint | Always WEB. |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Sessions | date = date, sessionId = sessionId | N:1 | The session the purchase was made in. |
Users
The visitors behind sessions, one row per client ID: the identifier Google Analytics gives a browser, not a person. The model builds a user from clientId alone; the other identifier columns are always empty, slots for other sources. Where the export carries no clientId, as in Google's public sample, every session lands on one user hash and this table holds one row per run. Sessions point here through userHash. The table has no date, so a hash repeats once per run (once per day for daily runs). Count distinct hashes. In your own SQL over these tables, deduplicate it before joining, or rows multiply; OWOX Data Marts reports collapse joined fields per source row.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
userHash | STRING | User Hash | PK. FARM_FINGERPRINT of the six identifiers below, joined without a separator, with an empty value in place of NULL; today the client ID alone. Unique within one run; repeats across daily runs. |
clientId | STRING | Client ID | The export's clientId: one browser. Empty in exports that do not carry it, Google's public sample included. |
userId | STRING | User ID | Always empty. A slot for your own user ID. |
visitorId | STRING | Visitor ID | Always empty. A slot for a visitor ID from another source. |
userPseudoId | STRING | Pseudo User ID | Always empty. A slot for a GA4 pseudo user ID. |
phone | STRING | Phone | Always empty. A slot for a phone number from your CRM. |
email | STRING | Always empty. A slot for an email address from your CRM. |
- 1
Install the Import Model plugin
One plugin, installed once, in your own OWOX workspace.
- 2
Import this model
Point it at this bundle and it creates every data mart above, joins and all.
- 3
Plug in your data and destinations
Connect your own sources and send the results where your team already works.
4. Optional — customize as you wish. Rename a column, drop a mart, add your own: once it is imported it is yours, and nothing here syncs back.
You are booked. The invitation is on its way to , with the calendar invite and the meeting link.