Skip to main content
This guide walks you through connecting Google BigQuery to Conversion and setting up your first sync.

Before You Begin

Before connecting BigQuery, we recommend the following:
  • Create a dedicated service account — Set up a service account specifically for Conversion with read-only access to the tables you need. This limits exposure and makes it easy to revoke access if needed.
  • Use a read replica if possible — Running queries against a replica prevents sync operations from impacting your production database.
  • Sync only the data you need — Select only the columns you’ll use, and always filter with last_sync_time to limit results to changed rows.
Queries that return millions of rows should not run more frequently than once per day. Large, frequent syncs can impact both your BigQuery costs and Conversion performance.

Step 1: Create a Service Account

Conversion connects to BigQuery using a service account. Create one in the Google Cloud Console.
  1. Go to IAM & Admin → Service Accounts in the Google Cloud Console
  2. Click Create Service Account
  3. Enter a name (e.g., “Conversion Sync”) and description
  4. Click Create and Continue
  5. Add the following roles:
    • BigQuery User — Allows running queries
    • BigQuery Job User — Allows creating query jobs
    • BigQuery Data Viewer — Allows reading table data (grant this on specific datasets if you want to limit access)
  6. Click Continue, then Done
  7. Find your new service account in the list, click the three dots under Actions, and select Manage keys
  8. Click Add Key → Create new key
  9. Select JSON and click Create
  10. Save the downloaded JSON file — you’ll need it when connecting to Conversion
For tighter security, grant BigQuery Data Viewer only on the specific datasets you want Conversion to access, rather than at the project level.

Step 2: Allow Conversion’s IP Addresses

If your BigQuery project uses VPC Service Controls or other network restrictions, allow connections from Conversion’s IP addresses:
RegionIP Addresses
US35.239.90.161, 35.188.167.166, 34.56.101.43, 34.122.97.230, 34.29.176.66, 35.226.154.44

Step 3: Connect BigQuery to Conversion

  1. In Conversion, go to Settings → Integrations → Data Warehouse
  2. Click Add Integration and select Google BigQuery
  3. Enter a name for this connection (e.g., “Production BigQuery”)
  4. Paste the contents of your service account JSON file into the Service Account Credentials field
  5. Click Connect
Conversion will verify the connection. If successful, you’re ready to create syncs.

Step 4: Create a Sync

After connecting, create a sync to start pulling data:
  1. Click Add Sync
  2. Select the destination type:
    • Contacts — Create or update contact records
    • Custom Objects — Create or update custom object records (with optional relationships)
    • Events — Record events on contacts
  3. For Custom Objects, select the specific object type
  4. Enter your SQL query (see examples below)
  5. Click Run Query to preview results
  6. Set the sync schedule (how often to run)
  7. Click Enable

Writing Queries for BigQuery

Contact Sync

SELECT 
  email,
  first_name,
  last_name,
  title AS job_title,
  phone,
  city
FROM `project.dataset.users`
WHERE updated_at > TIMESTAMP('{{last_sync_time}}')

Custom Objects (Without Relationships)

To sync objects without relating them to contacts, omit the email column:
SELECT 
  id,
  name,
  status,
  plan_tier,
  monthly_price
FROM `project.dataset.subscriptions`
WHERE updated_at > TIMESTAMP('{{last_sync_time}}')

Custom Objects with Relationships

To sync custom objects and their relationships to contacts in a single query, include the contact’s email and use JSON_OBJECT for relationship-specific fields:
SELECT 
  -- Object fields
  p.id,
  p.name,
  p.sku,
  p.category,
  p.price,
  
  -- Contact to relate this object to
  u.email,
  
  -- Relationship-specific fields
  JSON_OBJECT(
    'role', up.role,
    'quantity', up.quantity,
    'purchased_at', UNIX_SECONDS(up.purchased_at)
  ) AS relationshipFields
  
