GAQL account hygiene: disapprovals, budget caps, conversions and change history
Four read-only queries that surface disapproved ads, budget-constrained campaigns, the state of your conversion actions and who changed what recently.
The Query Cookbook
A pack of read-only Google Ads queries that surface search terms, keywords, placements and whole campaigns taking budget while returning no conversions.
Wasted spend is rarely one big leak. It is a search term nobody reads, a keyword whose quality score quietly collapsed, a display placement on a parked domain, and a campaign whose conversion tag stopped firing. Each hides in a different report, so each usually gets found on a different unlucky day. This pack pulls all four into queries you can run in one sitting.
Every query here reads. None of them changes a bid, a budget or a status. They tell you where to look; the decision, and the pausing, stays with you.
LAST_30_DAYS; shorten it for a high-volume account, lengthen it for a thin one.metrics.cost_micros is in millionths of the account currency: divide by 1,000,000 for a spend figure.The first place waste accumulates is the search terms report, where broad and phrase match quietly buy queries you never chose. This query lists the terms that cost money over the window and returned no conversions, worst spender first. Look for off-topic queries, job seekers, and the competitor names you meant to exclude.
SELECT
search_term_view.search_term,
campaign.name,
ad_group.name,
metrics.cost_micros,
metrics.clicks,
metrics.conversions
FROM search_term_view
WHERE segments.date DURING LAST_30_DAYS
AND metrics.conversions = 0
AND metrics.cost_micros > 0
ORDER BY metrics.cost_micros DESC
Spend on a low quality score keyword is spend at a premium: you pay more per click for a worse position. This query joins each keyword's cost to its current quality score and the three component scores behind it, so you can separate a landing-page problem from an ad-relevance one. Sort your attention to the keywords that spend the most while scoring the lowest.
SELECT
ad_group_criterion.keyword.text,
campaign.name,
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.cost_micros
FROM keyword_view
WHERE segments.date DURING LAST_30_DAYS
AND metrics.cost_micros > 0
ORDER BY metrics.cost_micros DESC
A note on honesty here: there is no segments field that gives you a day-by-day historical quality score, so this reads the current value on the criterion. Google does expose metrics.historical_quality_score as a separate metric if you want the aggregate historical figure, but the component scores above (creative_quality_score, post_click_quality_score, search_predicted_ctr) are the ones that actually tell you what to fix, so they are what this query selects.
On Display and video, the equivalent leak is the placement: an app, a channel or a parked domain that serves impressions, takes clicks and converts no one. This query lists the managed-network placements that cost money and drove no conversions over the window. Mobile-game apps and generic content-farm domains are the usual suspects.
SELECT
group_placement_view.display_name,
group_placement_view.target_url,
group_placement_view.placement_type,
campaign.name,
metrics.cost_micros,
metrics.conversions
FROM group_placement_view
WHERE segments.date DURING LAST_30_DAYS
AND metrics.conversions = 0
AND metrics.cost_micros > 0
ORDER BY metrics.cost_micros DESC
The most expensive leak is the one that looks like every other campaign: it spends normally, but its conversions column reads zero, because a tag broke, a goal was unlinked, or the campaign was never tracked at all. This query lists any campaign that spent over the window and recorded no conversions. A single row here is worth checking before any of the line-item waste above.
SELECT
campaign.name,
campaign.advertising_channel_type,
campaign.status,
metrics.cost_micros,
metrics.conversions
FROM campaign
WHERE segments.date DURING LAST_30_DAYS
AND metrics.conversions = 0
AND metrics.cost_micros > 0
ORDER BY metrics.cost_micros DESC
Any GAQL runner takes these as-is. Three common routes:
query field to GoogleAdsService.SearchStream (or Search for smaller result sets), against your customer id.AdsApp.search(query) and iterate the rows, for example while (rows.hasNext()) { var row = rows.next(); }. This keeps the whole thing inside the account with no API credentials.Zero last-click conversions is not zero value. These queries deliberately use metrics.conversions, the last-click count, so an assisting term or an upper-funnel placement can look like pure waste when it is doing quieter work; cross-check anything material against your attribution and your total conversions before you act. They also read only what the account will report: Performance Max hides most of its search terms and placements, so run these across your Search and Display campaigns and treat PMax as a separate, thinner picture. Finally, GAQL has no COUNT, so the "how many campaigns" style question is answered by counting the rows the query returns, not by the query itself.
More Like This
Four read-only queries that surface disapproved ads, budget-constrained campaigns, the state of your conversion actions and who changed what recently.
Ready-to-run GAQL for creative asset ratings across responsive search ads and Performance Max asset groups, so you can find weak headlines and images in one query set.
A cookbook of Demand Gen GAQL queries that splits spend, conversions, asset ratings and audiences out of the campaign line Google reports as a single figure.