# How to Integrate Retool with Google Ads

- Tool: Retool
- Difficulty: Advanced
- Time required: 45 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Google Ads by creating a REST API Resource using Google Ads API OAuth 2.0 with a developer token and client credentials. Build search campaign performance dashboards using GAQL (Google Ads Query Language) to query campaign metrics, keyword-level data, and ad group analytics — giving PPC teams faster reporting than Google Ads' native interface.

## Build a Google Ads Reporting and Management Panel in Retool

Google Ads' native interface provides powerful but fragmented reporting — campaign data is in one view, keyword data in another, and comparing performance across multiple client accounts requires switching between accounts. PPC managers and marketing analysts need cross-account dashboards: all campaigns sorted by ROAS in one table, keyword-level click share and quality score for all active ad groups, budget utilization tracking showing which campaigns are on pace to overspend or underspend this month. Retool lets you build these custom views against the Google Ads API.

The Google Ads API uses GAQL — Google Ads Query Language — a SQL-like syntax specifically designed for ad performance reporting. Queries select metrics and dimensions from Google Ads' resource types: campaign, ad_group, ad_group_keyword_view, search_term_view, and many others. All API requests are made to a per-account HTTPS endpoint with POST to /googleads/v17/customers/{customer_id}/googleAds:search.

The most valuable Retool use case for Google Ads is a keyword performance command center for PPC managers. They can see keyword-level impressions, clicks, CTR, average CPC, Quality Score, and conversion rate across all campaigns in a single sortable Table — with the ability to filter to specific campaigns, ad groups, or match types. Anomalies (sudden CTR drops, Quality Score declines) that would take minutes to find in Google Ads' interface become immediately visible.

## Before you start

