# Google Ads Change History

> Answer "what changed on this client's Google Ads account, and who changed it?" for up to 90 days, as a read-only timeline grouped by day and by user with budget, bid and status changes highlighted and a draft escalation summary for…

Google Ads Change History is an AI skill that you can use in Claude Code, Codex, or type.com. It works with Google Ads.

- Skill page: https://typestaging.com/library/skills/google-ads-change-history
- Raw SKILL.md: https://typestaging.com/library/skills/google-ads-change-history/SKILL.md
- Created by Kurt Henninger (fourteenwm) · adapted by type.com
- Updated: September 24, 2026
- Package: 13 files

## How to use Google Ads Change History

1. **type.com:** Choose Use Skill to add Google Ads Change History to your type.com workspace.
2. **Claude Code:** Download the skill and extract it into ~/.claude/skills/google-ads-change-history/ (or .claude/skills/google-ads-change-history/ in a project). Then ask Claude to use Google Ads Change History.
3. **Codex:** Download the skill and extract it into ~/.agents/skills/google-ads-change-history/ (or .agents/skills/google-ads-change-history/ in a repository). Then ask Codex to use Google Ads Change History.

## Frequently asked questions

### What is Google Ads Change History?

Google Ads Change History is an AI skill that you can use in Claude Code, Codex, or type.com. It works with Google Ads.

### What does Google Ads Change History do?

Answer "what changed on this client's Google Ads account, and who changed it?" for up to 90 days, as a read-only timeline grouped by day and by user with budget, bid and status changes highlighted and a draft escalation summary for…

### Can I use Google Ads Change History in Claude Code or Codex?

Yes. Google Ads Change History is a standard Agent Skills folder with a SKILL.md file. Download it and extract it into ~/.claude/skills/ for Claude Code or ~/.agents/skills/ for Codex.

### Who created Google Ads Change History?

Kurt Henninger (fourteenwm) created Google Ads Change History, and the type.com team adapted it for the Skills Library. The type.com team reviews every skill before it is published in the Skills Library.

## Example output

Example output from a sample run. Company names and figures are sample data.

```markdown
## Google Ads change history: Harbor & Vine (123-456-7890), 2026-06-23 to 2026-09-20 (USD)

**14 changes with user and old/new values between 2026-08-22 and 2026-09-20 (budget 2, bid 4, status 4, setting 1, other 3).** 11 were made by named users and 3 came from Google Ads automation, including an auto-applied recommendation that turned the Display Network on for Brand - Search on a Saturday.

**Budget, bid and setting changes**

| When | Who | Item | Change |
| --- | --- | --- | --- |
| 2026-08-25 10:12 | jane.doe@brightpath.agency | Budget "Brand - Search Budget" | 50.00 USD → 75.00 USD |
| 2026-08-25 10:15 | jane.doe@brightpath.agency | Campaign "Brand - Search" | target ROAS 400% → 350% |
| 2026-09-02 09:05 | mark.lee@brightpath.agency | Keyword "washed linen sheets" | max CPC 1.10 USD → 1.30 USD |
| 2026-09-02 09:05 | mark.lee@brightpath.agency | Keyword "linen duvet cover" | max CPC 1.20 USD → 1.45 USD |
| 2026-09-10 02:00 | Automated rule | Budget "PMax - All Products Budget" | 120.00 USD → 100.00 USD |
| 2026-09-18 13:05 | mark.lee@brightpath.agency | Campaign "PMax - All Products" | target ROAS (none) → 500% |
| 2026-09-19 10:00 | Auto-applied recommendation | Campaign "Brand - Search" | Display Network off → on |

**By user**

| User | Changes | Breakdown | Via |
| --- | ---: | --- | --- |
| jane.doe@brightpath.agency | 5 | budget 1, bid 1, status 1, other 2 | Web UI |
| mark.lee@brightpath.agency | 5 | bid 3, status 2 | API, Google Ads Editor, Web UI |
| Auto-applied recommendation | 2 | setting 1, other 1 | no user email |
| Automated rule | 1 | budget 1 | no user email |
| owner@harborandvine.com | 1 | status 1 | Web UI |

**Next actions**
- Check the automated changes (Auto-applied recommendation 2, Automated rule 1) were intended before attributing them to a person.
- Raise the client-side edit: owner@harborandvine.com paused Non-brand - Bedding on Sat 2026-09-05 at 22:14; jane.doe@brightpath.agency re-enabled it on 2026-09-07 at 08:30.
- Review weekend activity on 2026-08-29, 2026-09-05 and 2026-09-19.
- For 2026-06-23 to 2026-08-21, 7 resources changed but Google Ads does not record who. The drafted client reply says so and waits for account lead review before sending.
- Portfolio view (14 days) covers every client: 7 changes for Harbor & Vine, 3 for Ledgerline Software, and Copper Kettle Coffee SKIPPED because accounts.google_ads_customer_id is missing.

**Inputs:** change_event for 2026-08-22 to 2026-09-20 (who, which tool, old → new values) and change_status for 2026-06-23 to 2026-08-21 (which resources changed). Read-only: nothing in any account was changed.

_Produced by running `bash examples/run.sh` on the sample data bundled with this skill._
```

