Overview
Google Ads Query Language (GAQL) is the query language used by the Google Ads API to retrieve reporting data and resource metadata. It resembles SQL but operates on a fixed set of resource types rather than arbitrary tables. Understanding GAQL is essential for pulling performance data, auditing campaigns, and building automated optimizations with Cogny.
API endpoint: GoogleAdsService.SearchStream (streaming) or GoogleAdsService.Search (paged)
Syntax
Formal Grammar
query = SELECT field_list FROM resource_name
[ WHERE condition_list ]
[ ORDER BY field_name [ ASC | DESC ] ]
[ LIMIT positive_integer ]
[ PARAMETERS param_list ]
field_list = field_name { , field_name }
condition_list = condition { AND condition }
condition = field_name operator value
param_list = param_name = param_value { , param_name = param_value }
Clauses
| Clause | Required | Description |
|---|
SELECT | Yes | Fields to return (resource fields, metrics, segments) |
FROM | Yes | Single resource type to query |
WHERE | No | Filter conditions joined by AND (no OR support) |
ORDER BY | No | Sort by one field, ASC or DESC |
LIMIT | No | Maximum number of rows to return |
PARAMETERS | No | Query-level parameters (e.g., include_drafts = true) |
Example
SELECT
campaign.name,
metrics.impressions,
metrics.clicks,
metrics.cost_micros
FROM campaign
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.impressions DESC
LIMIT 50
Resource Types (FROM Clause)
Campaign Management
| Resource | Description |
|---|
campaign | Campaign settings, status, bidding, budget |
campaign_budget | Shared and campaign-level budgets |
campaign_criterion | Campaign-level targeting criteria (locations, languages, etc.) |
campaign_bid_modifier | Bid adjustments at campaign level |
bidding_strategy | Portfolio bidding strategies |
Ad Groups & Ads
| Resource | Description |
|---|
ad_group | Ad group settings, status, targeting |
ad_group_ad | Ads within ad groups (RSA, ETA, etc.) |
ad_group_ad_asset_view | Asset-level performance for responsive ads |
ad_group_criterion | Keywords, audiences, and other criteria in ad groups |
ad_group_bid_modifier | Bid adjustments at ad group level |
Performance Views
| Resource | Description |
|---|
keyword_view | Keyword-level performance metrics |
search_term_view | Actual search queries that triggered ads |
landing_page_view | Landing page performance (expanded/unexpanded URLs) |
geographic_view | Performance by geographic location |
location_view | Performance by targeted/excluded location |
age_range_view | Performance by age range demographic |
gender_view | Performance by gender demographic |
user_location_view | Performance by user's physical location |
display_keyword_view | Display network keyword performance |
topic_view | Display/video topic targeting performance |
managed_placement_view | Managed placement performance |
Conversion & Attribution
| Resource | Description |
|---|
conversion_action | Conversion action configuration |
customer_conversion_goal | Conversion goals and optimization settings |
Account & Extensions
| Resource | Description |
|---|
customer | Account-level settings and descriptive info |
asset | Account assets (sitelinks, callouts, images, etc.) |
asset_group | Performance Max asset groups |
asset_group_asset | Assets within asset groups |
extension_feed_item | Legacy extension feed items |
Change History
| Resource | Description |
|---|
change_status | Recent changes to account entities |
change_event | Detailed change history with old/new values |
Common Fields
Campaign Fields
| Field | Type | Description |
|---|
campaign.id | INT64 | Unique campaign ID |
campaign.name | STRING | Campaign name |
campaign.status | ENUM | ENABLED, PAUSED, REMOVED |
campaign.advertising_channel_type | ENUM | SEARCH, DISPLAY, SHOPPING, VIDEO, PERFORMANCE_MAX, MULTI_CHANNEL |
campaign.advertising_channel_sub_type | ENUM | Further channel subtype |
campaign.bidding_strategy_type | ENUM | TARGET_CPA, TARGET_ROAS, MAXIMIZE_CONVERSIONS, MAXIMIZE_CONVERSION_VALUE, MANUAL_CPC, ENHANCED_CPC, TARGET_IMPRESSION_SHARE |
campaign.campaign_budget | RESOURCE | Budget resource name |
campaign.start_date | DATE | Campaign start date (YYYY-MM-DD) |
campaign.end_date | DATE | Campaign end date (YYYY-MM-DD) |
campaign.serving_status | ENUM | Actual serving status (SERVING, NONE, ENDED, PENDING, SUSPENDED) |
campaign.target_cpa.target_cpa_micros | INT64 | Target CPA in micros |
campaign.target_roas.target_roas | DOUBLE | Target ROAS as a ratio (e.g., 3.5 = 350%) |
Ad Group Fields
| Field | Type | Description |
|---|
ad_group.id | INT64 | Unique ad group ID |
ad_group.name | STRING | Ad group name |
ad_group.status | ENUM | ENABLED, PAUSED, REMOVED |
ad_group.type | ENUM | SEARCH_STANDARD, DISPLAY_STANDARD, SHOPPING_PRODUCT_ADS, etc. |
ad_group.cpc_bid_micros | INT64 | Default CPC bid in micros |
ad_group.target_cpa_micros | INT64 | Ad group-level target CPA |
Ad Fields
| Field | Type | Description |
|---|
ad_group_ad.ad.id | INT64 | Unique ad ID |
ad_group_ad.ad.type | ENUM | RESPONSIVE_SEARCH_AD, EXPANDED_TEXT_AD, RESPONSIVE_DISPLAY_AD, etc. |
ad_group_ad.ad.final_urls | STRING (repeated) | Landing page URLs |
ad_group_ad.status | ENUM | ENABLED, PAUSED, REMOVED |
ad_group_ad.ad.responsive_search_ad.headlines | MESSAGE (repeated) | RSA headline assets |
ad_group_ad.ad.responsive_search_ad.descriptions | MESSAGE (repeated) | RSA description assets |
ad_group_ad.policy_summary.approval_status | ENUM | APPROVED, APPROVED_LIMITED, AREA_OF_INTEREST_ONLY, DISAPPROVED |
Keyword & Criterion Fields
| Field | Type | Description |
|---|
ad_group_criterion.criterion_id | INT64 | Criterion ID |
ad_group_criterion.keyword.text | STRING | Keyword text |
ad_group_criterion.keyword.match_type | ENUM | BROAD, PHRASE, EXACT |
ad_group_criterion.status | ENUM | ENABLED, PAUSED, REMOVED |
ad_group_criterion.quality_info.quality_score | INT32 | Quality Score (1-10) |
ad_group_criterion.quality_info.creative_quality_score | ENUM | BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE |
ad_group_criterion.quality_info.post_click_quality_score | ENUM | Landing page experience |
ad_group_criterion.quality_info.search_predicted_ctr | ENUM | Expected CTR |
ad_group_criterion.effective_cpc_bid_micros | INT64 | Effective CPC bid |
ad_group_criterion.position_estimates.first_page_cpc_micros | INT64 | Estimated first page CPC |
ad_group_criterion.final_urls | STRING (repeated) | Keyword-level final URLs |
Search Term Fields
| Field | Type | Description |
|---|
search_term_view.search_term | STRING | Actual user search query |
search_term_view.status | ENUM | ADDED, EXCLUDED, ADDED_EXCLUDED, NONE |
search_term_view.resource_name | STRING | Resource path |
Metrics
| Field | Type | Description |
|---|
metrics.impressions | INT64 | Number of impressions |
metrics.clicks | INT64 | Number of clicks |
metrics.cost_micros | INT64 | Cost in micros (divide by 1,000,000 for actual currency) |
metrics.ctr | DOUBLE | Click-through rate (clicks / impressions) |
metrics.average_cpc | DOUBLE | Average cost per click in micros |
metrics.average_cpm | DOUBLE | Average cost per thousand impressions in micros |
metrics.conversions | DOUBLE | Number of conversions |
metrics.conversions_value | DOUBLE | Total conversion value |
metrics.cost_per_conversion | DOUBLE | Cost per conversion in micros |
metrics.all_conversions | DOUBLE | All conversions (including cross-device) |
metrics.all_conversions_value | DOUBLE | All conversions value |
metrics.view_through_conversions | INT64 | View-through conversions |
metrics.search_impression_share | DOUBLE | Search impression share (0.0 to 1.0) |
metrics.search_top_impression_share | DOUBLE | Top impression share |
metrics.search_absolute_top_impression_share | DOUBLE | Absolute top impression share |
metrics.search_budget_lost_impression_share | DOUBLE | IS lost to budget |
metrics.search_rank_lost_impression_share | DOUBLE | IS lost to rank |
metrics.interaction_rate | DOUBLE | Interaction rate |
metrics.interactions | INT64 | Interactions |
metrics.video_views | INT64 | Video views |
metrics.video_view_rate | DOUBLE | Video view rate |
metrics.average_cpv | DOUBLE | Average cost per video view in micros |
metrics.bounce_rate | DOUBLE | Bounce rate (when linked to GA) |
metrics.active_view_impressions | INT64 | Viewable impressions |
metrics.active_view_ctr | DOUBLE | Viewable CTR |
metrics.invalid_clicks | INT64 | Invalid clicks filtered by Google |
Segments
| Field | Type | Description |
|---|
segments.date | DATE | Date (YYYY-MM-DD) |
segments.day_of_week | ENUM | MONDAY through SUNDAY |
segments.month | DATE | First day of the month |
segments.quarter | DATE | First day of the quarter |
segments.year | INT32 | Year |
segments.hour | INT32 | Hour of day (0-23) |
segments.device | ENUM | DESKTOP, MOBILE, TABLET, OTHER |
segments.ad_network_type | ENUM | SEARCH, SEARCH_PARTNERS, CONTENT, YOUTUBE_SEARCH, YOUTUBE_WATCH, MIXED |
segments.slot | ENUM | TOP, OTHER |
segments.conversion_action | RESOURCE | Conversion action resource name |
segments.conversion_action_name | STRING | Conversion action name |
segments.conversion_action_category | ENUM | Category of the conversion action |
segments.click_type | ENUM | URL_CLICKS, CALLS, SITELINKS, etc. |
segments.keyword.ad_group_criterion | RESOURCE | Keyword criterion resource |
segments.keyword.info.text | STRING | Keyword text (in search_term_view) |
segments.keyword.info.match_type | ENUM | Keyword match type |
WHERE Clause Operators
Comparison Operators
| Operator | Example |
|---|
= | campaign.status = 'ENABLED' |
!= | campaign.status != 'REMOVED' |
> | metrics.impressions > 100 |
< | metrics.ctr < 0.02 |
>= | metrics.clicks >= 10 |
<= | metrics.cost_micros <= 5000000 |
Set Operators
| Operator | Example |
|---|
IN | campaign.status IN ('ENABLED', 'PAUSED') |
NOT IN | campaign.advertising_channel_type NOT IN ('VIDEO', 'DISPLAY') |
CONTAINS ANY | campaign.labels CONTAINS ANY ('customers/123/labels/456') |
CONTAINS ALL | campaign.labels CONTAINS ALL ('customers/123/labels/456', 'customers/123/labels/789') |
CONTAINS NONE | campaign.labels CONTAINS NONE ('customers/123/labels/456') |
String Operators
| Operator | Example |
|---|
LIKE | campaign.name LIKE '%Brand%' |
NOT LIKE | campaign.name NOT LIKE '%Test%' |
Null Checks
| Operator | Example |
|---|
IS NULL | ad_group_criterion.quality_info.quality_score IS NULL |
IS NOT NULL | ad_group_criterion.quality_info.quality_score IS NOT NULL |
Range Operators
| Operator | Example |
|---|
BETWEEN | segments.date BETWEEN '2025-01-01' AND '2025-01-31' |
DURING | segments.date DURING LAST_30_DAYS |
Date Macros (DURING)
| Macro | Description |
|---|
TODAY | Today only |
YESTERDAY | Yesterday only |
LAST_7_DAYS | Last 7 days (not including today) |
LAST_14_DAYS | Last 14 days |
LAST_30_DAYS | Last 30 days |
LAST_BUSINESS_WEEK | Monday through Friday of the previous week |
THIS_WEEK_MON_TODAY | Monday of this week through today |
THIS_WEEK_SUN_TODAY | Sunday of this week through today |
THIS_MONTH | First day of this month through today |
LAST_MONTH | Entire previous month |
LAST_14_DAYS | Last 14 days |
Common Query Patterns
1. Campaign Performance Report
SELECT
campaign.id,
campaign.name,
campaign.status,
campaign.advertising_channel_type,
campaign.bidding_strategy_type,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.cost_per_conversion
FROM campaign
WHERE campaign.status != 'REMOVED'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.cost_micros DESC
2. Search Terms Report (with Negative Keyword Identification)
SELECT
search_term_view.search_term,
search_term_view.status,
segments.keyword.info.text,
segments.keyword.info.match_type,
campaign.name,
ad_group.name,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.cost_per_conversion
FROM search_term_view
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
AND metrics.impressions > 10
ORDER BY metrics.cost_micros DESC
LIMIT 1000
Use this to identify wasted spend: filter for search terms with high cost and zero conversions to build negative keyword lists.
3. Quality Score Analysis
SELECT
campaign.name,
ad_group.name,
ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
ad_group_criterion.quality_info.quality_score,
ad_group_criterion.quality_info.creative_quality_score,
ad_group_criterion.quality_info.post_click_quality_score,
ad_group_criterion.quality_info.search_predicted_ctr,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions
FROM keyword_view
WHERE campaign.status = 'ENABLED'
AND ad_group.status = 'ENABLED'
AND ad_group_criterion.status = 'ENABLED'
AND ad_group_criterion.quality_info.quality_score IS NOT NULL
AND segments.date DURING LAST_30_DAYS
ORDER BY ad_group_criterion.quality_info.quality_score ASC
4. Landing Page Performance
SELECT
landing_page_view.unexpanded_final_url,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.cost_per_conversion,
metrics.bounce_rate
FROM landing_page_view
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
AND metrics.clicks > 0
ORDER BY metrics.clicks DESC
LIMIT 100
5. Device Breakdown
SELECT
campaign.name,
segments.device,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.cost_per_conversion
FROM campaign
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY campaign.name, segments.device
6. Geographic Performance
SELECT
geographic_view.country_criterion_id,
geographic_view.location_type,
campaign.name,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.cost_per_conversion
FROM geographic_view
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
AND metrics.impressions > 0
ORDER BY metrics.cost_micros DESC
LIMIT 200
7. Ad Copy Performance (RSA Asset-Level)
SELECT
campaign.name,
ad_group.name,
ad_group_ad.ad.id,
ad_group_ad.ad.type,
ad_group_ad.ad.responsive_search_ad.headlines,
ad_group_ad.ad.responsive_search_ad.descriptions,
ad_group_ad.ad.final_urls,
ad_group_ad.policy_summary.approval_status,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions
FROM ad_group_ad
WHERE campaign.status = 'ENABLED'
AND ad_group.status = 'ENABLED'
AND ad_group_ad.status = 'ENABLED'
AND ad_group_ad.ad.type = 'RESPONSIVE_SEARCH_AD'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.impressions DESC
For asset-level performance (which headline/description combinations performed best):
SELECT
campaign.name,
ad_group.name,
ad_group_ad_asset_view.field_type,
ad_group_ad_asset_view.performance_label,
asset.text_asset.text,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions
FROM ad_group_ad_asset_view
WHERE campaign.status = 'ENABLED'
AND ad_group.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY ad_group_ad_asset_view.performance_label DESC, metrics.impressions DESC
8. Budget Utilization / Impression Share
SELECT
campaign.name,
campaign.campaign_budget,
campaign_budget.amount_micros,
campaign.bidding_strategy_type,
metrics.impressions,
metrics.cost_micros,
metrics.search_impression_share,
metrics.search_top_impression_share,
metrics.search_absolute_top_impression_share,
metrics.search_budget_lost_impression_share,
metrics.search_rank_lost_impression_share
FROM campaign
WHERE campaign.status = 'ENABLED'
AND campaign.advertising_channel_type = 'SEARCH'
AND segments.date DURING LAST_30_DAYS
ORDER BY metrics.search_budget_lost_impression_share DESC
9. Conversion Action Breakdown
SELECT
campaign.name,
segments.conversion_action_name,
segments.conversion_action_category,
metrics.conversions,
metrics.conversions_value,
metrics.all_conversions,
metrics.all_conversions_value,
metrics.cost_per_conversion
FROM campaign
WHERE campaign.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
AND metrics.conversions > 0
ORDER BY metrics.conversions DESC
10. Change History Audit
SELECT
change_event.change_date_time,
change_event.change_resource_type,
change_event.change_resource_name,
change_event.resource_change_operation,
change_event.changed_fields,
change_event.old_resource,
change_event.new_resource,
change_event.user_email
FROM change_event
WHERE change_event.change_date_time DURING LAST_14_DAYS
AND change_event.change_resource_type IN (
'CAMPAIGN', 'AD_GROUP', 'AD_GROUP_AD',
'AD_GROUP_CRITERION', 'CAMPAIGN_BUDGET'
)
ORDER BY change_event.change_date_time DESC
LIMIT 500
Gotchas and Important Notes
cost_micros Requires Division
All cost fields are in micros (1/1,000,000 of the currency unit). Always divide by 1,000,000 for human-readable values:
Actual cost = metrics.cost_micros / 1,000,000
Actual CPC = metrics.average_cpc / 1,000,000
For example, cost_micros = 5430000 means $5.43 (or 5.43 in the account's currency).
Segment + Metric Compatibility
Not all segments can be used with all metrics. Key rules:
segments.conversion_action — when you add this segment, metrics.conversions and metrics.conversions_value break down by conversion action, but metrics.clicks and metrics.impressions will repeat across each conversion action row. Do not sum impressions/clicks when conversion segments are present.
segments.click_type — similar issue; clicks and impressions fragment by click type. Summing them will overcount.
segments.slot — only compatible with search campaigns.
segments.hour — cannot be combined with segments.date in the same query for some resources. Use one or the other.
- Check the Google Ads API field compatibility matrix when in doubt.
Date Range Requirements
- Queries that include any
metrics.* field require a date range via segments.date DURING ... or segments.date BETWEEN ... AND ....
- If you omit the date range, the API returns an error for metric-bearing queries.
- Resource-only queries (no metrics) do not need a date range.
Enum Values
Enum fields must use their string constant names. Common enum values:
CampaignStatus: ENABLED, PAUSED, REMOVED
AdGroupStatus: ENABLED, PAUSED, REMOVED
AdGroupAdStatus: ENABLED, PAUSED, REMOVED
AdvertisingChannelType: SEARCH, DISPLAY, SHOPPING, VIDEO, PERFORMANCE_MAX, MULTI_CHANNEL, LOCAL, SMART, HOTEL, DISCOVERY
KeywordMatchType: BROAD, PHRASE, EXACT
BiddingStrategyType: TARGET_CPA, TARGET_ROAS, MAXIMIZE_CONVERSIONS, MAXIMIZE_CONVERSION_VALUE, MANUAL_CPC, ENHANCED_CPC, TARGET_IMPRESSION_SHARE, MANUAL_CPM, MANUAL_CPV
Device: DESKTOP, MOBILE, TABLET, CONNECTED_TV, OTHER
QualityScoreBucket: BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE
Rate Limits
- Standard access: 15,000 requests per day, 1,600 operations per minute per developer token.
- Basic access: 10,000 requests per day.
- Use
SearchStream instead of Search for large result sets to avoid pagination overhead and reduce quota consumption.
- Each
SearchStream call counts as one operation regardless of result size.
- Batch multiple queries in parallel where possible, but respect the per-minute operation limit.
Other Pitfalls
- No
OR in WHERE: All conditions are AND-joined. To simulate OR, run separate queries or use IN.
- No joins: GAQL queries operate on a single resource. Use attributed resources (e.g.,
search_term_view already includes campaign and ad group fields).
- No
GROUP BY: Aggregation is implicit. The API groups by the combination of resource fields and segments you select.
- No aliases: You cannot use
AS in GAQL. Field names are returned as-is.
- No arithmetic: You cannot do
metrics.cost_micros / 1000000 in GAQL. Perform calculations client-side.
- Segment auto-grouping: Adding a segment to
SELECT automatically splits rows by that segment. Selecting segments.device means you get one row per campaign per device, not one row per campaign.
- Removed resources: By default,
REMOVED entities are excluded. To include them, filter explicitly with campaign.status IN ('ENABLED', 'PAUSED', 'REMOVED').
- PARAMETERS clause: Use
PARAMETERS include_drafts = true to include draft campaigns, or PARAMETERS omit_unselected_resource_names = true to reduce response size.
Next Steps
- Google Ads API Requirements - Connect your Google Ads data
- AI Report Generation - How Cogny analyzes ads data
- GA4 BigQuery Export Schema - Combine with GA4 analytics data
Claude Code Skill
This GAQL reference is also available as a free Claude Code skill -- use it directly in your terminal:
# Install
curl -sSL https://raw.githubusercontent.com/cognyai/claude-code-marketing-skills/main/install.sh | bash
# Use
/gaql-reference # Full syntax overview
/gaql-reference search terms # Search terms report pattern
/gaql-reference quality score # Quality Score analysis query
/gaql-reference impression share # Budget & impression share query
View on GitHub →
Resources