FROM `project.dataset.user_products` up
JOIN `project.dataset.products` p ON up.product_id = p.id
JOIN `project.dataset.users` u ON up.user_id = u.id
WHERE up.updated_at > TIMESTAMP('{{last_sync_time}}')
In this example:
  • Object fields (id, name, sku, category, price) are stored on the Product object
  • email identifies which contact to create a relationship with
  • relationshipFields contains fields stored on the relationship itself (this contact’s role, quantity, etc.)
If multiple rows share the same object id but have different email values, Conversion creates one object with multiple relationships—one per contact.

Events

SELECT 
  u.email,
  'purchase_completed' AS event_name,
  o.created_at AS timestamp,
  CAST(o.id AS STRING) AS message_id,
  o.total_amount,
  o.product_name,
  o.currency
FROM `project.dataset.orders` o
JOIN `project.dataset.users` u ON o.user_id = u.id
WHERE o.created_at > TIMESTAMP('{{last_sync_time}}')

BigQuery SQL Reference

Converting Timestamps

Conversion expects Unix timestamps for date/time fields. Use UNIX_SECONDS() to convert BigQuery TIMESTAMP or DATETIME values:
SELECT 
  email,
  UNIX_SECONDS(created_at) AS created_at,
  UNIX_SECONDS(last_login) AS last_login
FROM `project.dataset.users`
WHERE updated_at > TIMESTAMP('{{last_sync_time}}')

Using last_sync_time

The last_sync_time variable is a Unix timestamp. To compare it against a BigQuery TIMESTAMP column, wrap it in the TIMESTAMP() function:
WHERE updated_at > TIMESTAMP('{{last_sync_time}}')
Or convert your column to Unix seconds instead:
WHERE UNIX_SECONDS(updated_at) > {{last_sync_time}}

Building Nested Objects with JSON_OBJECT

BigQuery doesn’t support dot notation for creating nested objects. Use JSON_OBJECT to build nested structures like relationshipFields:
JSON_OBJECT(
  'role', role_column,
  'quantity', quantity_column,
  'started_at', UNIX_SECONDS(started_at_column)
) AS relationshipFields

Handling NULLs

Use COALESCE or IFNULL to provide default values:
SELECT 
  email,
  COALESCE(first_name, '') AS first_name,
  IFNULL(phone, '') AS phone
FROM `project.dataset.users`

Casting Types

Use CAST to convert between types:
SELECT 
  CAST(user_id AS STRING) AS id,
  CAST(score AS INT64) AS lead_score
FROM `project.dataset.users`

Querying Across Datasets

Use fully-qualified table names to join across datasets:
SELECT 
  u.email,
  o.order_id
FROM `project.users_dataset.users` u
JOIN `project.orders_dataset.orders` o ON u.id = o.user_id

Troubleshooting

”Permission denied” errors

Ensure your service account has the required roles:
  • BigQuery User
  • BigQuery Job User
  • BigQuery Data Viewer (on the relevant datasets)

“Could not connect” errors

Check that Conversion’s IP addresses are allowed if you use VPC Service Controls or firewall rules.

Sync taking too long

  • Ensure you’re filtering by last_sync_time to reduce rows
  • Select only the columns you need
  • Consider reducing sync frequency for large datasets
  • Use partitioned tables if your data is time-based

Duplicate data appearing

If you’re using time-buffered queries (subtracting from last_sync_time to catch edge cases), Conversion handles duplicates automatically based on the unique key (email for contacts, id for objects, message_id for events).

Frequently Asked Questions

At minimum, the service account needs BigQuery User, BigQuery Job User, and BigQuery Data Viewer roles. For tighter security, grant Data Viewer only on specific datasets rather than the entire project.
No. Conversion only reads from BigQuery. The service account only needs read permissions.
BigQuery charges for the amount of data scanned by your queries. To minimize costs: select only the columns you need, filter with last_sync_time, and consider partitioned tables.
If you sync a custom object with an email that doesn’t exist in Conversion, we create the contact automatically. You can enrich that contact’s profile through a separate contacts sync.