## Package files

- CLIENTS.md
- DATA_CONTRACT.md
- LICENSE.txt
- NOTICE.md
- SKILL.md
- examples/clients/copper-kettle-coffee/client.json
- examples/clients/harbor-and-vine/client.json
- examples/clients/ledgerline-software/client.json
- examples/expected_output.txt
- examples/fixture_change_events.json
- examples/run.sh
- requirements.txt
- scripts/change_history.py

## SKILL.md

````markdown
---
name: google-ads-change-history
description: Answer "what changed on this client's Google Ads account, and who changed it?" for up to 90 days, as a read-only timeline grouped by day and by user with budget, bid, status and campaign-setting changes highlighted and a draft escalation summary for replying to the client.
---

# Google Ads change history

Use this skill when an account lead asks what changed on a client's Google Ads
account, who changed it, or needs to answer a client question such as "why did
our budget go down last week?" or "who paused the bedding campaign?". It also
gives a portfolio view across every client profile, with each row labelled by
client.

**Read-only.** The script only runs GAQL `SELECT` queries. It never changes a
campaign, budget, bid, status or any other setting, and it writes nothing to
disk. Output goes to the terminal.

## Get the skill's files first

This skill ships scripts and sample data alongside this SKILL.md. Before running any command:

1. **Get the files.** Make sure the skill's other files (`scripts/`, `examples/` and anything else listed with this skill) are in your working folder at the same relative paths. Some environments load only SKILL.md; if yours did, fetch each file from this skill's published files and write it to the matching path. In Type, read them with the skill-file tools. Anywhere else, the Type Skills Library API lists every file with its path, content and `sha256`: GET `https://api.type.com/api/public/library/skills` and take the entry with slug `google-ads-change-history`.
2. **Check the copies are exact.** Compare each file's size in bytes, not characters (and its hash, where your tools report one), with the published version before running. A copy written out from the published file is fine once its byte size and hash match; never run a script you summarised or reconstructed from memory.
3. **Run from the skill's folder**, calling interpreters explicitly: `python3 scripts/…` and `bash examples/run.sh`.
4. **Try the sample first.** If the skill ships `examples/run.sh` and `examples/expected_output.txt`, run `bash examples/run.sh`; its output should match the expected file exactly. If it doesn't, stop and report the first differing line rather than running on real data.

## Before you run it

1. **Client profile.** Resolve the client from `clients/<slug>/client.json`
   (see [CLIENTS.md](CLIENTS.md)). The skill needs
   `accounts.google_ads_customer_id`. If you reach the account through a
   manager (MCC) account, also set `accounts.google_ads_login_customer_id`.
   If a field is missing, the script names it, explains how to add it and
   stops. It does not guess.
2. **Credentials.** Use a standard `google-ads.yaml` or `GOOGLE_ADS_*`
   environment variables. See [DATA_CONTRACT.md](DATA_CONTRACT.md). Never paste
   credentials into the conversation.
3. **Install** (live mode only): `pip install -r requirements.txt`. This pins
   `google-ads==32.0.0`, and the script pins Google Ads API `v25`.

## Run

Run from the directory that contains `clients/`. You can also pass
`--clients-dir`.

```bash
# One client, last 30 days (the default window)
python3 scripts/change_history.py --client harbor-and-vine

# One client, full 90 days: days 1-30 include who changed what; days 31-90 show only which items changed
python3 scripts/change_history.py --client "Harbor & Vine" --days 90

# A specific range (must be inside the last 90 days)
python3 scripts/change_history.py --client harbor-and-vine --start 2026-09-01 --end 2026-09-15

# Portfolio view across every client profile, every row labelled [client-slug]
python3 scripts/change_history.py --all-clients --days 7

# Explicit credentials file
python3 scripts/change_history.py --client harbor-and-vine --google-ads-config ~/secure/google-ads.yaml

# Offline: recorded rows, no API, no credentials (see examples/)
bash examples/run.sh
```

`--fixture <json>` reads recorded `change_event`/`change_status` rows instead
of calling the API. Use it to test the formatting and aggregation or to replay
an export. `--as-of` sets "today" for fixture runs only.

## What the output contains

