Skip to main content
ClaudeWave
Skill1.1k repo starsupdated 2d ago

google-ads

Traps when running Google Ads through treg — the API requirements and cleanup semantics that cost round-trips or money. Use whenever asked to analyse ad performance, audit spend, create or change campaigns, adjust budgets or bids, or do media buying.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/superdesigndev/treg /tmp/google-ads && cp -r /tmp/google-ads/.agents/skills/google-ads ~/.claude/skills/google-ads
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Google Ads via treg — the traps

Verified live on 2026-07-22 against a live account, via `treg call google-ads`.
Each trap is tagged with how many independent agents hit it when working **without** this file, so
you know which are real and which are here for insurance.

Account id: `treg connections ls` → the `google-ads` row; `treg connections resources <id>` to list.
Never guess an account id — you may be spending someone else's money.

## 1. Pin the API version — there is no discovery  ⚠️ 2/2 agents hit this

Paths are versioned and a wrong guess returns a **Google HTML 404**, not JSON. Nothing in the API
or in `treg tool ls` reports the current version — one agent burned **five** calls walking v14→v18
before recovering the answer from the `treg calls` audit log.

**Use `v25`** (released 2026-07-22, live-verified through the proxy 2026-08-17; sunsets ~Aug 2027).
Do not guess downward.

Two different failures, two different fixes:

- **HTML 404** — the version never existed (you guessed too high, or typo'd the path).
- **JSON 400 `UNSUPPORTED_VERSION`** — the version existed and has been **sunset**. Google ships a
  major roughly quarterly and each lives ~12 months, so a pin that worked for months dies on a
  date, not on a deploy. v21 died this way on **2026-08-05**. Always jump to the newest GA
  version, not the next one up — the next one up may be months from its own sunset.

Release notes and sunset dates: <https://developers.google.com/google-ads/api/docs/sunset-dates>

## 2. `contains_eu_political_advertising` is required on campaign create  ⚠️ 3/3 hit this

Absent from essentially every code sample. Campaign create fails `REQUIRED` without it:

```json
"containsEuPoliticalAdvertising": "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING"
```

## 3. Bidding strategy must be the sub-message, not the enum  ⚠️ 1/2 hit this

`"biddingStrategyType":"TARGET_SPEND"` alone fails `REQUIRED` on `campaign_bidding_strategy`. It's
a protobuf oneof — send the field itself: `"targetSpend":{}`, `"manualCpc":{}`,
`"maximizeConversions":{}`. The enum is output-only.

## 4. Removing a parent orphans children — and their status lies  ⚠️ 2/2 confused by this

Remove a campaign and its ad groups/criteria/ads become immutable but **keep reporting their old
status** — a removed campaign's ad group still reads `ENABLED`. Mutating one returns
`OPERATION_NOT_PERMITTED_FOR_REMOVED_RESOURCE`.

**Verify teardown on `campaign.status`, never on a child's.** Checking the child looks like cleanup
silently failed. Remove campaign first, then its budget — the budget is not removed for you, and an
orphaned budget is easy to leave behind.

Nothing is ever hard-deleted: `REMOVED` is terminal. Filter with `WHERE campaign.status != 'REMOVED'`
or your campaign list fills with corpses.

## 5. Money is in micros  ✅ 0/2 got this wrong — kept for asymmetry

`amountMicros: 3000000` = **$3.00/day**. Both agents handled this correctly, so it is not a common
failure — but a 10⁶ slip creates a $3,000/day budget that the API accepts **without any error**, and
it is the only mistake here that spends money silently. Compute `dollars * 1_000_000` explicitly and
re-read it before sending.

Currency is **not** always USD — the account may bill in a non-USD currency (e.g. AUD):

```
SELECT customer.currency_code, customer.time_zone FROM customer
```

## 6. `updateMask` controls what changes

```json
{"operations":[{"updateMask":"amount_micros",
  "update":{"resourceName":"customers/<CID>/campaignBudgets/<BID>","amountMicros":3000000}}]}
```

Only listed fields change; a field you set but don't list is ignored, one you list but don't set is
**cleared**. Both `amount_micros` and `amountMicros` are accepted (verified).

## 7. `login-customer-id` failures look like auth failures

Acting on a client account under a manager needs the header:

```bash
treg call google-ads "<path>" --method POST --header 'login-customer-id: 9876543210' --data '...'
```

A wrong or unauthorised value returns **`401 UNAUTHENTICATED`**, not a targeting error. Check the
header before debugging OAuth.

## `validateOnly` — free insurance on any mutation

```json
{"validateOnly":true,"operations":[...]}   // returns {} on success, changes nothing
```

Verified: a `validateOnly` budget change returned `{}` and left the value untouched. Neither
unskilled agent used it and neither needed it — their mistakes were rejected by the API anyway. Its
real value is the case they never hit: a mutation that is **valid but wrong** (a mistyped budget),
which no error will catch. Use it whenever the operation spends money or you can't cheaply undo it.

## Reading performance

```bash
treg call google-ads "v25/customers/<CID>/googleAds:search" --method POST --data '{
  "query":"SELECT campaign.name, campaign.status, campaign_budget.amount_micros,
           metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions
           FROM campaign WHERE segments.date DURING LAST_30_DAYS
           ORDER BY metrics.cost_micros DESC"}'
```

Metrics need a date condition (`DURING LAST_30_DAYS`, or `BETWEEN '2026-06-01' AND '2026-06-30'`) —
without one you get lifetime totals. Use `googleAds:searchStream` for large unpaginated pulls.
Keyword-level detail lives in `keyword_view`.

**On zero conversions** (✅ 2/2 agents already handle this): an audited account showed ~$300 spent, ~170 clicks, 0 conversions because nothing is instrumented. Both unskilled agents correctly said they
couldn't distinguish "no tracking" from "no results" — keep doing that, and check before treating
zero as a performance verdict.

## Creating a campaign — minimum that works

Budget first, then campaign. Verified end-to-end.

```json
// campaignBudgets:mutate
{"operations":[{"create":{"name":"...","amountMicros":3000000,
  "deliveryMethod":"STANDARD","explicitlyShared":false}}]}

// campaigns:mutate
{"operations":[{"create":{
  "name":"...", "status":"PAUSED",
  "advertisingChannelType":"SEARCH",
  "campaignBu
add-oauth-providerSkill

Add a provider to treg's OAuth registry (the ones treg holds its own approved app for). Use when asked to "add YouTube/Notion/Meta OAuth", "support connecting X", "add a new OAuth provider", or when a connect flow, capability picker, channel/account picker, or provider health probe needs building. Covers the code changes, the platform-side approval steps, and the pitfalls that don't announce themselves.

ads-conversion-trackingSkill

Use when setting up, changing or debugging treg's own conversion tracking — the ad-click capture, the AdConversion outbox, or the Data Manager uploader — and whenever asked whether conversions are "working", "live" or "verified". Also use before claiming any part of the pipeline is proven.

dev-localSkill

One-command local dev stack for tools-registry. Use when asked to "start the dev server", "run treg locally", "test login locally", "bring the stack up", or before any manual/browser test against localhost.

google-analyticsSkill

Traps to avoid when querying Google Analytics 4 through treg — cases where the GA4 Data API returns a confident wrong answer instead of an error. Use whenever answering questions about site traffic, visitors, pageviews, channels, conversions, or revenue from GA4.

google-search-consoleSkill

Traps to avoid when querying Google Search Console through treg — cases where the API returns a confident wrong answer instead of an error, especially around totals and recent-date trends. Use whenever answering questions about organic search clicks, impressions, rankings, or index status.

tools-registry-contextSkill

tools-registry context + doc upkeep. Use to warm up a fresh session (orient on the architecture + recent commits) or when working on tools-registry — changing code, rules, content, data, or process (proxy · auth/secrets · API · CLI · the registry skill) — loads the relevant fragment(s) from docs/context so you act with accurate, cited context. Accepts an optional focus query (e.g. `/tools-registry-context <area>`). Also runs `/tools-registry-context sync` to update the doc fragments after changes (show → approve → apply). Mention it whenever a push to the main branch is near.

treg-pageSkill

Write a treg.to agent page (/agents/<client>) or use-case page (/use-cases/<category>/<job>). Researches the real problem on Reddit and X with agent-reach BEFORE writing, so the page targets the words buyers actually use and quotes their own questions. Use when adding a page from marketing/pseo-ship-plan.md, or when asked to "write the <job> page" / "add the <agent> page".

write-provider-skillSkill

Build a treg provider skill — the endpoint map + mistake map that lets an agent do real work on a platform API through treg's proxy. Use when adding a skill for a connected provider (Google Ads, LinkedIn, Meta Ads, TikTok, X, Instagram, Search Console), or when an existing provider skill needs verifying or extending.