Customer-managed BigQuery

Customer-managed — “Your BigQuery” — is the self-serve
BigQuery model: you keep the data in your own
Google Cloud project and grant Twelfth read-only access. It’s inbound and
read-only, reached from Settings → Integrations → Google BigQuery.

The connection is configuration only. Twelfth stores the project, dataset and
location — nothing else. There is no secret to upload and none is stored:
access rides a dedicated Google service account that you grant read-only IAM
roles inside your own project. Revoke those roles and Twelfth can no longer read
anything, immediately, without touching Twelfth at all.

Owners and admins only

Only workspace owners and admins can connect, validate, or change a warehouse
connection, and BigQuery must be enabled for your workspace first (see the
BigQuery overview).

What you’ll need

Before you start, have these to hand:

  • Your GCP project id (e.g. my-project) — the project that will run the
    queries and be billed for them.
  • The BigQuery dataset that holds your serving tables (e.g. warehouse_au).
  • The dataset’s location
    (e.g. australia-southeast1). This must match the dataset’s real location
    exactly.
  • Permission in Google Cloud to grant two IAM roles — on the dataset and on the
    project.

How Twelfth connects

You keep the data in your own Google Cloud project. Twelfth connects with a
dedicated Google service account and you grant that account read-only access.
Twelfth never receives, stores, or asks for a key, password, or JSON credential —
the identity lives on Twelfth’s side and the grant lives on yours.

Set up the connection

The connect page walks through five steps. You can leave and come back — the
saved connection, its last validation result, and your table selection persist.

1 · Where does the warehouse live?

Confirm the page offers Your BigQuery. If it says Twelfth managed, the
connection is already owned and operated by Twelfth and the setup fields are
intentionally unavailable.

2 · Point at the project and dataset

Enter three values and choose Save connection:

Field Example Rules
GCP project id my-project Lowercase, starts with a letter, 6–30 chars — a valid GCP project id
Dataset warehouse_au Letters, numbers and underscores
Location australia-southeast1 The dataset’s real BigQuery location

Saving stores this configuration against your workspace. It does not yet
prove anything can be read — that’s the next step. If you later edit the values,
choose Update connection.

3 · Grant this principal read-only access

Twelfth shows the service-account principal to grant access to — copy it with
the copy button. Grant it exactly two roles:

Role Where you grant it Why
roles/bigquery.dataViewer On the dataset Read the serving tables and their metadata
roles/bigquery.jobUser On the project Run the query jobs (they run on your project’s billing)
Least privilege

These are the only two roles Twelfth needs, and both are read-only. dataViewer
lets Twelfth read; jobUser lets Twelfth run the SELECT that does the reading.
Grant dataViewer on the dataset (not the whole project) to keep the scope
tight. If the principal shows as pending, your dedicated service account is
issued when BigQuery is enabled for your workspace — grant access once it
resolves.

Jump straight to Google Cloud

Once you’ve entered your project and dataset, the connect page shows Open
project IAM
and Open dataset in BigQuery links that deep-link into the
Google Cloud console for your project — grant jobUser (and add the principal)
in IAM, and grant dataViewer from the dataset’s Sharing → Permissions.

To open the console by hand, swap your own ids into these URLs:

# Project IAM — grant jobUser, add the principal
https://console.cloud.google.com/iam-admin/iam?project=YOUR_PROJECT

# Dataset in BigQuery — grant dataViewer via Sharing → Permissions
https://console.cloud.google.com/bigquery?project=YOUR_PROJECT&d=YOUR_DATASET&page=dataset

4 · Prove the grants

Choose Run validation. Twelfth runs three staged checks, cheapest first —
each proves exactly one grant, so a failure points straight at the missing role:

Check What it proves Fails when
Run query jobs in the project A dry-run SELECT 1 — the principal can create jobs roles/bigquery.jobUser is missing on the project
Read the dataset The dataset’s metadata is readable roles/bigquery.dataViewer is missing, or the location is wrong
Discover serving tables The expected webapp_* tables are found, with row counts The dataset doesn’t hold the serving contract, or earlier grants aren’t in place

Later checks are skipped once an earlier one fails, so you fix one grant at a
time. The result is saved to the connection, so the page shows your last
validation when you return.

5 · Choose the serving tables