1. **Header:** client, customer ID, window, and which data source covers which
   dates. It is always marked read-only and draft.
2. **Timeline by day** (oldest first, in the account's time zone). Each line
   shows time, a tag (`[BUDGET]`, `[BID]`, `[STATUS]`, `[SETTING]`, or `[other]`), who made
   the change and which tool they used (Web UI, Editor, API, scripts,
   automated rule, or auto-applied recommendation), what changed, and old and
   new values. Money values use the account currency. Target ROAS appears as a
   percentage, and on/off settings appear as `on` / `off`.
   - `BUDGET`: campaign budget changes, or a campaign moved to another budget.
   - `BID`: bid strategy, target CPA/ROAS, max CPC/CPM/CPV, and bid
     adjustments.
   - `STATUS`: status updates such as pause or enable, and removals.
   - `SETTING`: material campaign settings — networks (Search partners,
     Display Network, YouTube), locations and location targeting options,
     languages, ad schedule, start/end dates and campaign type. Bid strategy
     changes are tagged `BID`.
3. **By user:** change count per person or automated source, broken down by
   category, with the date span and tools used.
4. **Older changes** (only when the window goes past 30 days). This section
   comes from `change_status` and counts which resources changed per day and
   type. It has **no user and no old/new values**.
5. **Escalation summary** (one per client). It lists every budget, bid and
   campaign-setting change (up to 10, then a pointer to the timeline), status outcomes, who made changes, automated sources, changes made
   from the client's own email domain (from `website` in client.json), weekend
   activity, row-cap warnings, and a neutral **suggested reply**. The reply
   only states what the history shows; it does not promise any follow-up, so
   add one yourself if the account lead agrees to it.
6. **Portfolio summary** (`--all-clients` only): per client, change counts by
   category, then how many distinct people (user emails) and how many distinct
   automated sources made them, counted separately.

## How to use the result

- Present the summary to the account lead as a **draft**. Do not send anything
  to the client automatically (CLIENTS.md rule 2).
- Before you attribute a change to a person, check automated sources:
  auto-applied recommendations, automated rules, and scripts explain many
  "nobody did this" questions.
- If a change came from an unknown email address, flag it to the account lead
  as an access question. Do not conclude that the account was compromised.
  The Google Ads UI shows who has access.
- Never mix clients. A single-client run reads only that client's customer ID.
  The portfolio view labels every row.
- This skill does not make fixes. If the lead wants something changed back,
  that is a separate write action. It needs explicit approval in the
  conversation that names the client and the change (CLIENTS.md rule 3).

## Limits

- **30 days of "who".** Google Ads `change_event` only returns changes from
  the last 30 days. That is the only API source that includes user email,
  tool, and old/new values. The query must also include a date range and a
  `LIMIT` of 10,000 or less. The script pages past the limit by timestamp, up
  to 100,000 rows.
- **90 days of "what".** For days 31 to 90, the script uses `change_status`.
  It returns one row per resource, dated by that resource's latest change. It
  has no user, no tool, and no old/new values. If a resource changed again
  later, it drops out of the older part of the window.
- **Nothing older than 90 days** is available through the API. Older changes
  (about 2 years) are in the Google Ads UI under Tools > Change history, which
  can export CSV.
- **change_event is not the full UI log.** Google says it may omit some rows
  shown in the UI's Change History. Not every client type records events. It
  can also lag by up to about 3 minutes.
- **Not captured:** who accepted a manager-account link or changed user
  access; billing and payment changes; many changes Google makes on its own
  (for example automated bidding adjustments inside a Smart Bidding strategy,
  and Performance Max asset serving). Some resource types come back as
  `UNKNOWN`. Performance data is not included, so this skill does not explain
  *why* results moved.
- **Automated changes** from rules, scripts, or auto-applied recommendations
  often have no user email. The report labels the tool instead.
- **Time zone:** timestamps are in the account's time zone. The window is
  calculated from the local date where the script runs, so edge days can be
  off by one across time zones.
- **Currency:** `*_micros` values are divided by 1,000,000 and labelled with
  the account currency. Budget amounts are shown as stored and are not
  converted to a period.

## Files

| File | Purpose |
|---|---|
| `scripts/change_history.py` | Read-only GAQL queries, normalization, and report |
| `requirements.txt` | Pinned `google-ads` client library (live mode only) |
| `examples/` | Synthetic fixture, sample client profiles, `run.sh`, `expected_output.txt` |
| `CLIENTS.md` | Shared client-profile contract |
| `DATA_CONTRACT.md` | Credentials, API version, fields read, outputs |
| `NOTICE.md`, `LICENSE.txt` | Upstream attribution (MIT) and list of modifications |
````
