1. Create the table. Create a dataset in the region where the data should live, then the table from the schema file that ships with the template. Partition on event_date and cluster on event_name: almost every query filters on both, and it keeps cost down.
bq --location=europe-west4 mk --dataset my-project:sgtm
bq mk --table \
--schema bigquery-event-tag-schema.json \
--time_partitioning_type DAY \
--time_partitioning_field event_date \
--clustering_fields event_name \
my-project:sgtm.events
You can add your own columns later. The tag only writes the columns it knows, and BigQuery ignores fields the table doesn't have, so an insert never breaks on it. It does mean a field the tag sends is silently dropped until the column exists.
2. Give the container access. The tag writes as the service account your container runs under. Grant that account BigQuery Data Editor on the dataset. Nothing more: no query rights, no project-wide Editor.
bq add-iam-policy-binding \
--member=serviceAccount:<runtime-sa> \
--role=roles/bigquery.dataEditor \
my-project:sgtm
3. Import the template. In the server container: Templates, Tag Templates, Search Gallery, and add BigQuery Event Tag by New North. To run a newer version than the gallery has, import template.tpl from the repository instead.
4. Configure the tag. Only project, dataset and table are required; the rest has sensible defaults. Set Event Name to the built-in {{Event Name}} variable, and User ID to an Event Data variable if you send your own logged-in ID. Fire the tag on a custom trigger where Client Name equals the name of your GA4 client. Events you never want in BigQuery, such as ad impressions at high volume, you exclude in that same trigger.
5. Test and publish. Open Preview in the server container, click a request and check that the tag is under Tags Fired. With Log to console you see the exact row. Streamed rows are queryable within seconds:
SELECT event_timestamp, event_name, user_pseudo_id
FROM `my-project.sgtm.events`
WHERE event_date = CURRENT_DATE()
ORDER BY event_timestamp DESC
LIMIT 20
Publish, then watch your Cloud Run logs for BigQuery insert FAILED. That line means an insert failed twice, and it names the table and the event. Put a log-based alert on it, and you'll know before there's a gap in your data.