{"_id":"@ads-repo/bidding-update-impact","name":"@ads-repo/bidding-update-impact","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ads-repo/bidding-update-impact","version":"0.1.0","description":"Measure whether Google's 17 August 2026 target-based bidding change actually affected a Google Ads account. Corrects for conversion lag, runs difference-in-differences against campaigns the change cannot touch, and reports the spend still at risk. Install","keywords":["google-ads","smart-bidding","tcpa","troas","bidding-update","ppc","difference-in-differences","conversion-lag","ai-agent","claude-code","codex","cursor","skill","adsrepo"],"homepage":"https://adsrepo.com/products/bidding-update-impact","license":"SEE LICENSE IN LICENSE.md","author":{"name":"AdsRepo","email":"denis@adsrepo.com"},"type":"module","bin":{"bidding-update-impact":"bin/install.mjs"},"scripts":{"prepack":"rm -rf Setup && cp -RL ../Setup ./Setup"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"_id":"@ads-repo/bidding-update-impact@0.1.0","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-zHGJdPL5xPFpxPprn8moLqGxDTXVFp/JRKF4XrYAe5zB4djg1xk/fUnsOXmlqoWBZPdlBIxv8r1COA7zY5FIKQ==","shasum":"9ee8d21d0ee6407a5bf403b837d2095851b3cfd0","tarball":"https://registry.npmjs.org/@ads-repo/bidding-update-impact/-/bidding-update-impact-0.1.0.tgz","fileCount":29,"unpackedSize":345903,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIB1R9FfPHWh08gn9r4WZR/aZwxqp1JV5PRqji3H2ScHQAiEAoJFP/xEnZSiopC9PEXVvKQIgjK/rNJ3Apb1J6YNAGHg="}]},"_npmUser":{"name":"denis-adsrepo","email":"denis@adsrepo.com"},"directories":{},"maintainers":[{"name":"adsrepo","email":"tomas@adsrepo.com"},{"name":"denis-adsrepo","email":"denis@adsrepo.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bidding-update-impact_0.1.0_1787737983968_0.963167378434441"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-26T09:53:03.094Z","0.1.0":"2026-08-26T09:53:04.108Z","modified":"2026-08-26T09:53:04.355Z"},"maintainers":[{"name":"adsrepo","email":"tomas@adsrepo.com"},{"name":"denis-adsrepo","email":"denis@adsrepo.com"}],"description":"Measure whether Google's 17 August 2026 target-based bidding change actually affected a Google Ads account. Corrects for conversion lag, runs difference-in-differences against campaigns the change cannot touch, and reports the spend still at risk. Install","homepage":"https://adsrepo.com/products/bidding-update-impact","keywords":["google-ads","smart-bidding","tcpa","troas","bidding-update","ppc","difference-in-differences","conversion-lag","ai-agent","claude-code","codex","cursor","skill","adsrepo"],"author":{"name":"AdsRepo","email":"denis@adsrepo.com"},"license":"SEE LICENSE IN LICENSE.md","readme":"# Bidding Update Impact\n\n**Did Google's 17 August 2026 bidding change actually hit this account — and what did it cost?**\n\nOn 17 August 2026 Google stopped letting budget-limited campaigns on a target-based\nbid strategy **overperform** their target. A tCPA of €10 that had been quietly\ndelivering €5 now drifts toward €10. Spend is capped either way; what changes is\nwhat that spend buys.\n\nHalf the industry is currently answering this question with a before/after\nspreadsheet. That answer is usually wrong.\n\n## Why the obvious approach fails\n\nFrom a real account (PMax, tROAS 6.0, budget-constrained):\n\n| Window | Spend | Conv. value | ROAS |\n|---|---|---|---|\n| 10–16 Aug | 34,577 | 155,915 | **4.51** |\n| 17–23 Aug | 34,267 | 128,933 | **3.76** |\n\nReads like a 17% collapse. It isn't. That account's own conversion-lag curve shows\nonly **79.8% of conversion value has matured by day 7** — the post window was still\nfilling in. Corrected, it lands at **~4.7: up, not down.**\n\nThe naive comparison inverted the conclusion.\n\nOn synthetic data with a *known* answer, the gap is starker still: in a scenario\nwith **zero** injected effect but a normal seasonal dip, raw ROAS reads 4.99 → 3.74,\na 25% apparent collapse. This skill returns **NOT_YET_DETECTED** and a\ndifference-in-differences of **−0.0%**.\n\n## What it does\n\n1. **Classifies** every campaign into treatment and three control groups, handling\n   the four different fields a bid target can hide in and the campaign types Google\n   excluded. (A live account had an App campaign on Target CPA *and* flagged\n   budget-constrained — a textbook false positive. App is out of scope.)\n2. **Corrects for conversion lag** using the account's own curve, so a fresh window\n   isn't compared against a matured one.\n3. **Difference-in-differences** against campaigns the update provably cannot have\n   touched, so seasonality cancels instead of being reported as impact.\n4. **Excludes contaminated campaigns** — anything a human re-budgeted or retargeted\n   mid-window gets no verdict, and says who changed it.\n5. **Recommends targets** for campaigns still at risk. It never writes to the\n   account.\n\nOutput: a self-contained `report.html`, plus `analysis.json` for auditing and\n`raw_pull.json` as a permanent snapshot.\n\n## Verdicts\n\n| | |\n|---|---|\n| `AFFECTED` | Treatment converged toward target; control didn't. Real signal. |\n| `NOT_YET_DETECTED` | No divergence found. The rollout is gradual — **not yet, or not at all**. Never \"unaffected\". |\n| `TOO_EARLY` | Post window too short or too immature. No verdict is honest here. |\n| `CONFOUNDED` | Too many mid-window edits to attribute anything. |\n\nEven on a null verdict the report gives the **exposure** figure — spend sitting in\ncampaigns that were overperforming and are therefore still at risk whenever the\nrollout reaches them. That number is actionable regardless.\n\n## Run it\n\n```bash\n# demo, no account needed\npython scripts/sample_data.py --scenario affected --out raw_pull.json\npython scripts/analyze.py --raw raw_pull.json --out analysis.json\npython scripts/build_report.py --data analysis.json --out report.html\n```\n\nAgainst a real account, replace step 1 with the five GAQL pulls in\n`reference/gaql-queries.md` (all validated live) and follow `SKILL.md`.\n\nScenarios: `affected`, `null`, `too-early`, `confounded` — each with known ground\ntruth, which is how the engine is tested.\n\n## ⚠️ Time limit\n\n`change_event` reaches back **30 days only**. From roughly **17 September 2026**,\nchange history around the switch date is gone permanently — after that there is no\nway to prove whether a target was human-edited or moved by the rollout. Capture\n`raw_pull.json` for any account you might want to analyse before then.\n\n## Files\n\n```\nSKILL.md                      workflow the agent follows\nreference/the-change.md       what Google actually announced, with sources\nreference/methodology.md      why the naive test fails, and the honesty rules\nreference/gaql-queries.md     validated GAQL + the field traps\nreference/data-schema.md      raw_pull.json contract\nscripts/analyze.py            classification, lag correction, DiD, verdict\nscripts/build_report.py       HTML renderer\nscripts/sample_data.py        ground-truth fixtures for tests and demos\nassets/                       example reports\n```\n\nRequires Python 3.9+ and the `googleAdsServer` MCP. No third-party packages.\nRead-only throughout.\n","readmeFilename":"README.md","_rev":"1-a96c2229c8add9f11c57f377c2f91011"}