Google Ads Report Builder

Google ads report

by OpenClaudia · MIT license · ★ 705 on GitHub

Google ads report cover

Pull Google Ads performance data and generate reports. Use when asked about ad campaign performance, keyword costs, quality scores, ROAS, conversion tracking, or ad spend analysis.

---
name: google-ads-report
description: >
  Pull Google Ads performance data and generate reports. Use when asked about
  ad campaign performance, keyword costs, quality scores, ROAS, conversion
  tracking, or ad spend analysis. Trigger phrases: "google ads", "adwords",
  "campaign performance", "ad spend", "quality score", "CPC report",
  "ROAS", "ad conversion", "keyword performance", "google ads report".
---

# Google Ads Report

Pull campaign, keyword, and conversion data from the Google Ads API.

## Prerequisites

Requires:
- `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` (OAuth)

Overview

Pull campaign, keyword, and conversion data from the Google Ads API.

Manual install (npx, ZIP)
Claude Codenpx skills add OpenClaudia/openclaudia-skills --skill google-ads-report -g -a claude-code
Claude Code (degit)npx degit OpenClaudia/openclaudia-skills/skills/google-ads-report#main ~/.claude/skills/google-ads-report
Claude.ai / desktopZip the folder and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md11.2 KB
Read SKILL.md here
OpenClaudia/main1 file shown
SKILL.md
Show the full text306 lines

Google Ads Report

Pull campaign, keyword, and conversion data from the Google Ads API.

Prerequisites

Requires:

  • GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET (OAuth)
  • GOOGLE_ADS_DEVELOPER_TOKEN (apply at https://ads.google.com/home/tools/manager-accounts/)
  • GOOGLE_ADS_CUSTOMER_ID (the account ID, format: XXX-XXX-XXXX, passed without dashes)
  • GOOGLE_ADS_LOGIN_CUSTOMER_ID (if using a manager account, the manager account ID)

Set in .env, .env.local, or ~/.claude/.env.global.

Getting an Access Token
# Same OAuth flow as other Google APIs
# Scope needed: https://www.googleapis.com/auth/adwords

echo "https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/adwords&response_type=code&access_type=offline"

# Exchange code for tokens
curl -s -X POST "https://oauth2.googleapis.com/token" \
  -d "code={AUTH_CODE}" \
  -d "client_id=${GOOGLE_CLIENT_ID}" \
  -d "client_secret=${GOOGLE_CLIENT_SECRET}" \
  -d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
  -d "grant_type=authorization_code"

API Base

Google Ads API uses GAQL (Google Ads Query Language) via REST.

POST https://googleads.googleapis.com/v17/customers/{CUSTOMER_ID}/googleAds:searchStream

Headers:

Authorization: Bearer {ACCESS_TOKEN}
developer-token: {DEVELOPER_TOKEN}
login-customer-id: {LOGIN_CUSTOMER_ID}  # Only if using manager account
Content-Type: application/json

1. Campaign Performance Report

Overview of all campaigns with key metrics.

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.cost_per_conversion, metrics.conversions_value FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status != REMOVED ORDER BY metrics.cost_micros DESC"
  }'
Parsing Campaign Data
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"{'Campaign':<35} {'Status':<10} {'Impr':>8} {'Clicks':>7} {'CTR':>7} {'Avg CPC':>8} {'Cost':>10} {'Conv':>6} {'CPA':>8}\")
print('-' * 110)
for batch in data:
    for row in batch.get('results', []):
        c = row.get('campaign', {})
        m = row.get('metrics', {})
        cost = int(m.get('costMicros', 0)) / 1_000_000
        cpc = int(m.get('averageCpc', 0)) / 1_000_000
        cpa = float(m.get('costPerConversion', 0)) / 1_000_000 if m.get('costPerConversion') else 0
        print(f\"{c.get('name',''):<35} {c.get('status',''):<10} {int(m.get('impressions',0)):>8} {int(m.get('clicks',0)):>7} {float(m.get('ctr',0))*100:>6.2f}% \${cpc:>7.2f} \${cost:>9.2f} {float(m.get('conversions',0)):>6.1f} \${cpa:>7.2f}\")
"
Important: Cost Micros

All cost values in Google Ads API are in micros (1/1,000,000 of the currency unit). Divide by 1,000,000 to get the actual amount.


2. Keyword Performance Report

See how individual keywords perform.

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.quality_info.quality_score, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.conversions_value FROM keyword_view WHERE segments.date DURING LAST_30_DAYS AND ad_group_criterion.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
  }'