- A Google Ads account with active campaigns (test accounts work for API setup but have no real data)
- A Google Ads API developer token (apply at https://ads.google.com/nav/selectaccount then API Center — basic access level is sufficient for most reporting use cases)
- A Google Cloud project with the Google Ads API enabled and OAuth 2.0 client credentials (client ID and client secret)
- An OAuth 2.0 refresh token obtained by authorizing the Google Ads API for your Google account
- Your Google Ads customer ID (the 10-digit ID in the format XXX-XXX-XXXX visible in Google Ads top right)

## Step-by-step guide

### 1. Obtain Google Ads API developer token and OAuth credentials

The Google Ads API requires three authentication components: a developer token, OAuth 2.0 client credentials, and a user OAuth token.

Step 1 — Developer token: Log into your Google Ads manager account (MCC). Navigate to Tools & Settings → Setup → API Center. Apply for API access if you haven't already. A test developer token is available immediately for testing against test accounts. Production access (real account data) requires applying for basic or standard access (approval takes 1–5 business days).

Step 2 — Google Cloud OAuth credentials: Go to https://console.cloud.google.com. Create a project or use an existing one. Enable the 'Google Ads API' in APIs & Services → Library. Navigate to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID. Select Web Application. Add https://oauth2.googleapis.com and your Retool URL as authorized redirect URIs. Download the client JSON to get your client_id and client_secret.

Step 3 — OAuth refresh token: Use Google's OAuth 2.0 playground (https://developers.google.com/oauthplayground) or a local script to authorize the Google Ads API scope (https://www.googleapis.com/auth/adwords) for your Google account. Exchange the authorization code for an access token and refresh token. Copy the refresh_token.

Store all credentials in Retool Configuration Variables: GOOGLE_ADS_DEVELOPER_TOKEN (marked as secret), GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET (secret), GOOGLE_ADS_REFRESH_TOKEN (secret), and GOOGLE_ADS_CUSTOMER_ID.

**Expected result:** You have all four Google Ads API credentials stored in Retool Configuration Variables: developer token, client ID, client secret, refresh token, and customer ID.

### 2. Set up token refresh and create the Google Ads REST API Resource

Google Ads OAuth 2.0 access tokens expire after 1 hour. You need a mechanism to refresh them before building queries.

Create a Retool JavaScript query called refreshGoogleAdsToken (set to run on page load): POST https://oauth2.googleapis.com/token with body:
grant_type=refresh_token&client_id={{ retoolContext.configVars.GOOGLE_ADS_CLIENT_ID }}&client_secret={{ retoolContext.configVars.GOOGLE_ADS_CLIENT_SECRET }}&refresh_token={{ retoolContext.configVars.GOOGLE_ADS_REFRESH_TOKEN }}

This returns a fresh access_token valid for 1 hour. Store this in a Retool variable: setVariable('googleAdsAccessToken', response.access_token).

Now create the REST API Resource: Resources tab → Add Resource → REST API.

Name: Google Ads API

Base URL: https://googleads.googleapis.com

Authentication: Bearer Token → {{ googleAdsAccessToken.value }} (references the variable set by the token refresh query).

Add headers:
- developer-token: {{ retoolContext.configVars.GOOGLE_ADS_DEVELOPER_TOKEN }}
- login-customer-id: {{ retoolContext.configVars.GOOGLE_ADS_MANAGER_ACCOUNT_ID }} (only needed if accessing via MCC — omit if accessing a standalone account directly)

Click Create Resource.

```
// JavaScript query: refreshGoogleAdsToken
// POST https://oauth2.googleapis.com/token
// (Use a separate REST API Resource pointed at oauth2.googleapis.com for this query)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: [
    `grant_type=refresh_token`,
    `client_id=${retoolContext.configVars.GOOGLE_ADS_CLIENT_ID}`,
    `client_secret=${retoolContext.configVars.GOOGLE_ADS_CLIENT_SECRET}`,
    `refresh_token=${retoolContext.configVars.GOOGLE_ADS_REFRESH_TOKEN}`
  ].join('&')
});
const data = await response.json();
return data.access_token;
```

**Expected result:** The Google Ads REST API Resource is created with the Bearer token referencing your refreshed access token. The developer-token header is configured. The resource is ready for GAQL queries.

### 3. Write GAQL queries for campaign and keyword performance

Google Ads API uses POST requests with GAQL query in the request body. All reporting queries go to:
POST /v17/customers/{{ retoolContext.configVars.GOOGLE_ADS_CUSTOMER_ID }}/googleAds:search

The request body is a JSON object with a single query field containing the GAQL string.

Create a getCampaignPerformance query: POST /v17/customers/{customerId}/googleAds:search with body:
{ "query": "SELECT campaign.id, campaign.name, campaign.status, campaign.advertising_channel_type, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.conversions, metrics.cost_micros, metrics.roas FROM campaign WHERE campaign.status = 'ENABLED' AND segments.date DURING LAST_30_DAYS ORDER BY metrics.cost_micros DESC LIMIT 50" }

GAQL key concepts:
- Resources: campaign, ad_group, keyword_view, search_term_view, campaign_budget
- Metrics: metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros (divide by 1,000,000 to get dollars), metrics.conversions, metrics.roas
- Segments: segments.date, segments.device, segments.day_of_week
- Date filters: WHERE segments.date DURING LAST_7_DAYS (also: LAST_30_DAYS, THIS_MONTH, LAST_MONTH)
- Status filters: WHERE campaign.status = 'ENABLED' (values: ENABLED, PAUSED, REMOVED)

Create a getKeywordPerformance query with a GAQL query targeting the ad_group_criterion resource with ad_group_criterion.type = 'KEYWORD'.

```
// GAQL query for keyword performance
// POST /v17/customers/{customerId}/googleAds:search
{
  "query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.quality_info.quality_score, ad_group.name, campaign.name, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.conversions, metrics.cost_micros FROM ad_group_criterion WHERE ad_group_criterion.type = 'KEYWORD' AND ad_group_criterion.status = 'ENABLED' AND segments.date DURING LAST_30_DAYS ORDER BY metrics.impressions DESC LIMIT 200"
}
```

**Expected result:** The getCampaignPerformance query returns an array of campaign objects with metrics. The getKeywordPerformance query returns keywords with Quality Scores and performance metrics.

### 4. Transform GAQL responses and build the campaign dashboard UI

Google Ads API GAQL responses have a nested structure. Each row in the response is an object with nested resource and metrics objects. Create a transformer to flatten this for the Table component.

The response format from GAQL is: { results: [ { campaign: { id, name, status }, metrics: { impressions, clicks, ctr, average_cpc, cost_micros, conversions } }, ... ] }

Create a campaignTransformer to flatten and compute derived metrics. Then bind to a Table component.

For the keyword Quality Score dashboard, create a separate Table with color-coded Quality Score badges using Retool's Table column formatting: set the quality_score column to tag/badge type with rules — red for 1-4, yellow for 5-6, green for 7-10.

Add summary Stat components above the Table:
- Total Spend: sum of all campaign cost values
- Total Clicks: sum of clicks
- Average CTR: weighted average by impressions
- Total Conversions: sum of conversions

For a Chart comparing campaigns by spend vs. ROAS, use Retool's Chart component (Plotly.js). Create a scatter plot with x = ROAS and y = spend, with bubble size representing impressions. This visualizes the efficiency/scale relationship across all campaigns at a glance.

```
// Transformer for GAQL campaign response
const results = data?.results || [];
return results.map(row => {
  const campaign = row.campaign || {};
  const metrics = row.metrics || {};
  const budget = row.campaignBudget || {};

  const costDollars = (metrics.costMicros || 0) / 1000000;
  const ctr = parseFloat(metrics.ctr || 0) * 100;
  const avgCpc = (metrics.averageCpc || 0) / 1000000;
  const roas = metrics.conversionsValue > 0
    ? (metrics.conversionsValue / costDollars).toFixed(2)
    : '0.00';

  return {
    id: campaign.id,
    name: campaign.name,
    status: campaign.status,
    channel: campaign.advertisingChannelType || '',
    impressions: parseInt(metrics.impressions || 0).toLocaleString(),
    clicks: parseInt(metrics.clicks || 0).toLocaleString(),
    ctr: `${ctr.toFixed(2)}%`,
    avg_cpc: `$${avgCpc.toFixed(2)}`,
    spend: `$${costDollars.toFixed(2)}`,
    spend_raw: costDollars,
    conversions: parseFloat(metrics.conversions || 0).toFixed(1),
    roas: roas,
    conv_rate: metrics.clicks > 0
      ? `${((metrics.conversions / metrics.clicks) * 100).toFixed(2)}%`
      : '0.00%'
  };
});
```

**Expected result:** The campaigns Table shows all active campaigns with spend, CTR, and ROAS metrics formatted as currency and percentages. Quality Score badges are color-coded in the keywords Table.

### 5. Build the search term report and multi-account support

Create a getSearchTerms query: POST /v17/customers/{customerId}/googleAds:search with GAQL:
{ "query": "SELECT search_term_view.search_term, campaign.name, ad_group.name, metrics.impressions, metrics.clicks, metrics.ctr, metrics.cost_micros, metrics.conversions FROM search_term_view WHERE segments.date DURING LAST_30_DAYS AND metrics.impressions > 10 ORDER BY metrics.cost_micros DESC LIMIT 500" }

Filter the search term results in a transformer to identify 'waste' terms: high cost (> $5) with zero conversions. Display these in a separate 'Negative Keywords Candidates' Table to help PPC managers identify irrelevant queries.

For multi-account support (MCC/manager accounts), create a getAccessibleCustomers query: GET /v17/customers:listAccessibleCustomers. This returns all Google Ads accounts accessible to the authenticated user. Build a customer Select component and dynamically replace the customer ID in all query paths based on the selection.

For the budget pacing calculation, fetch campaign budget data: SELECT campaign.name, campaign_budget.amount_micros FROM campaign WHERE campaign.status = 'ENABLED'. Compute pacing status in a transformer using the current day of month and total days in the current month.

For PPC teams managing multiple Google Ads accounts across complex agency or enterprise setups, combining GAQL reporting with automated budget alerts, bid change tracking, and internal dashboard distribution, RapidDev's team can help architect the complete Retool solution.

```
// Transformer: identify negative keyword candidates
const terms = data?.results || [];
const formatted = terms.map(row => ({
  term: row.searchTermView?.searchTerm || '',
  campaign: row.campaign?.name || '',
  ad_group: row.adGroup?.name || '',
  impressions: parseInt(row.metrics?.impressions || 0),
  clicks: parseInt(row.metrics?.clicks || 0),
  cost: (row.metrics?.costMicros || 0) / 1000000,
  conversions: parseFloat(row.metrics?.conversions || 0)
}));

// Flag waste: cost > $2, conversions = 0, impressions > 20
const negativeCandidates = formatted.filter(t =>
  t.cost > 2 && t.conversions === 0 && t.impressions > 20
);

return {
  all_terms: formatted,
  negative_candidates: negativeCandidates.sort((a, b) => b.cost - a.cost),
  total_waste: negativeCandidates.reduce((sum, t) => sum + t.cost, 0).toFixed(2)
};
```

**Expected result:** The search terms Table shows all queries triggering your ads with a negative keyword candidates tab pre-filtered to high-cost, zero-conversion terms. Multi-account switching works via the customer Select dropdown.

## Best practices

- Store all Google Ads API credentials (developer token, client ID, client secret, refresh token) in Retool Configuration Variables marked as secret — never hardcode them in resource configurations or JavaScript queries.
- Implement OAuth 2.0 token refresh on a 50-minute schedule using a Retool Workflow — Google Ads access tokens expire after 1 hour and stale tokens cause dashboard failures during active sessions.
- Always use the segments.date DURING LAST_30_DAYS or explicit date range filters in GAQL queries — queries without date segments return all-time totals which are slower and usually not what dashboards need.
- Limit GAQL results to 1000 rows maximum and use OFFSET for pagination — Google Ads API has a default result limit and very large queries can time out on accounts with many campaigns or keywords.
- Divide metrics.cost_micros by 1,000,000 in your transformer to convert to dollar amounts — Google Ads API returns all monetary values in micros (millionths) of the account currency, which is easy to overlook.
- For multi-account MCC setups, always add the login-customer-id header pointing to the MCC ID and query individual leaf account IDs in the endpoint path — omitting the login-customer-id header causes 401 errors when accessing accounts through a manager.
- Cache campaign and ad group reference data (IDs and names) for 10 minutes — this data changes infrequently and repeated lookups waste quota on stable reference data.
- Apply for basic access to the Google Ads API before going to production — a test developer token blocks access to real account data and the approval process for basic access requires a few business days.

## Use cases

### Build a keyword performance and Quality Score dashboard

Create a Retool dashboard showing all active keywords across all campaigns with impressions, clicks, CTR, average CPC, Quality Score, and conversion rate. PPC managers can sort by Quality Score to find underperforming keywords, filter to specific campaigns, and identify keywords with high impressions but low CTR that need ad copy improvement.

Prompt example:

```
Build a Retool keyword performance panel for Google Ads. Show all enabled keywords with: keyword text, match type, campaign, ad group, impressions, clicks, CTR, average CPC, Quality Score (1-10), conversions, and conversion rate. Sort by Quality Score ascending to surface low-quality keywords first. Add campaign filter. Color-code Quality Score: red for 1-4, yellow for 5-6, green for 7-10.
```

### Build a campaign budget utilization and pacing dashboard

Build a Retool panel showing all active Google Ads campaigns with daily budget, spend today, month-to-date spend, budget utilization percentage, and pacing status. Marketing managers can see which campaigns are on track, overpacing (at risk of exhausting budget early), or underpacing (won't spend the full budget by month end).

Prompt example:

```
Build a Retool Google Ads budget pacing dashboard. Show all campaigns with: campaign name, status, daily budget, today's spend, MTD spend, % of monthly budget used, and pacing status (On Track / Overpacing / Underpacing). Compute pacing as: expected spend = (days elapsed / days in month) × monthly budget. If actual > expected × 1.1, show Overpacing in red. Include a total row showing combined budget and spend.
```

### Build a search term report for negative keyword discovery

Create a Retool tool showing the Google Ads search terms that triggered your ads — including terms that are not yet in your keyword list. Identify irrelevant search terms with impressions but no conversions that should be added as negative keywords to reduce wasted spend.

Prompt example:

```
Build a Retool search terms analysis panel. Fetch the last 30 days of search terms from Google Ads. Show: search term, campaign, ad group, impressions, clicks, CTR, cost, conversions. Filter to terms with: cost > $5 AND conversions = 0. Sort by cost descending. Add an 'Add as Negative' button that marks the selected search term for negative keyword review. Export button for the negative keyword list.
```

## Troubleshooting

### PERMISSION_DENIED error with 'Developer token does not have permission to access' message

Cause: A test developer token can only query test accounts, not real Google Ads accounts. Attempting to query a live account with a test token results in a permission denied error.

Solution: Apply for basic access to the Google Ads API in your Google Ads account → Tools & Settings → API Center. Basic access allows querying real account data for production use. Approval typically takes 1–5 business days. In the meantime, create a test Google Ads account (visible in your MCC) to test your Retool integration with real API responses.

### 401 Unauthorized after the dashboard has been open for a while

Cause: Google Ads OAuth 2.0 access tokens expire after 1 hour. The token generated on page load becomes invalid after this period, causing all subsequent API calls to return 401.

Solution: Add a Refresh Token button to your Retool dashboard that re-runs the refreshGoogleAdsToken query and updates the access token variable. For an automated solution, set the refreshGoogleAdsToken query to run on a 50-minute timer using Retool's query periodic trigger setting. This keeps the token fresh without requiring user interaction.

```
// Set query to auto-refresh:
// In query settings, enable 'Run automatically'
// Set interval to 3000000 ms (50 minutes)
```

### GAQL query returns 'INVALID_ARGUMENT' with 'Cannot select segment X with resource Y' error

Cause: Some GAQL dimensions and segments are incompatible with certain resource types. Google Ads API enforces resource compatibility rules — not all fields can be combined in a single query.

Solution: Check Google's GAQL resource compatibility tables in the official documentation at https://developers.google.com/google-ads/api/fields/. For common issues: segments.device cannot be combined with campaign_budget resource; metrics.search_impression_share requires campaign or ad_group resources, not keyword_view. Split incompatible fields into separate queries if needed.

```
// GAQL compatibility example:
// Valid: SELECT campaign.name, metrics.clicks FROM campaign
// Invalid: SELECT campaign_budget.amount_micros, metrics.clicks FROM campaign
// (budget fields and metrics cannot be selected from the same resource)
```

### GAQL metrics return zero values for date ranges despite campaigns running

Cause: The customer ID in the API endpoint path may belong to a manager account (MCC) rather than a leaf customer account. Manager accounts do not have performance metrics directly — you must query leaf account IDs.

Solution: Verify you are querying a leaf customer account (one that runs actual campaigns) rather than a manager account. Use GET /v17/customers:listAccessibleCustomers to see all accessible accounts. Manager account IDs (MCCs) appear in the list but have no direct metrics. Use the leaf account customer IDs for performance queries.

```
// Correct endpoint for leaf account:
// POST /v17/customers/LEAF_CUSTOMER_ID/googleAds:search
// NOT: POST /v17/customers/MCC_MANAGER_ID/googleAds:search
```

## Frequently asked questions

### Does Retool have a native Google Ads connector?

Retool has a native Google Analytics connector, but not a dedicated Google Ads connector. For Google Ads, you connect via a REST API Resource using Google Ads API OAuth 2.0 authentication with a developer token. The setup is more complex than most API integrations due to the developer token requirement and OAuth flow, but once configured you have full access to GAQL for campaign, keyword, and ad group reporting.

### What is GAQL and why do I need to learn it for Google Ads in Retool?

GAQL (Google Ads Query Language) is Google's SQL-like query language for the Ads API. Unlike REST APIs that expose resources as endpoints, Google Ads API uses GAQL queries sent via POST to a single search endpoint. GAQL queries specify which resource to query (campaign, keyword_view, etc.), which fields to select, and how to filter and sort. Learning basic GAQL is necessary to fetch any Google Ads data — there are no pre-built action dropdowns like in native connectors.

### Do I need a test developer token or basic access to query real Google Ads data?

You need basic access (or standard access) to the Google Ads API to query real campaign data. A test developer token — which you get immediately upon application — only works with test Google Ads accounts created specifically for API testing. To query your actual campaign performance data, apply for basic access in Google Ads → Tools & Settings → API Center. Approval typically takes 1–5 business days and requires describing your use case.

### How do I query multiple Google Ads accounts from one Retool dashboard?

For manager account (MCC) access, add the login-customer-id header set to your MCC customer ID in the REST API Resource configuration. Then query individual leaf account IDs by dynamically changing the customer ID in the endpoint path: /v17/customers/{{ select_account.value }}/googleAds:search. Populate the account selector by calling GET /v17/customers:listAccessibleCustomers which returns all accounts your credentials can access.

### What is the Google Ads API rate limit?

Google Ads API rate limits vary by developer token access level. Basic access allows up to 15,000 requests per day and 1,000 per minute. Standard access has higher limits. Rate limit errors return HTTP 429 with a Retry-After header. For Retool dashboards, use query caching (5–10 minutes) for performance reports that don't change frequently — this dramatically reduces API call volume while keeping the dashboard responsive.

---

Source: https://www.rapidevelopers.com/retool-integrations/google-ads
© RapidDev — https://www.rapidevelopers.com/retool-integrations/google-ads