Validation discovers the tables and their row counts. Tick the ones you want
Twelfth to use and choose Save selection. Expand any table to review its
columns, types and descriptions before selecting it. Discovery only ever
shows allowlisted webapp_* tables (see What Twelfth reads),
and your selection can only narrow that list — it can never widen access
beyond the allowlist.

What Twelfth reads

Discovery is deliberately narrow. Even if you grant dataViewer on a dataset
that holds many tables, Twelfth only ever surfaces the serving contract — a
fixed allowlist of webapp_* end tables. Anything outside this list is invisible
to Twelfth and can’t be discovered, selected, or queried.

The serving-contract tables are:

Table Holds
webapp_sku SKUs — name, department, category, sub-category
webapp_outlet Outlets and their type
webapp_supplier Suppliers
webapp_sku_supplier SKU ↔ supplier links (and which is primary)
webapp_sku_user SKU ↔ user assignments
webapp_sku_performance Per-SKU metrics over time
webapp_category_performance Per-category metrics over time
webapp_supplier_performance Per-supplier metrics over time
webapp_user_performance Per-user metrics over time
webapp_recommendation_price_change Price-change recommendations
webapp_recommendation_purchase_order Purchase-order recommendations
webapp_recommendation_stock_transfer Stock-transfer recommendations

If you don’t already produce the webapp_* contract, see
Transaction inbound, which
reads raw transaction and customer data instead.

How Twelfth queries your warehouse

Every read Twelfth makes goes through one bounded gateway, with the same guards
on every query — the connect page’s query console exercises this exact path:

  • Read-only, single statement. Only a single SELECT (or a WITH … SELECT)
    is allowed. Anything else — multiple statements, INSERT, UPDATE, DELETE,
    CREATE, DROP — is rejected before it ever reaches BigQuery. Twelfth cannot
    write to your warehouse.
  • Cost gate. Every query is dry-run first to estimate bytes processed and
    rejected if it exceeds the cap. BigQuery also enforces a hard
    maximumBytesBilled server-side (default 500 MB), so no query can bill
    beyond the cap even if the estimate is off.
  • Row cap and deadline. Results are capped (10,000 rows by default) and each
    query has a timeout (60s by default).
  • Runs on your billing. Because jobUser is granted on your project, query
    jobs run in your project and appear in your own
    BigQuery job history
    (swap in your project id).

Security and guarantees

  • Read-only, always. Only single-statement SELECT queries run, enforced
    before they reach BigQuery. Twelfth never writes to source systems.
  • Narrow by design. Discovery and queries are confined to the webapp_*
    serving allowlist; a broad dataViewer grant on a mixed dataset can’t leak
    unrelated table names or data into Twelfth.
  • Your identity, your revocation. Remove the two IAM roles from the service
    account and Twelfth loses all access instantly — no Twelfth-side step needed.
  • Location pinned. The dataset location is stored with the connection, so
    reads stay in the region you chose.
  • One connection per workspace. A workspace holds a single live BigQuery
    connection at a time.

Manage or change a connection

Return to Settings → Integrations → Google BigQuery at any time to:

  • Update the project, dataset or location (choose Update connection),
    then re-run validation.
  • Re-run validation after changing IAM grants — for example, after granting a
    role the last run flagged as missing.
  • Change the serving-table selection and save it again.

Troubleshooting

Validation is your map

When something’s wrong, Run validation tells you exactly which grant is
missing — read the first check that fails, not the last.

Symptom Likely cause Fix
“Run query jobs in the project” fails roles/bigquery.jobUser not granted on the project Grant roles/bigquery.jobUser to the shown principal, on the project
“Read the dataset” fails roles/bigquery.dataViewer not granted, or the location is wrong Grant roles/bigquery.dataViewer on the dataset; confirm the location matches the dataset exactly
“Discover serving tables” fails, or finds fewer tables than expected The dataset doesn’t hold the webapp_* serving contract, or the tables are named differently Confirm the dataset is the one that holds your webapp_* end tables
The principal shows “pending” Your dedicated service account hasn’t been issued yet Ask your Twelfth contact to enable BigQuery for the workspace, then reload
A banner says the gateway has no Google credential on this environment The environment isn’t configured for warehouse access yet The form still saves configuration; validation and queries become available once it’s configured
A query is rejected for processing too many bytes The query would scan more than the cost cap Narrow the query (fewer columns, a WHERE filter)