Knowi connects directly to the Google Ads API to pull campaign performance, ad group metrics, keyword data, search terms, and geographic breakdowns into a single analytics platform.
Analyze your Google Ads spend, impressions, clicks, conversions, and ROI alongside data from your other sources ? no manual CSV exports or spreadsheet wrangling needed.
Knowi integrates with the Google Ads API v23 via OAuth 2.0. Once connected, you can pull campaign, ad group, ad, keyword, search term, and geographic performance data using predefined collections or write your own queries using GAQL (Google Ads Query Language).
All data access is read-only. Knowi does not modify your Google Ads campaigns, bids, or settings.
Before connecting, make sure you have the following:
That's it. Knowi handles the API authentication and account discovery automatically ? no developer tokens, customer IDs, or MCC configuration required on your end.
Log in to Knowi and select "Queries" from the left sidebar.
Click on the "New Datasource +" button and select Google Ads from the list of datasources.
Enter a Datasource Name (e.g., "Google Ads - Production").
Click "Connect with Google" to start the OAuth flow. You will be redirected to Google to authorize Knowi to access your Google Ads data with read-only permissions.
After approving, you'll be redirected back to Knowi. The Google Ads Account dropdown will automatically populate with all accounts accessible to your Google account. Each account is shown with its descriptive name and Customer ID. Manager (MCC) accounts are labeled with "(MCC)".
Select the account you want to query and click "Save".
Note: If your Google Ads access token expires or you change your Google password, you will need to reconnect by clicking "Connect with Google" again.
After connecting, create a new query with your Google Ads datasource and select a collection from the dropdown.
Each collection comes with a default GAQL query and Cloud9QL transformations pre-configured. The defaults flatten the nested API response into clean column names and convert cost values from micros to dollars automatically.
Retrieves campaign-level performance metrics with daily date segmentation. Excludes removed campaigns by default.
Fields returned: campaign, campaign_id, status, channel_type, impressions, clicks, cost, conversions, ctr, avg_cpc, date
Default GAQL:
SELECT campaign.id, campaign.name, campaign.status,
campaign.advertising_channel_type, segments.date,
metrics.impressions, metrics.clicks, metrics.cost_micros,
metrics.conversions, metrics.ctr, metrics.average_cpc
FROM campaign
WHERE campaign.status != 'REMOVED'
AND segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select campaign.name as campaign, campaign.id as campaign_id,
campaign.status as status,
campaign.advertisingChannelType as channel_type,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions,
round(metrics.ctr, 4) as ctr,
round(metrics.averageCpc / 1000000, 2) as avg_cpc,
segments.date as date;
Retrieves ad group-level performance metrics grouped by ad group within campaigns.
Fields returned: ad_group, ad_group_id, status, campaign, impressions, clicks, cost, conversions, ctr, avg_cpc, date
Default GAQL:
SELECT ad_group.id, ad_group.name, ad_group.status,
campaign.name, segments.date,
metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions,
metrics.ctr, metrics.average_cpc
FROM ad_group
WHERE ad_group.status != 'REMOVED'
AND segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select adGroup.name as ad_group, adGroup.id as ad_group_id,
adGroup.status as status, campaign.name as campaign,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions,
round(metrics.ctr, 4) as ctr,
round(metrics.averageCpc / 1000000, 2) as avg_cpc,
segments.date as date;
Retrieves individual ad-level performance metrics including ad type and final URLs.
Fields returned: ad_id, ad_type, final_urls, ad_status, ad_group, campaign, impressions, clicks, cost, conversions, ctr, date
Default GAQL:
SELECT ad_group_ad.ad.id, ad_group_ad.ad.type,
ad_group_ad.ad.final_urls, ad_group_ad.status,
ad_group.name, campaign.name, segments.date,
metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions, metrics.ctr
FROM ad_group_ad
WHERE segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select adGroupAd.ad.id as ad_id, adGroupAd.ad.type as ad_type,
adGroupAd.ad.finalUrls as final_urls,
adGroupAd.status as ad_status,
adGroup.name as ad_group, campaign.name as campaign,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions,
round(metrics.ctr, 4) as ctr, segments.date as date;
Retrieves keyword-level performance including match type and quality score.
Fields returned: keyword, match_type, quality_score, ad_group, campaign, impressions, clicks, cost, conversions, ctr, avg_cpc, date
Default GAQL:
SELECT ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
ad_group_criterion.quality_info.quality_score,
ad_group.name, campaign.name, segments.date,
metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions,
metrics.ctr, metrics.average_cpc
FROM keyword_view
WHERE segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select adGroupCriterion.keyword.text as keyword,
adGroupCriterion.keyword.matchType as match_type,
adGroupCriterion.qualityInfo.qualityScore as quality_score,
adGroup.name as ad_group, campaign.name as campaign,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions,
round(metrics.ctr, 4) as ctr,
round(metrics.averageCpc / 1000000, 2) as avg_cpc,
segments.date as date;
Retrieves the actual search queries that triggered your ads, along with performance metrics.
Fields returned: search_term, status, campaign, ad_group, impressions, clicks, cost, conversions, ctr, date
Default GAQL:
SELECT search_term_view.search_term,
search_term_view.status,
campaign.name, ad_group.name, segments.date,
metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions, metrics.ctr
FROM search_term_view
WHERE segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select searchTermView.searchTerm as search_term,
searchTermView.status as status,
campaign.name as campaign, adGroup.name as ad_group,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions,
round(metrics.ctr, 4) as ctr, segments.date as date;
Retrieves performance data broken down by geographic location.
Fields returned: country_id, location_type, campaign, impressions, clicks, cost, conversions, date
Default GAQL:
SELECT geographic_view.country_criterion_id,
geographic_view.location_type,
campaign.name, segments.date,
metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions
FROM geographic_view
WHERE segments.date DURING LAST_30_DAYS
Default Cloud9QL:
select expand(results);
select geographicView.countryCriterionId as country_id,
geographicView.locationType as location_type,
campaign.name as campaign,
metrics.impressions as impressions, metrics.clicks as clicks,
round(metrics.costMicros / 1000000, 2) as cost,
metrics.conversions as conversions, segments.date as date;
For power users who need full control over the data pulled from Google Ads. Write your own GAQL query to access any resource and field combination supported by the Google Ads API.
Required Parameters: * GAQL Query - A valid Google Ads Query Language statement.
The default Cloud9QL flattens the response structure. Modify it to match the fields in your custom query.
Refer to the Google Ads Query Language documentation for the full syntax reference and available resources.
GAQL (Google Ads Query Language) follows a SQL-like SELECT ... FROM ... WHERE format. Below are the key patterns.
SELECT field1, field2, metrics.impressions
FROM resource
WHERE condition
ORDER BY metrics.impressions DESC
LIMIT 100
Use segments.date with DURING for preset date ranges:
WHERE segments.date DURING LAST_30_DAYS
Or use BETWEEN for specific date ranges:
WHERE segments.date BETWEEN '2024-01-01' AND '2024-01-31'
Available date presets:
TODAY, YESTERDAY, LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, THIS_WEEK_MON_TODAY, THIS_WEEK_SUN_TODAY, LAST_WEEK_MON_SUN, LAST_WEEK_SUN_SAT, THIS_MONTH, LAST_MONTH, LAST_BUSINESS_WEEK, THIS_QUARTER, LAST_QUARTER, THIS_YEAR, LAST_YEAR
Add segment fields to break down metrics by device, network, or other dimensions:
SELECT campaign.name, segments.device,
metrics.clicks, metrics.impressions
FROM campaign
WHERE segments.date DURING LAST_7_DAYS
Common segments: segments.device, segments.ad_network_type, segments.day_of_week, segments.hour, segments.conversion_action
WHERE campaign.status = 'ENABLED'
AND metrics.impressions > 100
AND campaign.name LIKE '%Brand%'
After pulling data from Google Ads, use Cloud9QL to transform and enrich the results.
The default Cloud9QL for each collection handles two things automatically:
select expand(results); followed by field aliases flattens the nested structure into clean column names.round(metrics.costMicros / 1000000, 2).You can modify or extend the default Cloud9QL. Some examples:
Calculate ROAS (Return on Ad Spend):
select *, conversions_value / cost as roas;
Filter to high-performing campaigns:
select * where clicks > 100 and ctr > 0.05;
Aggregate by campaign:
select campaign, sum(impressions) as total_impressions,
sum(clicks) as total_clicks,
sum(cost) as total_cost,
sum(conversions) as total_conversions
group by campaign
order by total_cost desc;
Join with CRM data:
select * left join [salesforce_leads] on campaign = lead_source;
Once your query is configured, schedule it to run automatically to keep dashboards current:
Set up alerts to get notified via email, Slack, or webhook when metrics cross thresholds (e.g., CPA exceeds budget, CTR drops below target).
For more information, see Defining Data Execution Strategy.
One of Knowi's key strengths is joining Google Ads data with other sources without ETL. Examples:
Join campaign data with lead and opportunity data for full-funnel ROI analysis:
select * left join [salesforce_opportunities]
on campaign = lead_source;
Join ad performance with product usage or behavioral data:
select * left join [product_usage]
on campaign_id = attribution_campaign;
Combine ad click data with on-site behavior:
select * left join [ga_sessions]
on campaign = traffic_source_campaign;
Match ad spend with actual e-commerce revenue:
select * left join [shopify_orders]
on campaign = utm_campaign;
See Joining Across Multiple Databases for details.
Re-authenticate by clicking "Connect with Google" on the datasource edit page. Ensure the Google Ads scope is granted during the OAuth flow.
If the account dropdown is empty after authentication, your Google account may not have access to any Google Ads accounts. Verify that the Google account you authenticated with has at least read access to a Google Ads account.
Check that your GAQL query uses valid field names for the selected resource. Not all fields can be combined in a single query. Refer to the GAQL field compatibility matrix.
The default Cloud9QL converts cost from micros to dollars automatically. If you're using a Custom GAQL query, add round(metrics.costMicros / 1000000, 2) as cost to your Cloud9QL.
Google Ads API Basic Access allows 15,000 operations per day. Each Knowi query execution counts as one operation. If you hit rate limits, reduce query frequency or consolidate queries.
Google Ads reporting data can have a lag of up to 3 hours for standard metrics and up to 24 hours for conversion data (depending on your conversion tracking setup and attribution window).