adloop 0.20.0__tar.gz → 0.22.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {adloop-0.20.0 → adloop-0.22.0}/PKG-INFO +39 -12
- {adloop-0.20.0 → adloop-0.22.0}/README.md +37 -11
- {adloop-0.20.0 → adloop-0.22.0}/pyproject.toml +2 -1
- {adloop-0.20.0 → adloop-0.22.0}/pyproject.toml.orig +2 -1
- adloop-0.22.0/src/adloop/ads/conversion_actions.py +2530 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/gaql.py +6 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/read.py +432 -3
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/validate_only.py +35 -2
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/write.py +264 -28
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/auth.py +54 -6
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/config.py +21 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/crossref.py +24 -8
- adloop-0.22.0/src/adloop/ga4/reports.py +513 -0
- adloop-0.22.0/src/adloop/ga4/tracking.py +89 -0
- adloop-0.22.0/src/adloop/ga4/write.py +239 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gsc/reports.py +89 -8
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gtm/client.py +16 -0
- adloop-0.22.0/src/adloop/gtm/entities.py +22 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gtm/read.py +430 -113
- adloop-0.22.0/src/adloop/gtm/write.py +1190 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/pagespeed.py +56 -8
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/read.py +59 -2
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/write.py +147 -1
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/adloop.md +67 -24
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/safety/preview.py +80 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/server.py +847 -63
- adloop-0.20.0/src/adloop/ads/conversion_actions.py +0 -559
- adloop-0.20.0/src/adloop/ga4/reports.py +0 -162
- adloop-0.20.0/src/adloop/ga4/tracking.py +0 -36
- adloop-0.20.0/src/adloop/ga4/write.py +0 -100
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/__main__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/_mcp_patches.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/ai_max.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/brands.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/client.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/currency.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/custom_conversion_goals.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/enums.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/forecast.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/image_fetch.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ads/pmax.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/cli.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/diagnostics.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ga4/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/ga4/client.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gsc/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gsc/client.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/gtm/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/merchant/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/merchant/client.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/merchant/read.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/auth.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/client.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/reddit/schedule.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/analyze-performance.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/budget-plan.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/create-ad.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/create-campaign.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/diagnose-tracking.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules/commands/optimize-campaign.md +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/rules_install.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/runtime.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/safety/__init__.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/safety/audit.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/safety/guards.py +0 -0
- {adloop-0.20.0 → adloop-0.22.0}/src/adloop/tracking.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: adloop
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.
|
|
5
5
|
Keywords: mcp,google-ads,reddit-ads,google-analytics,ga4,cursor,marketing
|
|
6
6
|
Author: Daniel Klose
|
|
@@ -13,6 +13,7 @@ Requires-Dist: google-analytics-admin>=0.27.0
|
|
|
13
13
|
Requires-Dist: google-api-python-client>=2.100.0
|
|
14
14
|
Requires-Dist: google-auth-oauthlib>=1.0.0
|
|
15
15
|
Requires-Dist: google-api-python-client>=2.0.0
|
|
16
|
+
Requires-Dist: phonenumbers>=8.13
|
|
16
17
|
Requires-Dist: pyyaml>=6.0
|
|
17
18
|
Requires-Dist: requests>=2.31
|
|
18
19
|
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
@@ -66,7 +67,7 @@ Both versions run the same tools with the same safety model. The difference is w
|
|
|
66
67
|
| **Works with** | claude.ai, ChatGPT, Claude Code, Cursor, Gemini | Claude Code, Cursor, Claude Desktop, any local MCP client |
|
|
67
68
|
| **Where your data flows** | EU servers (Germany), GDPR-first, DPA included | 100% your machine — nothing leaves it |
|
|
68
69
|
| **Updates** | Automatic | `pip install -U adloop` |
|
|
69
|
-
| **Price** | Free plan, no card; [paid plans](https://getadloop.com/
|
|
70
|
+
| **Price** | Free plan, no card; [paid plans](https://getadloop.com/pricing) for more accounts and volume | Free forever (MIT) |
|
|
70
71
|
|
|
71
72
|
**Not sure? [Start with Cloud](https://getadloop.com)** — it's the fastest way to see what AdLoop can do, and it's the only way to use AdLoop from claude.ai or ChatGPT. Self-host when you want everything on your own machine or need to modify the code. And if you're here to hack on AdLoop itself: welcome, keep scrolling.
|
|
72
73
|
|
|
@@ -109,17 +110,19 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
109
110
|
| Tool | What It Does |
|
|
110
111
|
|------|-------------|
|
|
111
112
|
| `get_account_summaries` | List GA4 accounts and properties |
|
|
112
|
-
| `run_ga4_report` | Custom reports
|
|
113
|
+
| `run_ga4_report` | Custom reports: sessions, users, key events, page performance. Optional dimension and metric filters, ordering, paging, and a comparison period |
|
|
113
114
|
| `run_realtime_report` | Live data — verify tracking fires after deploys |
|
|
114
115
|
| `get_tracking_events` | All configured events and their volume |
|
|
116
|
+
| `list_key_events` | The property's key events (conversions) with counting method, create time and whether they can be deleted |
|
|
117
|
+
| `list_ga4_dimensions_and_metrics` | Every dimension and metric the property can report on, including custom ones, with search |
|
|
115
118
|
|
|
116
119
|
### Google Ads Read Tools
|
|
117
120
|
|
|
118
121
|
| Tool | What It Does |
|
|
119
122
|
|------|-------------|
|
|
120
123
|
| `list_accounts` | Discover accessible Ads accounts |
|
|
121
|
-
| `get_campaign_performance` | Campaign metrics
|
|
122
|
-
| `get_ad_performance` | Ad copy analysis
|
|
124
|
+
| `get_campaign_performance` | Campaign metrics: impressions, clicks, cost, conversions, CPA, Search impression share and share lost to budget/rank |
|
|
125
|
+
| `get_ad_performance` | Ad copy analysis: headlines, descriptions, CTR, policy approval status and topics |
|
|
123
126
|
| `get_keyword_performance` | Keywords — quality scores, competitive metrics |
|
|
124
127
|
| `get_search_terms` | What users actually searched before clicking |
|
|
125
128
|
| `get_negative_keywords` | List direct campaign-level negative keywords |
|
|
@@ -131,6 +134,7 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
131
134
|
| `get_pmax_assets` | Per-asset details for PMax — field type, serving status, content |
|
|
132
135
|
| `get_detailed_asset_performance` | Top-performing asset combinations — which headline+description+image combos Google selects most |
|
|
133
136
|
| `get_audience_performance` | Audience segment performance — remarketing, in-market, affinity, demographics |
|
|
137
|
+
| `get_change_history` | What changed before the drop: who changed what and when, through which client (UI, API, scripts, auto-applied recommendations), last 30 days |
|
|
134
138
|
| `get_demographic_targeting` | List demographic criteria (age/gender/parental status/income) on an ad group or campaign |
|
|
135
139
|
| `suggest_brands` | Resolve a brand name to the brands Google recognizes — brand ID, name, state, URLs |
|
|
136
140
|
| `check_brand_names` | Check a shortlist of brand names against Google's brand knowledge graph (max 25 per call) |
|
|
@@ -177,15 +181,37 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
177
181
|
| `audit_event_coverage` | **The flagship.** Three-way join: codebase events ↔ GTM tags ↔ GA4 actual fires. For each event name in `expected_events`, returns one of 10 statuses (`ok`, `no_tag_no_fire`, `tag_paused`, `tag_active_but_not_firing`, `gtm_only_firing`, `ga4_only`, etc.) plus auto-generated insights for the gaps. |
|
|
178
182
|
| `list_gtm_accounts` | Discover accessible GTM accounts |
|
|
179
183
|
| `list_gtm_containers` | List containers under an account — returns numeric `container_id` (needed by other tools), public `GTM-XXXXXXX` ID, and usage context (web/iOS/Android/server) |
|
|
180
|
-
| `list_gtm_tags` | Every tag in the live container with parsed event names and resolved firing/blocking trigger names |
|
|
184
|
+
| `list_gtm_tags` | Every tag in the live container with parsed event names and resolved firing/blocking trigger names. Pass `workspace_id` to read a workspace's unpublished state instead, so a just-drafted tag is visible (also on `get_gtm_tag`, `list_gtm_triggers`, `get_gtm_trigger`, `list_gtm_variables`) |
|
|
181
185
|
| `get_gtm_tag` | Full raw config for a single tag — every parameter, firing/blocking triggers with filter conditions, priority, pause status, sampling |
|
|
182
186
|
| `list_gtm_triggers` | Every trigger with filter conditions parsed to readable text (e.g. `{{Page Path}} contains service-promotions`, `{{Form ID}} NOT contains wf-form-...`). Renders the `negate` flag explicitly. |
|
|
183
187
|
| `get_gtm_trigger` | Full trigger config + reverse lookup of every tag that uses it. Includes parsed `element_visibility` block (selector, on-screen ratio, firing frequency) for elementVisibility triggers and `group_member_trigger_ids` for triggerGroup types |
|
|
184
188
|
| `list_gtm_variables` | Custom variables (data layer, constants, JS) plus enabled built-in variables |
|
|
185
189
|
| `list_gtm_workspaces` | List drafts (workspaces) under a container — workspace IDs are needed by `get_gtm_workspace_diff` |
|
|
186
190
|
| `get_gtm_workspace_diff` | Drafted-but-not-published changes — common cause of "I edited a tag but nothing happened". Returns `is_clean: true` when nothing is pending. |
|
|
187
|
-
| `list_gtm_versions` |
|
|
188
|
-
| `get_gtm_version` |
|
|
191
|
+
| `list_gtm_versions` | Version history, newest first, with version IDs and entity counts. The Tag Manager API returns no timestamps or author for versions. |
|
|
192
|
+
| `get_gtm_version` | Name, notes and tag/trigger names for a single historical container version |
|
|
193
|
+
| `get_gtm_version_diff` | What a publish changed: added, removed and changed tags, triggers and variables with the changed fields, plus built-in variables enabled or disabled. Defaults to the live version against the one before it; two or three API calls. |
|
|
194
|
+
|
|
195
|
+
#### GTM write tools (opt-in)
|
|
196
|
+
|
|
197
|
+
Off by default. Set `gtm.write_enabled: true` in `~/.adloop/config.yaml` and restart; the next call asks you to re-consent with the Tag Manager edit + publish scopes, which are never part of the default grant. Everything follows the usual draft → preview → `confirm_and_apply` flow, and tag/trigger edits only touch a workspace until you publish it.
|
|
198
|
+
|
|
199
|
+
| Tool | What It Does |
|
|
200
|
+
|------|-------------|
|
|
201
|
+
| `draft_gtm_tag` | Create a tag, or update one by `tag_id`. Updates are a read-modify-write: `parameters` merge by key and every field you don't pass (priority, consent settings, firing options, schedule, folder, …) is preserved. Tag types are canonical GTM template IDs (`googtag`, `gaawe`, `awct`, `sp`, `gclidw`, …) or `cvt_<id>` gallery templates. |
|
|
202
|
+
| `draft_gtm_trigger` | Create a trigger, or update one by `trigger_id` (type is immutable). `custom_event_name` wires a `customEvent` trigger to a dataLayer event. |
|
|
203
|
+
| `draft_delete_gtm_entity` | Delete a workspace tag or trigger. Triggers still referenced by a tag are refused up front, with the tags listed. |
|
|
204
|
+
| `draft_publish_gtm_workspace` | Publish a workspace live. The preview lists every pending change, including edits other people made in the GTM UI. |
|
|
205
|
+
| `draft_rollback_gtm_version` | Republish an older container version live. The preview is the diff from the live version to the target; the plan pins the live version, so apply refuses if someone publishes in between. Workspaces are left as they are. |
|
|
206
|
+
|
|
207
|
+
Safety gates specific to GTM:
|
|
208
|
+
- **Custom HTML** runs arbitrary JavaScript on your site, so creating or editing an `html` tag — or publishing a workspace that adds or changes one — is refused unless `gtm.allow_custom_html: true` is also set. Pausing or deleting one is always allowed.
|
|
209
|
+
- **No stale writes.** Updates and deletes pin the entity's fingerprint from the preview, and publish pins the workspace's pending changes; if someone edits the container in between, apply refuses and you re-draft.
|
|
210
|
+
- Publishing stops on merge conflicts or GTM compiler errors. The dry run runs a Tag Manager **quick preview** first (Tag Manager has no validate-only mode), so compiler errors surface before a version is even created. That preview is a POST and stores a preview version in the container — nothing is published and no live tag changes; the rest of the dry run only reads.
|
|
211
|
+
- The publish and rollback results name the version they replaced (`previous_live_version_id`), so rolling back is one step: `draft_rollback_gtm_version` with that id. If the version was created but publishing it failed, the error carries both the created version id and the still-live one.
|
|
212
|
+
- Per-operation names for `safety.blocked_operations`: `gtm_create_tag`, `gtm_update_tag`, `gtm_delete_tag`, `gtm_create_trigger`, `gtm_update_trigger`, `gtm_delete_trigger`, `gtm_publish_workspace`, `gtm_rollback_version`.
|
|
213
|
+
|
|
214
|
+
The Google account also needs **Edit** permission on the container (and **Publish** to publish) under Admin → User Management.
|
|
189
215
|
|
|
190
216
|
> **Setup for GTM tools** — Enable the **Tag Manager API v2** in your GCP project, then add your AdLoop credentials' email (the OAuth user, or the service account email if using a service account) as a **Read** user on the GTM container under Admin → User Management. Service accounts pick up access on the next call. **OAuth users upgrading from an earlier AdLoop version must re-authorize once**: the GTM scope is new, so delete `~/.adloop/token.json` and run any tool to re-consent — until then GTM tools return a permissions error.
|
|
191
217
|
|
|
@@ -194,13 +220,13 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
194
220
|
| Tool | What It Does |
|
|
195
221
|
|------|-------------|
|
|
196
222
|
| `list_gsc_sites` | List Search Console properties the connected account can access |
|
|
197
|
-
| `run_gsc_report` | Organic search analytics
|
|
223
|
+
| `run_gsc_report` | Organic search analytics: clicks, impressions, CTR, position by query/page/country/device/date/searchAppearance/hour. Supports fresh data (`data_state="all"`), `aggregation_type`, and paging past 25,000 rows with `start_row` |
|
|
198
224
|
|
|
199
225
|
### Web Performance Tools
|
|
200
226
|
|
|
201
227
|
| Tool | What It Does |
|
|
202
228
|
|------|-------------|
|
|
203
|
-
| `analyze_page_speed` | PageSpeed Insights for landing pages
|
|
229
|
+
| `analyze_page_speed` | PageSpeed Insights for landing pages: Lighthouse score, Core Web Vitals, real-user CrUX data (falls back to origin-wide data, labelled as such, when the page has too little traffic), top fixes. No OAuth needed (optional API key). |
|
|
204
230
|
|
|
205
231
|
### Merchant Center Tools
|
|
206
232
|
|
|
@@ -259,6 +285,7 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
259
285
|
| `add_negative_keywords` | Propose negative keywords directly on a campaign |
|
|
260
286
|
| `add_negative_locations` | Propose negative geo exclusions on a campaign — exclude cities/regions while keeping broader positive targets |
|
|
261
287
|
| `draft_key_event` | Mark a GA4 event as a key event (conversion) — the fix for "fires but isn't tracked as a conversion" |
|
|
288
|
+
| `draft_delete_key_event` | Remove a GA4 key event. The event keeps firing but no longer counts as a conversion, for future data only |
|
|
262
289
|
| `draft_demographic_targeting` | Propose demographic criteria (age, gender, parental status, income) — exclusions by default |
|
|
263
290
|
| `propose_negative_keyword_list` | Draft a shared negative keyword list (SharedSet) and attach it to a campaign — reusable across multiple campaigns |
|
|
264
291
|
| `propose_brand_list` | Draft a brand list (SharedSet of type BRANDS) from Commercial KG MIDs and optionally attach it to campaigns — `negative=true` (default) excludes the brands, `false` restricts targeting to them |
|
|
@@ -515,7 +542,7 @@ Most MCP clients (claude.ai, ChatGPT, Cursor, …) load **every tool schema into
|
|
|
515
542
|
| `ads` | Google Ads reads, writes, and planning (Keyword Planner) |
|
|
516
543
|
| `ga4` | Google Analytics reports, realtime, key events |
|
|
517
544
|
| `tracking` | Cross-channel attribution + tracking code generation |
|
|
518
|
-
| `gtm` | Google Tag Manager audits and
|
|
545
|
+
| `gtm` | Google Tag Manager audits, reads, and opt-in writes |
|
|
519
546
|
| `gsc` | Search Console reads |
|
|
520
547
|
| `web` | PageSpeed / Core Web Vitals |
|
|
521
548
|
| `merchant` | Merchant Center feed health |
|
|
@@ -593,7 +620,7 @@ MIT — see [LICENSE](LICENSE).
|
|
|
593
620
|
|
|
594
621
|
## Privacy
|
|
595
622
|
|
|
596
|
-
The open-source version runs entirely on your machine. No data is collected, stored, or transmitted to any server. See [PRIVACY.md](PRIVACY.md) for the full privacy policy. AdLoop Cloud has its own [privacy policy](https://getadloop.com/
|
|
623
|
+
The open-source version runs entirely on your machine. No data is collected, stored, or transmitted to any server. See [PRIVACY.md](PRIVACY.md) for the full privacy policy. AdLoop Cloud has its own [privacy policy](https://getadloop.com/privacy) and [DPA](https://getadloop.com/avv).
|
|
597
624
|
|
|
598
625
|
---
|
|
599
626
|
|
|
@@ -39,7 +39,7 @@ Both versions run the same tools with the same safety model. The difference is w
|
|
|
39
39
|
| **Works with** | claude.ai, ChatGPT, Claude Code, Cursor, Gemini | Claude Code, Cursor, Claude Desktop, any local MCP client |
|
|
40
40
|
| **Where your data flows** | EU servers (Germany), GDPR-first, DPA included | 100% your machine — nothing leaves it |
|
|
41
41
|
| **Updates** | Automatic | `pip install -U adloop` |
|
|
42
|
-
| **Price** | Free plan, no card; [paid plans](https://getadloop.com/
|
|
42
|
+
| **Price** | Free plan, no card; [paid plans](https://getadloop.com/pricing) for more accounts and volume | Free forever (MIT) |
|
|
43
43
|
|
|
44
44
|
**Not sure? [Start with Cloud](https://getadloop.com)** — it's the fastest way to see what AdLoop can do, and it's the only way to use AdLoop from claude.ai or ChatGPT. Self-host when you want everything on your own machine or need to modify the code. And if you're here to hack on AdLoop itself: welcome, keep scrolling.
|
|
45
45
|
|
|
@@ -82,17 +82,19 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
82
82
|
| Tool | What It Does |
|
|
83
83
|
|------|-------------|
|
|
84
84
|
| `get_account_summaries` | List GA4 accounts and properties |
|
|
85
|
-
| `run_ga4_report` | Custom reports
|
|
85
|
+
| `run_ga4_report` | Custom reports: sessions, users, key events, page performance. Optional dimension and metric filters, ordering, paging, and a comparison period |
|
|
86
86
|
| `run_realtime_report` | Live data — verify tracking fires after deploys |
|
|
87
87
|
| `get_tracking_events` | All configured events and their volume |
|
|
88
|
+
| `list_key_events` | The property's key events (conversions) with counting method, create time and whether they can be deleted |
|
|
89
|
+
| `list_ga4_dimensions_and_metrics` | Every dimension and metric the property can report on, including custom ones, with search |
|
|
88
90
|
|
|
89
91
|
### Google Ads Read Tools
|
|
90
92
|
|
|
91
93
|
| Tool | What It Does |
|
|
92
94
|
|------|-------------|
|
|
93
95
|
| `list_accounts` | Discover accessible Ads accounts |
|
|
94
|
-
| `get_campaign_performance` | Campaign metrics
|
|
95
|
-
| `get_ad_performance` | Ad copy analysis
|
|
96
|
+
| `get_campaign_performance` | Campaign metrics: impressions, clicks, cost, conversions, CPA, Search impression share and share lost to budget/rank |
|
|
97
|
+
| `get_ad_performance` | Ad copy analysis: headlines, descriptions, CTR, policy approval status and topics |
|
|
96
98
|
| `get_keyword_performance` | Keywords — quality scores, competitive metrics |
|
|
97
99
|
| `get_search_terms` | What users actually searched before clicking |
|
|
98
100
|
| `get_negative_keywords` | List direct campaign-level negative keywords |
|
|
@@ -104,6 +106,7 @@ The best features come from real workflows. If you're using AdLoop and find your
|
|
|
104
106
|
| `get_pmax_assets` | Per-asset details for PMax — field type, serving status, content |
|
|
105
107
|
| `get_detailed_asset_performance` | Top-performing asset combinations — which headline+description+image combos Google selects most |
|
|
106
108
|
| `get_audience_performance` | Audience segment performance — remarketing, in-market, affinity, demographics |
|
|
109
|
+
| `get_change_history` | What changed before the drop: who changed what and when, through which client (UI, API, scripts, auto-applied recommendations), last 30 days |
|
|
107
110
|
| `get_demographic_targeting` | List demographic criteria (age/gender/parental status/income) on an ad group or campaign |
|
|
108
111
|
| `suggest_brands` | Resolve a brand name to the brands Google recognizes — brand ID, name, state, URLs |
|
|
109
112
|
| `check_brand_names` | Check a shortlist of brand names against Google's brand knowledge graph (max 25 per call) |
|
|
@@ -150,15 +153,37 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
150
153
|
| `audit_event_coverage` | **The flagship.** Three-way join: codebase events ↔ GTM tags ↔ GA4 actual fires. For each event name in `expected_events`, returns one of 10 statuses (`ok`, `no_tag_no_fire`, `tag_paused`, `tag_active_but_not_firing`, `gtm_only_firing`, `ga4_only`, etc.) plus auto-generated insights for the gaps. |
|
|
151
154
|
| `list_gtm_accounts` | Discover accessible GTM accounts |
|
|
152
155
|
| `list_gtm_containers` | List containers under an account — returns numeric `container_id` (needed by other tools), public `GTM-XXXXXXX` ID, and usage context (web/iOS/Android/server) |
|
|
153
|
-
| `list_gtm_tags` | Every tag in the live container with parsed event names and resolved firing/blocking trigger names |
|
|
156
|
+
| `list_gtm_tags` | Every tag in the live container with parsed event names and resolved firing/blocking trigger names. Pass `workspace_id` to read a workspace's unpublished state instead, so a just-drafted tag is visible (also on `get_gtm_tag`, `list_gtm_triggers`, `get_gtm_trigger`, `list_gtm_variables`) |
|
|
154
157
|
| `get_gtm_tag` | Full raw config for a single tag — every parameter, firing/blocking triggers with filter conditions, priority, pause status, sampling |
|
|
155
158
|
| `list_gtm_triggers` | Every trigger with filter conditions parsed to readable text (e.g. `{{Page Path}} contains service-promotions`, `{{Form ID}} NOT contains wf-form-...`). Renders the `negate` flag explicitly. |
|
|
156
159
|
| `get_gtm_trigger` | Full trigger config + reverse lookup of every tag that uses it. Includes parsed `element_visibility` block (selector, on-screen ratio, firing frequency) for elementVisibility triggers and `group_member_trigger_ids` for triggerGroup types |
|
|
157
160
|
| `list_gtm_variables` | Custom variables (data layer, constants, JS) plus enabled built-in variables |
|
|
158
161
|
| `list_gtm_workspaces` | List drafts (workspaces) under a container — workspace IDs are needed by `get_gtm_workspace_diff` |
|
|
159
162
|
| `get_gtm_workspace_diff` | Drafted-but-not-published changes — common cause of "I edited a tag but nothing happened". Returns `is_clean: true` when nothing is pending. |
|
|
160
|
-
| `list_gtm_versions` |
|
|
161
|
-
| `get_gtm_version` |
|
|
163
|
+
| `list_gtm_versions` | Version history, newest first, with version IDs and entity counts. The Tag Manager API returns no timestamps or author for versions. |
|
|
164
|
+
| `get_gtm_version` | Name, notes and tag/trigger names for a single historical container version |
|
|
165
|
+
| `get_gtm_version_diff` | What a publish changed: added, removed and changed tags, triggers and variables with the changed fields, plus built-in variables enabled or disabled. Defaults to the live version against the one before it; two or three API calls. |
|
|
166
|
+
|
|
167
|
+
#### GTM write tools (opt-in)
|
|
168
|
+
|
|
169
|
+
Off by default. Set `gtm.write_enabled: true` in `~/.adloop/config.yaml` and restart; the next call asks you to re-consent with the Tag Manager edit + publish scopes, which are never part of the default grant. Everything follows the usual draft → preview → `confirm_and_apply` flow, and tag/trigger edits only touch a workspace until you publish it.
|
|
170
|
+
|
|
171
|
+
| Tool | What It Does |
|
|
172
|
+
|------|-------------|
|
|
173
|
+
| `draft_gtm_tag` | Create a tag, or update one by `tag_id`. Updates are a read-modify-write: `parameters` merge by key and every field you don't pass (priority, consent settings, firing options, schedule, folder, …) is preserved. Tag types are canonical GTM template IDs (`googtag`, `gaawe`, `awct`, `sp`, `gclidw`, …) or `cvt_<id>` gallery templates. |
|
|
174
|
+
| `draft_gtm_trigger` | Create a trigger, or update one by `trigger_id` (type is immutable). `custom_event_name` wires a `customEvent` trigger to a dataLayer event. |
|
|
175
|
+
| `draft_delete_gtm_entity` | Delete a workspace tag or trigger. Triggers still referenced by a tag are refused up front, with the tags listed. |
|
|
176
|
+
| `draft_publish_gtm_workspace` | Publish a workspace live. The preview lists every pending change, including edits other people made in the GTM UI. |
|
|
177
|
+
| `draft_rollback_gtm_version` | Republish an older container version live. The preview is the diff from the live version to the target; the plan pins the live version, so apply refuses if someone publishes in between. Workspaces are left as they are. |
|
|
178
|
+
|
|
179
|
+
Safety gates specific to GTM:
|
|
180
|
+
- **Custom HTML** runs arbitrary JavaScript on your site, so creating or editing an `html` tag — or publishing a workspace that adds or changes one — is refused unless `gtm.allow_custom_html: true` is also set. Pausing or deleting one is always allowed.
|
|
181
|
+
- **No stale writes.** Updates and deletes pin the entity's fingerprint from the preview, and publish pins the workspace's pending changes; if someone edits the container in between, apply refuses and you re-draft.
|
|
182
|
+
- Publishing stops on merge conflicts or GTM compiler errors. The dry run runs a Tag Manager **quick preview** first (Tag Manager has no validate-only mode), so compiler errors surface before a version is even created. That preview is a POST and stores a preview version in the container — nothing is published and no live tag changes; the rest of the dry run only reads.
|
|
183
|
+
- The publish and rollback results name the version they replaced (`previous_live_version_id`), so rolling back is one step: `draft_rollback_gtm_version` with that id. If the version was created but publishing it failed, the error carries both the created version id and the still-live one.
|
|
184
|
+
- Per-operation names for `safety.blocked_operations`: `gtm_create_tag`, `gtm_update_tag`, `gtm_delete_tag`, `gtm_create_trigger`, `gtm_update_trigger`, `gtm_delete_trigger`, `gtm_publish_workspace`, `gtm_rollback_version`.
|
|
185
|
+
|
|
186
|
+
The Google account also needs **Edit** permission on the container (and **Publish** to publish) under Admin → User Management.
|
|
162
187
|
|
|
163
188
|
> **Setup for GTM tools** — Enable the **Tag Manager API v2** in your GCP project, then add your AdLoop credentials' email (the OAuth user, or the service account email if using a service account) as a **Read** user on the GTM container under Admin → User Management. Service accounts pick up access on the next call. **OAuth users upgrading from an earlier AdLoop version must re-authorize once**: the GTM scope is new, so delete `~/.adloop/token.json` and run any tool to re-consent — until then GTM tools return a permissions error.
|
|
164
189
|
|
|
@@ -167,13 +192,13 @@ These tools read the live GTM container and join it with the codebase + GA4 to f
|
|
|
167
192
|
| Tool | What It Does |
|
|
168
193
|
|------|-------------|
|
|
169
194
|
| `list_gsc_sites` | List Search Console properties the connected account can access |
|
|
170
|
-
| `run_gsc_report` | Organic search analytics
|
|
195
|
+
| `run_gsc_report` | Organic search analytics: clicks, impressions, CTR, position by query/page/country/device/date/searchAppearance/hour. Supports fresh data (`data_state="all"`), `aggregation_type`, and paging past 25,000 rows with `start_row` |
|
|
171
196
|
|
|
172
197
|
### Web Performance Tools
|
|
173
198
|
|
|
174
199
|
| Tool | What It Does |
|
|
175
200
|
|------|-------------|
|
|
176
|
-
| `analyze_page_speed` | PageSpeed Insights for landing pages
|
|
201
|
+
| `analyze_page_speed` | PageSpeed Insights for landing pages: Lighthouse score, Core Web Vitals, real-user CrUX data (falls back to origin-wide data, labelled as such, when the page has too little traffic), top fixes. No OAuth needed (optional API key). |
|
|
177
202
|
|
|
178
203
|
### Merchant Center Tools
|
|
179
204
|
|
|
@@ -232,6 +257,7 @@ All write operations follow a **draft → preview → confirm** workflow. Nothin
|
|
|
232
257
|
| `add_negative_keywords` | Propose negative keywords directly on a campaign |
|
|
233
258
|
| `add_negative_locations` | Propose negative geo exclusions on a campaign — exclude cities/regions while keeping broader positive targets |
|
|
234
259
|
| `draft_key_event` | Mark a GA4 event as a key event (conversion) — the fix for "fires but isn't tracked as a conversion" |
|
|
260
|
+
| `draft_delete_key_event` | Remove a GA4 key event. The event keeps firing but no longer counts as a conversion, for future data only |
|
|
235
261
|
| `draft_demographic_targeting` | Propose demographic criteria (age, gender, parental status, income) — exclusions by default |
|
|
236
262
|
| `propose_negative_keyword_list` | Draft a shared negative keyword list (SharedSet) and attach it to a campaign — reusable across multiple campaigns |
|
|
237
263
|
| `propose_brand_list` | Draft a brand list (SharedSet of type BRANDS) from Commercial KG MIDs and optionally attach it to campaigns — `negative=true` (default) excludes the brands, `false` restricts targeting to them |
|
|
@@ -488,7 +514,7 @@ Most MCP clients (claude.ai, ChatGPT, Cursor, …) load **every tool schema into
|
|
|
488
514
|
| `ads` | Google Ads reads, writes, and planning (Keyword Planner) |
|
|
489
515
|
| `ga4` | Google Analytics reports, realtime, key events |
|
|
490
516
|
| `tracking` | Cross-channel attribution + tracking code generation |
|
|
491
|
-
| `gtm` | Google Tag Manager audits and
|
|
517
|
+
| `gtm` | Google Tag Manager audits, reads, and opt-in writes |
|
|
492
518
|
| `gsc` | Search Console reads |
|
|
493
519
|
| `web` | PageSpeed / Core Web Vitals |
|
|
494
520
|
| `merchant` | Merchant Center feed health |
|
|
@@ -566,7 +592,7 @@ MIT — see [LICENSE](LICENSE).
|
|
|
566
592
|
|
|
567
593
|
## Privacy
|
|
568
594
|
|
|
569
|
-
The open-source version runs entirely on your machine. No data is collected, stored, or transmitted to any server. See [PRIVACY.md](PRIVACY.md) for the full privacy policy. AdLoop Cloud has its own [privacy policy](https://getadloop.com/
|
|
595
|
+
The open-source version runs entirely on your machine. No data is collected, stored, or transmitted to any server. See [PRIVACY.md](PRIVACY.md) for the full privacy policy. AdLoop Cloud has its own [privacy policy](https://getadloop.com/privacy) and [DPA](https://getadloop.com/avv).
|
|
570
596
|
|
|
571
597
|
---
|
|
572
598
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "adloop"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.22.0"
|
|
4
4
|
description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"google-api-python-client>=2.100.0",
|
|
22
22
|
"google-auth-oauthlib>=1.0.0",
|
|
23
23
|
"google-api-python-client>=2.0.0",
|
|
24
|
+
"phonenumbers>=8.13",
|
|
24
25
|
"pyyaml>=6.0",
|
|
25
26
|
"requests>=2.31",
|
|
26
27
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "adloop"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.22.0"
|
|
4
4
|
description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -17,6 +17,7 @@ dependencies = [
|
|
|
17
17
|
"google-api-python-client>=2.100.0",
|
|
18
18
|
"google-auth-oauthlib>=1.0.0",
|
|
19
19
|
"google-api-python-client>=2.0.0",
|
|
20
|
+
"phonenumbers>=8.13",
|
|
20
21
|
"pyyaml>=6.0",
|
|
21
22
|
# Reddit Ads has no SDK; the REST client (adloop.reddit.client) and the
|
|
22
23
|
# PageSpeed helper call requests directly.
|