Quality Score Breakdown
curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT ad_group_criterion.keyword.text, 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.average_cpc FROM keyword_view WHERE 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 LIMIT 50"
  }'

Quality Score Components:

  • quality_score: Overall score (1-10)
  • creative_quality_score: Ad relevance (BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE)
  • post_click_quality_score: Landing page experience
  • search_predicted_ctr: Expected click-through rate

3. Ad Group Performance

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT campaign.name, ad_group.name, ad_group.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions FROM ad_group WHERE segments.date DURING LAST_30_DAYS AND ad_group.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
  }'

4. Search Terms Report

See what users actually searched for (vs. your keywords).

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT search_term_view.search_term, segments.keyword.info.text, segments.keyword.info.match_type, metrics.impressions, metrics.clicks, metrics.ctr, metrics.cost_micros, metrics.conversions FROM search_term_view WHERE segments.date DURING LAST_30_DAYS ORDER BY metrics.impressions DESC LIMIT 100"
  }'

Use this to:

  • Find new keyword opportunities (high-converting search terms)
  • Identify negative keyword candidates (irrelevant terms with spend)
  • Discover match type issues (broad match pulling in junk traffic)

5. Conversion Tracking

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT campaign.name, metrics.conversions, metrics.conversions_value, metrics.cost_micros, metrics.conversions_from_interactions_rate, metrics.value_per_conversion FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status = ENABLED ORDER BY metrics.conversions DESC"
  }'
ROAS Calculation
# ROAS = conversions_value / (cost_micros / 1_000_000)
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"{'Campaign':<35} {'Cost':>10} {'Conv Value':>12} {'ROAS':>8}\")
for batch in data:
    for row in batch.get('results', []):
        c = row['campaign']['name']
        m = row['metrics']
        cost = int(m.get('costMicros', 0)) / 1_000_000
        value = float(m.get('conversionsValue', 0))
        roas = value / cost if cost > 0 else 0
        print(f\"{c:<35} \${cost:>9.2f} \${value:>11.2f} {roas:>7.2f}x\")
"

6. Daily Spend Trend

curl -s -X POST \
  "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
  -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
  -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "SELECT segments.date, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions FROM customer WHERE segments.date DURING LAST_30_DAYS ORDER BY segments.date DESC"
  }'

GAQL Date Ranges

Use these built-in date ranges in GAQL:

  • TODAY, YESTERDAY
  • LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS
  • THIS_MONTH, LAST_MONTH
  • THIS_QUARTER, LAST_QUARTER
  • Custom: segments.date BETWEEN '2024-01-01' AND '2024-03-31'

Workflow: Monthly Google Ads Report

When asked for a full ads report:

  1. Account Overview: Total spend, impressions, clicks, conversions, ROAS
  2. Campaign Performance: All active campaigns ranked by spend
  3. Top Keywords: Top 20 keywords by spend with quality scores
  4. Search Terms: Top search terms and negative keyword candidates
  5. Quality Score Distribution: How many keywords at each QS level
  6. Conversion Analysis: Conversions and ROAS by campaign
  7. Daily Trend: Spend and conversion trend over the period
Report Format
## Google Ads Report: {Account Name}
### Period: {date range}

### Account Summary
| Metric | Value | vs Previous |
|--------|-------|-------------|
| Total Spend | $X | +Y% |
| Impressions | X | +Y% |
| Clicks | X | +Y% |
| CTR | X% | +Y pp |
| Avg CPC | $X | +Y% |
| Conversions | X | +Y% |
| ROAS | Xx | +Y% |

### Campaign Performance
| Campaign | Spend | Clicks | Conv | CPA | ROAS |
|----------|-------|--------|------|-----|------|
| ...      | ...   | ...    | ...  | ... | ...  |

### Top Keywords (by spend)
| Keyword | Match | QS | Spend | Clicks | Conv | CPC |
|---------|-------|-----|-------|--------|------|-----|
| ...     | ...   | ... | ...   | ...    | ...  | ... |

### Recommendations
- **Pause**: Keywords with high spend and zero conversions
- **Increase Bids**: Keywords with high conversion rate but limited budget
- **Negative Keywords**: Search terms wasting budget
- **Quality Score Fixes**: Keywords with QS < 5 and actions to improve
- **Budget Reallocation**: Shift budget from low-ROAS to high-ROAS campaigns

