[{"data":1,"prerenderedAt":731},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fconnections\u002Fgoogle-analytics-4":3},{"page":4,"navigation":646,"surround":728},{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"body":11,"_type":640,"_id":641,"_source":642,"_file":643,"_stem":644,"_extension":645},"\u002Fdocs\u002Fconnections\u002Fgoogle-analytics-4","connections",false,"","Google Analytics 4","Connect GA4 through its BigQuery export, and understand the tables, settling window and cost controls.",{"type":12,"children":13,"toc":630},"root",[14,39,46,66,75,81,86,148,153,159,288,294,299,437,466,471,477,482,487,493,498,527,533,538,619],{"type":15,"tag":16,"props":17,"children":18},"element","p",{},[19,22,29,31,37],{"type":20,"value":21},"text","GA4's reporting API only returns aggregates. They're capped, sampled over long date ranges, and fold rare values into ",{"type":15,"tag":23,"props":24,"children":26},"code",{"className":25},[],[27],{"type":20,"value":28},"(other)",{"type":20,"value":30},". The only way to get event-level data out of GA4 is its ",{"type":15,"tag":32,"props":33,"children":34},"strong",{},[35],{"type":20,"value":36},"BigQuery export",{"type":20,"value":38},", so that's what Datachef reads. Two things have to exist before you connect.",{"type":15,"tag":40,"props":41,"children":43},"h2",{"id":42},"_1-link-ga4-to-bigquery",[44],{"type":20,"value":45},"1. Link GA4 to BigQuery",{"type":15,"tag":16,"props":47,"children":48},{},[49,51,56,58,64],{"type":20,"value":50},"In GA4, go to ",{"type":15,"tag":32,"props":52,"children":53},{},[54],{"type":20,"value":55},"Admin → Product links → BigQuery links → Link",{"type":20,"value":57},". Choose a Google Cloud project, turn on the daily export (and the streaming export if you want today's data too), and save. The first ",{"type":15,"tag":23,"props":59,"children":61},{"className":60},[],[62],{"type":20,"value":63},"events_YYYYMMDD",{"type":20,"value":65}," table appears about a day later.",{"type":15,"tag":67,"props":68,"children":69},"blockquote",{},[70],{"type":15,"tag":16,"props":71,"children":72},{},[73],{"type":20,"value":74},"The export isn't backfilled. It holds data from the day you link it, and nothing earlier, so link it before you need the history.",{"type":15,"tag":40,"props":76,"children":78},{"id":77},"_2-create-a-service-account",[79],{"type":20,"value":80},"2. Create a service account",{"type":15,"tag":16,"props":82,"children":83},{},[84],{"type":20,"value":85},"In that Google Cloud project, create a service account and give it two roles:",{"type":15,"tag":87,"props":88,"children":89},"table",{},[90,109],{"type":15,"tag":91,"props":92,"children":93},"thead",{},[94],{"type":15,"tag":95,"props":96,"children":97},"tr",{},[98,104],{"type":15,"tag":99,"props":100,"children":101},"th",{},[102],{"type":20,"value":103},"Role",{"type":15,"tag":99,"props":105,"children":106},{},[107],{"type":20,"value":108},"Where",{"type":15,"tag":110,"props":111,"children":112},"tbody",{},[113,135],{"type":15,"tag":95,"props":114,"children":115},{},[116,122],{"type":15,"tag":117,"props":118,"children":119},"td",{},[120],{"type":20,"value":121},"BigQuery Data Viewer",{"type":15,"tag":117,"props":123,"children":124},{},[125,127,133],{"type":20,"value":126},"On the ",{"type":15,"tag":23,"props":128,"children":130},{"className":129},[],[131],{"type":20,"value":132},"analytics_\u003Cproperty id>",{"type":20,"value":134}," dataset",{"type":15,"tag":95,"props":136,"children":137},{},[138,143],{"type":15,"tag":117,"props":139,"children":140},{},[141],{"type":20,"value":142},"BigQuery Job User",{"type":15,"tag":117,"props":144,"children":145},{},[146],{"type":20,"value":147},"On the project that runs the queries",{"type":15,"tag":16,"props":149,"children":150},{},[151],{"type":20,"value":152},"Then download a JSON key for the service account. Job User is the role people usually forget. The connection test runs a free dry-run query, so if the role is missing you'll find out when you save, not at the first sync.",{"type":15,"tag":40,"props":154,"children":156},{"id":155},"connection-fields",[157],{"type":20,"value":158},"Connection fields",{"type":15,"tag":87,"props":160,"children":161},{},[162,178],{"type":15,"tag":91,"props":163,"children":164},{},[165],{"type":15,"tag":95,"props":166,"children":167},{},[168,173],{"type":15,"tag":99,"props":169,"children":170},{},[171],{"type":20,"value":172},"Field",{"type":15,"tag":99,"props":174,"children":175},{},[176],{"type":20,"value":177},"Notes",{"type":15,"tag":110,"props":179,"children":180},{},[181,194,207,223,236,249,262,275],{"type":15,"tag":95,"props":182,"children":183},{},[184,189],{"type":15,"tag":117,"props":185,"children":186},{},[187],{"type":20,"value":188},"Google Cloud project",{"type":15,"tag":117,"props":190,"children":191},{},[192],{"type":20,"value":193},"The project that holds the export dataset",{"type":15,"tag":95,"props":195,"children":196},{},[197,202],{"type":15,"tag":117,"props":198,"children":199},{},[200],{"type":20,"value":201},"Billing project",{"type":15,"tag":117,"props":203,"children":204},{},[205],{"type":20,"value":206},"Leave blank unless the queries should be billed to a different project, for example when the export is shared to you from another project",{"type":15,"tag":95,"props":208,"children":209},{},[210,215],{"type":15,"tag":117,"props":211,"children":212},{},[213],{"type":20,"value":214},"Export dataset",{"type":15,"tag":117,"props":216,"children":217},{},[218],{"type":15,"tag":23,"props":219,"children":221},{"className":220},[],[222],{"type":20,"value":132},{"type":15,"tag":95,"props":224,"children":225},{},[226,231],{"type":15,"tag":117,"props":227,"children":228},{},[229],{"type":20,"value":230},"Service account key",{"type":15,"tag":117,"props":232,"children":233},{},[234],{"type":20,"value":235},"Paste the whole JSON key",{"type":15,"tag":95,"props":237,"children":238},{},[239,244],{"type":15,"tag":117,"props":240,"children":241},{},[242],{"type":20,"value":243},"Sync data from",{"type":15,"tag":117,"props":245,"children":246},{},[247],{"type":20,"value":248},"Defaults to one year ago",{"type":15,"tag":95,"props":250,"children":251},{},[252,257],{"type":15,"tag":117,"props":253,"children":254},{},[255],{"type":20,"value":256},"Days to let a shard settle",{"type":15,"tag":117,"props":258,"children":259},{},[260],{"type":20,"value":261},"Defaults to 3. See below.",{"type":15,"tag":95,"props":263,"children":264},{},[265,270],{"type":15,"tag":117,"props":266,"children":267},{},[268],{"type":20,"value":269},"Days per query",{"type":15,"tag":117,"props":271,"children":272},{},[273],{"type":20,"value":274},"Optional. Leave blank unless you want smaller queries.",{"type":15,"tag":95,"props":276,"children":277},{},[278,283],{"type":15,"tag":117,"props":279,"children":280},{},[281],{"type":20,"value":282},"Max GB scanned per query",{"type":15,"tag":117,"props":284,"children":285},{},[286],{"type":20,"value":287},"A hard ceiling. BigQuery refuses a query it estimates would scan more, instead of billing you for it.",{"type":15,"tag":40,"props":289,"children":291},{"id":290},"tables",[292],{"type":20,"value":293},"Tables",{"type":15,"tag":16,"props":295,"children":296},{},[297],{"type":20,"value":298},"You get one table per export family, not one per day:",{"type":15,"tag":87,"props":300,"children":301},{},[302,323],{"type":15,"tag":91,"props":303,"children":304},{},[305],{"type":15,"tag":95,"props":306,"children":307},{},[308,313,318],{"type":15,"tag":99,"props":309,"children":310},{},[311],{"type":20,"value":312},"Table",{"type":15,"tag":99,"props":314,"children":315},{},[316],{"type":20,"value":317},"Present when",{"type":15,"tag":99,"props":319,"children":320},{},[321],{"type":20,"value":322},"Sync modes",{"type":15,"tag":110,"props":324,"children":325},{},[326,348,383,407],{"type":15,"tag":95,"props":327,"children":328},{},[329,338,343],{"type":15,"tag":117,"props":330,"children":331},{},[332],{"type":15,"tag":23,"props":333,"children":335},{"className":334},[],[336],{"type":20,"value":337},"events",{"type":15,"tag":117,"props":339,"children":340},{},[341],{"type":20,"value":342},"Always",{"type":15,"tag":117,"props":344,"children":345},{},[346],{"type":20,"value":347},"Incremental or full refresh",{"type":15,"tag":95,"props":349,"children":350},{},[351,375,379],{"type":15,"tag":117,"props":352,"children":353},{},[354,360,362,368,369],{"type":15,"tag":23,"props":355,"children":357},{"className":356},[],[358],{"type":20,"value":359},"events_event_params",{"type":20,"value":361},", ",{"type":15,"tag":23,"props":363,"children":365},{"className":364},[],[366],{"type":20,"value":367},"events_items",{"type":20,"value":361},{"type":15,"tag":23,"props":370,"children":372},{"className":371},[],[373],{"type":20,"value":374},"events_user_properties",{"type":15,"tag":117,"props":376,"children":377},{},[378],{"type":20,"value":342},{"type":15,"tag":117,"props":380,"children":381},{},[382],{"type":20,"value":347},{"type":15,"tag":95,"props":384,"children":385},{},[386,397,402],{"type":15,"tag":117,"props":387,"children":388},{},[389,395],{"type":15,"tag":23,"props":390,"children":392},{"className":391},[],[393],{"type":20,"value":394},"events_intraday",{"type":20,"value":396}," (and its child tables)",{"type":15,"tag":117,"props":398,"children":399},{},[400],{"type":20,"value":401},"The streaming export is on",{"type":15,"tag":117,"props":403,"children":404},{},[405],{"type":20,"value":406},"Full refresh only",{"type":15,"tag":95,"props":408,"children":409},{},[410,428,433],{"type":15,"tag":117,"props":411,"children":412},{},[413,419,420,426],{"type":15,"tag":23,"props":414,"children":416},{"className":415},[],[417],{"type":20,"value":418},"users",{"type":20,"value":361},{"type":15,"tag":23,"props":421,"children":423},{"className":422},[],[424],{"type":20,"value":425},"pseudonymous_users",{"type":20,"value":427}," (and their child tables)",{"type":15,"tag":117,"props":429,"children":430},{},[431],{"type":20,"value":432},"The user-data export is on",{"type":15,"tag":117,"props":434,"children":435},{},[436],{"type":20,"value":347},{"type":15,"tag":16,"props":438,"children":439},{},[440,442,448,450,456,458,464],{"type":20,"value":441},"Nested records are flattened to one column per field, so ",{"type":15,"tag":23,"props":443,"children":445},{"className":444},[],[446],{"type":20,"value":447},"device.category",{"type":20,"value":449}," becomes ",{"type":15,"tag":23,"props":451,"children":453},{"className":452},[],[454],{"type":20,"value":455},"device_category",{"type":20,"value":457},". Each repeated field, such as ",{"type":15,"tag":23,"props":459,"children":461},{"className":460},[],[462],{"type":20,"value":463},"event_params",{"type":20,"value":465},", becomes a table of its own with one row per element. It keeps its parent's key columns so you can join back to the event.",{"type":15,"tag":16,"props":467,"children":468},{},[469],{"type":20,"value":470},"This is event-level data, not GA4's reports. There are no pre-computed sessions or channel groupings, so you compute them in SQL. The agent knows the export's schema and can write those queries for you.",{"type":15,"tag":40,"props":472,"children":474},{"id":473},"the-settling-window",[475],{"type":20,"value":476},"The settling window",{"type":15,"tag":16,"props":478,"children":479},{},[480],{"type":20,"value":481},"GA4 keeps adding events to a day's table for up to 72 hours after the day ends. An incremental sync waits until a day has settled before reading it, and then never reads that day again. Data lands a few days late, but it lands once and complete. With the default of 3 days, the table for the 1st is read on the 6th. The extra two days allow for the property's timezone.",{"type":15,"tag":16,"props":483,"children":484},{},[485],{"type":20,"value":486},"A full refresh doesn't wait, because it replaces the whole table each time.",{"type":15,"tag":40,"props":488,"children":490},{"id":489},"keeping-bigquery-costs-down",[491],{"type":20,"value":492},"Keeping BigQuery costs down",{"type":15,"tag":16,"props":494,"children":495},{},[496],{"type":20,"value":497},"BigQuery bills for the bytes a query scans:",{"type":15,"tag":499,"props":500,"children":501},"ul",{},[502,513,518],{"type":15,"tag":503,"props":504,"children":505},"li",{},[506,511],{"type":15,"tag":32,"props":507,"children":508},{},[509],{"type":20,"value":510},"Columns you don't sync aren't scanned",{"type":20,"value":512},", so they aren't billed.",{"type":15,"tag":503,"props":514,"children":515},{},[516],{"type":20,"value":517},"Syncs are filtered by day, so BigQuery skips whole days that aren't needed.",{"type":15,"tag":503,"props":519,"children":520},{},[521,525],{"type":15,"tag":32,"props":522,"children":523},{},[524],{"type":20,"value":282},{"type":20,"value":526}," caps any one query.",{"type":15,"tag":40,"props":528,"children":530},{"id":529},"trying-it-without-a-ga4-property",[531],{"type":20,"value":532},"Trying it without a GA4 property",{"type":15,"tag":16,"props":534,"children":535},{},[536],{"type":20,"value":537},"Google publishes an export of its merchandise store as a public dataset. You can use it to try the connector:",{"type":15,"tag":87,"props":539,"children":540},{},[541,556],{"type":15,"tag":91,"props":542,"children":543},{},[544],{"type":15,"tag":95,"props":545,"children":546},{},[547,551],{"type":15,"tag":99,"props":548,"children":549},{},[550],{"type":20,"value":172},{"type":15,"tag":99,"props":552,"children":553},{},[554],{"type":20,"value":555},"Value",{"type":15,"tag":110,"props":557,"children":558},{},[559,575,587,603],{"type":15,"tag":95,"props":560,"children":561},{},[562,566],{"type":15,"tag":117,"props":563,"children":564},{},[565],{"type":20,"value":188},{"type":15,"tag":117,"props":567,"children":568},{},[569],{"type":15,"tag":23,"props":570,"children":572},{"className":571},[],[573],{"type":20,"value":574},"bigquery-public-data",{"type":15,"tag":95,"props":576,"children":577},{},[578,582],{"type":15,"tag":117,"props":579,"children":580},{},[581],{"type":20,"value":201},{"type":15,"tag":117,"props":583,"children":584},{},[585],{"type":20,"value":586},"Any project of yours with BigQuery enabled. A free BigQuery sandbox project works.",{"type":15,"tag":95,"props":588,"children":589},{},[590,594],{"type":15,"tag":117,"props":591,"children":592},{},[593],{"type":20,"value":214},{"type":15,"tag":117,"props":595,"children":596},{},[597],{"type":15,"tag":23,"props":598,"children":600},{"className":599},[],[601],{"type":20,"value":602},"ga4_obfuscated_sample_ecommerce",{"type":15,"tag":95,"props":604,"children":605},{},[606,610],{"type":15,"tag":117,"props":607,"children":608},{},[609],{"type":20,"value":243},{"type":15,"tag":117,"props":611,"children":612},{},[613],{"type":15,"tag":23,"props":614,"children":616},{"className":615},[],[617],{"type":20,"value":618},"2020-11-01",{"type":15,"tag":16,"props":620,"children":621},{},[622,624,628],{"type":20,"value":623},"The data ends in early 2021, so you have to set ",{"type":15,"tag":32,"props":625,"children":626},{},[627],{"type":20,"value":243},{"type":20,"value":629},". With the default of one year ago, nothing is found.",{"title":8,"searchDepth":631,"depth":631,"links":632},2,[633,634,635,636,637,638,639],{"id":42,"depth":631,"text":45},{"id":77,"depth":631,"text":80},{"id":155,"depth":631,"text":158},{"id":290,"depth":631,"text":293},{"id":473,"depth":631,"text":476},{"id":489,"depth":631,"text":492},{"id":529,"depth":631,"text":532},"markdown","content:docs:2.connections:5.google-analytics-4.md","content","docs\u002F2.connections\u002F5.google-analytics-4.md","docs\u002F2.connections\u002F5.google-analytics-4","md",[647],{"title":648,"_path":649,"children":650},"Welcome","\u002Fdocs",[651,652,662,682,698,705,715],{"title":648,"_path":649},{"title":653,"_path":654,"children":655},"Getting started","\u002Fdocs\u002Fgetting-started",[656,659],{"title":657,"_path":658},"Quickstart","\u002Fdocs\u002Fgetting-started\u002Fquickstart",{"title":660,"_path":661},"Key concepts","\u002Fdocs\u002Fgetting-started\u002Fconcepts",{"title":663,"_path":664,"children":665},"Connecting data","\u002Fdocs\u002Fconnections",[666,669,672,675,678,679],{"title":667,"_path":668},"Overview","\u002Fdocs\u002Fconnections\u002Foverview",{"title":670,"_path":671},"Sync settings","\u002Fdocs\u002Fconnections\u002Fsync-settings",{"title":673,"_path":674},"Salesforce","\u002Fdocs\u002Fconnections\u002Fsalesforce",{"title":676,"_path":677},"Marketo","\u002Fdocs\u002Fconnections\u002Fmarketo",{"title":9,"_path":5},{"title":680,"_path":681},"PostgreSQL and MySQL","\u002Fdocs\u002Fconnections\u002Fpostgres-mysql",{"title":683,"_path":684,"children":685},"Analysis","\u002Fdocs\u002Fanalysis",[686,689,692,695],{"title":687,"_path":688},"Asking questions","\u002Fdocs\u002Fanalysis\u002Fask-a-question",{"title":690,"_path":691},"SQL editor","\u002Fdocs\u002Fanalysis\u002Fsql-editor",{"title":693,"_path":694},"Charts","\u002Fdocs\u002Fanalysis\u002Fcharts",{"title":696,"_path":697},"Tabs and sharing","\u002Fdocs\u002Fanalysis\u002Ftabs-and-sharing",{"title":699,"_path":700,"children":701},"Models","\u002Fdocs\u002Fmodels",[702],{"title":703,"_path":704},"Working with models","\u002Fdocs\u002Fmodels\u002Foverview",{"title":706,"_path":707,"children":708},"AI agents","\u002Fdocs\u002Fai-agents",[709,712],{"title":710,"_path":711},"Claude connector","\u002Fdocs\u002Fai-agents\u002Fclaude-connector",{"title":713,"_path":714},"Tools","\u002Fdocs\u002Fai-agents\u002Ftools",{"title":716,"_path":717,"children":718},"Administration","\u002Fdocs\u002Fadministration",[719,722,725],{"title":720,"_path":721},"People and roles","\u002Fdocs\u002Fadministration\u002Fpeople-and-roles",{"title":723,"_path":724},"Sign-in and SSO","\u002Fdocs\u002Fadministration\u002Fsign-in-and-sso",{"title":726,"_path":727},"Security","\u002Fdocs\u002Fadministration\u002Fsecurity",[729,730],{"_path":677,"title":676},{"_path":681,"title":680},1792546942928]