Error Handling

Error Cause
AUTHENTICATION_ERROR Invalid or expired access token
AUTHORIZATION_ERROR Developer token issue or account access
REQUEST_ERROR GAQL syntax error
QUOTA_ERROR API quota exceeded
Common GAQL Mistakes
  • Missing WHERE segments.date DURING ... (required for most metric queries)
  • Using REMOVED status filter incorrectly
  • Forgetting to handle costMicros division by 1,000,000
  • Requesting incompatible resource + segment combinations

Tips

  • Always filter out REMOVED campaigns/ad groups/keywords
  • Use searchStream instead of search for large result sets (no pagination needed)
  • Cache results when building multi-section reports
  • Quality Score of 0 means "not enough data" -- treat as null
1---
2name: google-ads-report
3description: >
4 Pull Google Ads performance data and generate reports. Use when asked about
5 ad campaign performance, keyword costs, quality scores, ROAS, conversion
6 tracking, or ad spend analysis. Trigger phrases: "google ads", "adwords",
7 "campaign performance", "ad spend", "quality score", "CPC report",
8 "ROAS", "ad conversion", "keyword performance", "google ads report".
9---
10 
11# Google Ads Report
12 
13Pull campaign, keyword, and conversion data from the Google Ads API.
14 
15## Prerequisites
16 
17Requires:
18- `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` (OAuth)
19- `GOOGLE_ADS_DEVELOPER_TOKEN` (apply at https://ads.google.com/home/tools/manager-accounts/)
20- `GOOGLE_ADS_CUSTOMER_ID` (the account ID, format: `XXX-XXX-XXXX`, passed without dashes)
21- `GOOGLE_ADS_LOGIN_CUSTOMER_ID` (if using a manager account, the manager account ID)
22 
23Set in `.env`, `.env.local`, or `~/.claude/.env.global`.
24 
25### Getting an Access Token
26 
27```bash
28# Same OAuth flow as other Google APIs
29# Scope needed: https://www.googleapis.com/auth/adwords
30 
31echo "https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/adwords&response_type=code&access_type=offline"
32 
33# Exchange code for tokens
34curl -s -X POST "https://oauth2.googleapis.com/token" \
35 -d "code={AUTH_CODE}" \
36 -d "client_id=${GOOGLE_CLIENT_ID}" \
37 -d "client_secret=${GOOGLE_CLIENT_SECRET}" \
38 -d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
39 -d "grant_type=authorization_code"
40```
41 
42---
43 
44## API Base
45 
46Google Ads API uses GAQL (Google Ads Query Language) via REST.
47 
48```
49POST https://googleads.googleapis.com/v17/customers/{CUSTOMER_ID}/googleAds:searchStream
50```
51 
52Headers:
53```
54Authorization: Bearer {ACCESS_TOKEN}
55developer-token: {DEVELOPER_TOKEN}
56login-customer-id: {LOGIN_CUSTOMER_ID} # Only if using manager account
57Content-Type: application/json
58```
59 
60---
61 
62## 1. Campaign Performance Report
63 
64Overview of all campaigns with key metrics.
65 
66```bash
67curl -s -X POST \
68 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
69 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
70 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
71 -H "Content-Type: application/json" \
72 -d '{
73 "query": "SELECT campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.cost_per_conversion, metrics.conversions_value FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status != REMOVED ORDER BY metrics.cost_micros DESC"
74 }'
75```
76 
77### Parsing Campaign Data
78 
79```bash
80curl -s -X POST "..." | python3 -c "
81import json, sys
82data = json.load(sys.stdin)
83print(f\"{'Campaign':<35} {'Status':<10} {'Impr':>8} {'Clicks':>7} {'CTR':>7} {'Avg CPC':>8} {'Cost':>10} {'Conv':>6} {'CPA':>8}\")
84print('-' * 110)
85for batch in data:
86 for row in batch.get('results', []):
87 c = row.get('campaign', {})
88 m = row.get('metrics', {})
89 cost = int(m.get('costMicros', 0)) / 1_000_000
90 cpc = int(m.get('averageCpc', 0)) / 1_000_000
91 cpa = float(m.get('costPerConversion', 0)) / 1_000_000 if m.get('costPerConversion') else 0
92 print(f\"{c.get('name',''):<35} {c.get('status',''):<10} {int(m.get('impressions',0)):>8} {int(m.get('clicks',0)):>7} {float(m.get('ctr',0))*100:>6.2f}% \${cpc:>7.2f} \${cost:>9.2f} {float(m.get('conversions',0)):>6.1f} \${cpa:>7.2f}\")
93"
94```
95 
96### Important: Cost Micros
97 
98All cost values in Google Ads API are in **micros** (1/1,000,000 of the currency unit). Divide by 1,000,000 to get the actual amount.
99 
100---
101 
102## 2. Keyword Performance Report
103 
104See how individual keywords perform.
105 
106```bash
107curl -s -X POST \
108 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
109 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
110 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
111 -H "Content-Type: application/json" \
112 -d '{
113 "query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.quality_info.quality_score, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.conversions_value FROM keyword_view WHERE segments.date DURING LAST_30_DAYS AND ad_group_criterion.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
114 }'
115```
116 
117### Quality Score Breakdown
118 
119```bash
120curl -s -X POST \
121 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
122 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
123 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
124 -H "Content-Type: application/json" \
125 -d '{
126 "query": "SELECT ad_group_criterion.keyword.text, 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.average_cpc FROM keyword_view WHERE 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 LIMIT 50"
127 }'
128```
129 
130Quality Score Components:
131- **quality_score**: Overall score (1-10)
132- **creative_quality_score**: Ad relevance (BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE)
133- **post_click_quality_score**: Landing page experience
134- **search_predicted_ctr**: Expected click-through rate
135 
136---
137 
138## 3. Ad Group Performance
139 
140```bash
141curl -s -X POST \
142 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
143 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
144 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
145 -H "Content-Type: application/json" \
146 -d '{
147 "query": "SELECT campaign.name, ad_group.name, ad_group.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions FROM ad_group WHERE segments.date DURING LAST_30_DAYS AND ad_group.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
148 }'
149```
150 
151---
152 
153## 4. Search Terms Report
154 
155See what users actually searched for (vs. your keywords).
156 
157```bash
158curl -s -X POST \
159 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
160 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
161 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
162 -H "Content-Type: application/json" \
163 -d '{
164 "query": "SELECT search_term_view.search_term, segments.keyword.info.text, segments.keyword.info.match_type, metrics.impressions, metrics.clicks, metrics.ctr, metrics.cost_micros, metrics.conversions FROM search_term_view WHERE segments.date DURING LAST_30_DAYS ORDER BY metrics.impressions DESC LIMIT 100"
165 }'
166```
167 
168Use this to:
169- Find new keyword opportunities (high-converting search terms)
170- Identify negative keyword candidates (irrelevant terms with spend)
171- Discover match type issues (broad match pulling in junk traffic)
172 
173---
174 
175## 5. Conversion Tracking
176 
177```bash
178curl -s -X POST \
179 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
180 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
181 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
182 -H "Content-Type: application/json" \
183 -d '{
184 "query": "SELECT campaign.name, metrics.conversions, metrics.conversions_value, metrics.cost_micros, metrics.conversions_from_interactions_rate, metrics.value_per_conversion FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status = ENABLED ORDER BY metrics.conversions DESC"
185 }'
186```
187 
188### ROAS Calculation
189 
190```bash
191# ROAS = conversions_value / (cost_micros / 1_000_000)
192curl -s -X POST "..." | python3 -c "
193import json, sys
194data = json.load(sys.stdin)
195print(f\"{'Campaign':<35} {'Cost':>10} {'Conv Value':>12} {'ROAS':>8}\")
196for batch in data:
197 for row in batch.get('results', []):
198 c = row['campaign']['name']
199 m = row['metrics']
200 cost = int(m.get('costMicros', 0)) / 1_000_000
201 value = float(m.get('conversionsValue', 0))
202 roas = value / cost if cost > 0 else 0
203 print(f\"{c:<35} \${cost:>9.2f} \${value:>11.2f} {roas:>7.2f}x\")
204"
205```
206 
207---
208 
209## 6. Daily Spend Trend
210 
211```bash
212curl -s -X POST \
213 "https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
214 -H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
215 -H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
216 -H "Content-Type: application/json" \
217 -d '{
218 "query": "SELECT segments.date, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions FROM customer WHERE segments.date DURING LAST_30_DAYS ORDER BY segments.date DESC"
219 }'
220```
221 
222---
223 
224## GAQL Date Ranges
225 
226Use these built-in date ranges in GAQL:
227- `TODAY`, `YESTERDAY`
228- `LAST_7_DAYS`, `LAST_14_DAYS`, `LAST_30_DAYS`
229- `THIS_MONTH`, `LAST_MONTH`
230- `THIS_QUARTER`, `LAST_QUARTER`
231- Custom: `segments.date BETWEEN '2024-01-01' AND '2024-03-31'`
232 
233---
234 
235## Workflow: Monthly Google Ads Report
236 
237When asked for a full ads report:
238 
2391. **Account Overview**: Total spend, impressions, clicks, conversions, ROAS
2402. **Campaign Performance**: All active campaigns ranked by spend
2413. **Top Keywords**: Top 20 keywords by spend with quality scores
2424. **Search Terms**: Top search terms and negative keyword candidates
2435. **Quality Score Distribution**: How many keywords at each QS level
2446. **Conversion Analysis**: Conversions and ROAS by campaign
2457. **Daily Trend**: Spend and conversion trend over the period
246 
247### Report Format
248 
249```
250## Google Ads Report: {Account Name}
251### Period: {date range}
252 
253### Account Summary
254| Metric | Value | vs Previous |
255|--------|-------|-------------|
256| Total Spend | $X | +Y% |
257| Impressions | X | +Y% |
258| Clicks | X | +Y% |
259| CTR | X% | +Y pp |
260| Avg CPC | $X | +Y% |
261| Conversions | X | +Y% |
262| ROAS | Xx | +Y% |
263 
264### Campaign Performance
265| Campaign | Spend | Clicks | Conv | CPA | ROAS |
266|----------|-------|--------|------|-----|------|
267| ... | ... | ... | ... | ... | ... |
268 
269### Top Keywords (by spend)
270| Keyword | Match | QS | Spend | Clicks | Conv | CPC |
271|---------|-------|-----|-------|--------|------|-----|
272| ... | ... | ... | ... | ... | ... | ... |
273 
274### Recommendations
275- **Pause**: Keywords with high spend and zero conversions
276- **Increase Bids**: Keywords with high conversion rate but limited budget
277- **Negative Keywords**: Search terms wasting budget
278- **Quality Score Fixes**: Keywords with QS < 5 and actions to improve
279- **Budget Reallocation**: Shift budget from low-ROAS to high-ROAS campaigns
280```
281 
282---
283 
284## Error Handling
285 
286| Error | Cause |
287|-------|-------|
288| `AUTHENTICATION_ERROR` | Invalid or expired access token |
289| `AUTHORIZATION_ERROR` | Developer token issue or account access |
290| `REQUEST_ERROR` | GAQL syntax error |
291| `QUOTA_ERROR` | API quota exceeded |
292 
293### Common GAQL Mistakes
294 
295- Missing `WHERE segments.date DURING ...` (required for most metric queries)
296- Using `REMOVED` status filter incorrectly
297- Forgetting to handle `costMicros` division by 1,000,000
298- Requesting incompatible resource + segment combinations
299 
300## Tips
301 
302- Always filter out REMOVED campaigns/ad groups/keywords
303- Use `searchStream` instead of `search` for large result sets (no pagination needed)
304- Cache results when building multi-section reports
305- Quality Score of 0 means "not enough data" -- treat as null
306 
View all files on GitHub →

Details

License
MIT
Stars on the repo
★ 705
Checked
Source
OpenClaudia/openclaudia-skills ↗
Creator
OpenClaudia · 78 listings
View creator

Similar skills

See all →
SkillGoogle Ads Managerivangfalco/ads-skills · by ivangfalcoGoogle Ads management skill with API integration. Covers campaign creation, optimization, keyword management, performance analysis, and search term auditing via Python scripts that connect to the Google Ads API. MANDATORY TRIGGERS: Google Ads, Google campaign, Google search ads, Google PMax, Performance Max, Google Display, Google Shopping, Google ad performance, Google keyword, search terms, Google RSA, Google bidding, Google Ads API★ 275 GitHub starsSkillAd Copy Generatormarcosmodly/marketing-skill · by marcosmodlyWrites paid ad copy for Facebook and Instagram (Meta) Ads, Google Search Ads (RSA headlines and descriptions), and LinkedIn Ads: multiple variants per platform, each testing a different hook angle and sized to that platform's character limits, ready for A/B testing. Use when the user asks for ad copy, ad headlines, ad variants, PPC or paid social copy, Facebook ad text, Google Ads headlines, or A/B test copy for a paid campaign.★ 42 GitHub starsSkillPaid Ads Managerdavila7/claude-code-templates · by davila7When the user wants help with paid advertising campaigns on Google Ads, Meta (Facebook/Instagram), LinkedIn, Twitter/X, or other ad platforms. Also use when the user mentions 'PPC,' 'paid media,' 'ad copy,' 'ad creative,' 'ROAS,' 'CPA,' 'ad campaign,' 'retargeting,' or 'audience targeting.' This skill covers campaign strategy, ad creation, audience targeting, and optimization.★ 32.3k GitHub starsSkillGoogle Ads AuditorAgriciDaniel/claude-ads · by AgriciDanielAudit Google Ads measurement, Search, Shopping, Performance Max, Demand Gen, YouTube-linked inventory, keywords and search terms, negative-keyword generation or review, creative assets, bidding, budgets, settings, and policy. Use for Google Ads, AdWords, Search campaigns, search terms reports, broad negatives, Shopping, Performance Max, PMax, Demand Gen, GAQL, Google conversion tracking, or Google campaign optimization.★ 9.5k GitHub starsSkillMicrosoft Ads AuditorAgriciDaniel/claude-ads · by AgriciDanielPaste what you're selling and share your Microsoft Advertising numbers; get back a plain-English report on what's wasting money and what to fix first.★ 9.5k GitHub starsSkillGoogle Ads Performance Managernowork-studio/notfair-plugin · by nowork-studioManage Google Ads — performance, keywords, bids, budgets, negatives, campaigns, ads, search terms, QS, location targeting, bulk operations, experiments, asset management, portfolio bidding, offline conversions. Use for any mention of Google Ads, CPA, ROAS, ad spend, or campaign settings.★ 3.9k GitHub stars

More from OpenClaudia

SkillA/B Testing FrameworkOpenClaudia/openclaudia-skills · by OpenClaudiaDesign, plan, and analyze A/B tests with statistical rigor. Use when the user asks about A/B testing, split testing, experiment design, statistical significance, sample size calculation, test duration, multivariate testing, or conversion experiments. Trigger phrases include "A/B test", "split test", "experiment", "statistical significance", "sample size", "test duration", "which version wins", "conversion experiment", "hypothesis test", "variant testing".★ 705 GitHub starsSkillAffiliate Marketing ProgramOpenClaudia/openclaudia-skills · by OpenClaudiaBuild and manage an affiliate marketing program. Use when the user says "affiliate program", "affiliate marketing", "affiliate partners", "referral commissions", "affiliate network", "partner program", "affiliate tracking", or asks about creating, managing, or growing an affiliate or partner program.★ 705 GitHub starsSkillAhrefs API ManagerOpenClaudia/openclaudia-skills · by OpenClaudiaManages Ahrefs API usage in Python using `ahrefs-python` library. Use when working with SEO / marketing related tasks or with data including backlinks, keywords, domain ratings, organic traffic, site audits, rank tracking, and brand monitoring. Covers `ahrefs-python` usage including AhrefsClient / AsyncAhrefsClient, typed request/response models, error handling, and all API sections.★ 705 GitHub starsSkillAI Citations Report GeneratorOpenClaudia/openclaudia-skills · by OpenClaudiaGenerate an AI Citations Report (GEO) for a domain — which AI-search prompts cite the site across Google AI Overview and ChatGPT, plus organic-traffic context and per-article citation coverage. Use when the user asks for an 'AI citations report', 'GEO citations report', or 'which AI prompts cite <domain>'.★ 705 GitHub starsSkillB2B Lead EnricherOpenClaudia/openclaudia-skills · by OpenClaudiaResearch and enrich B2B leads using the Apollo.io API. Use when the user says "find leads", "prospect research", "company enrichment", "find decision makers", "B2B leads", "lead research", "enrich contacts", "find VP of marketing at", or asks about finding people at specific companies or in specific roles.★ 705 GitHub starsSkillBacklink Health CheckerOpenClaudia/openclaudia-skills · by OpenClaudiaAudit a domain's backlink profile using the SemRush API. Use when the user says "audit backlinks", "check my backlinks", "backlink analysis", "link profile", "toxic links", "disavow", "link building opportunities", "referring domains", "anchor text", or asks about a site's link authority.★ 705 GitHub stars