Campaign performance, creative fatigue and event health.
Quick start · Example output · Tests · Releases · Contributing
A read-only Python toolkit for Facebook and Instagram advertising analysis. It reads Marketing API data, works out why ad sets stall, what changed before a metric moved and which creatives are wearing out, and combines specialist findings into reports through the /meta-ads agent workflow.
| Area | Included capabilities |
|---|---|
| Performance | Spend, purchases, revenue, ROAS, CPA, CTR and frequency at campaign, ad-set and ad level |
| Creative | Creative metadata, metrics, and per-ad fatigue scored from frequency, CTR change and CPM drift over the period |
| Audiences | Age, gender, geography, device and placement breakdowns |
| Measurement | Pixel health, browser and Conversions API coverage per event, and conversion-funnel checks |
| Budget | Agent analysis of utilization, pacing and bid-strategy fit |
| Change history | Activity log lined up with each entity's metrics before and after a change |
| Delivery | Stalled ad sets: caps below the account's real CPA, learning phase status, budgets too small for the optimisation event |
| Reports | Markdown, HTML, PDF, CSV tables and period comparisons |
The adapters retrieve data and compute the delivery, change history and fatigue checks; specialist agents interpret the results. The complete audit is an agent skill, not a standalone meta_audit.py command. Account mutation is not implemented.
Meta ships its own Ads MCP server. It lists accounts and entities, runs insights queries, reads the activity log and datasets, offers benchmarks and anomaly signals, and creates and changes campaigns. This toolkit does not rebuild that. It covers the analysis the server leaves to the person running the account:
| Question | Official server | This toolkit |
|---|---|---|
| Why is this ad set not spending? | Returns the raw bid, budget and learning fields | meta_delivery.py compares them with the account's real cost per result |
| What changed before this dropped? | Activity log and insights are separate tools | meta_changes.py lines each change up with the metrics before and after |
| Which creatives are wearing out? | Frequency and CTR series, no score | meta_creatives.py --fatigue scores each ad |
| How do conversions differ by attribution window? | No window parameter | meta_insights.py --attribution |
| Can I get a report file, or diff two runs? | Conversational output | Markdown, HTML, PDF and CSV reports; sorted, stable JSON |
To change anything in an account, use Ads Manager or the official server. The full comparison, with sources, is in the roadmap.
Requires Python 3.10+, a Meta app and access to the ad account. See docs/SETUP.md for app setup and permissions.
git clone https://github.com/arcbaslow/meta-ads-agents.git
cd meta-ads-agents
python -m venv .venvActivate with source .venv/bin/activate on macOS/Linux or .venv\Scripts\Activate.ps1 in Windows PowerShell, then:
python -m pip install -e ".[dev]"Run the adapters from the cloned repository. The project is distributed as an agent toolkit; the source tree includes the scripts, reference material and skill definitions needed for that workflow.
Configure credentials using the OAuth browser flow:
python scripts/meta_auth.py --oauth --app-id YOUR_APP_ID --app-secret YOUR_APP_SECRET
python scripts/meta_auth.py --check
python scripts/meta_auth.py --accountsThe callback listens on localhost:8477. For environments where that flow is unavailable, use the manual configuration path documented in setup. Credentials are stored locally in ~/.claude/meta-ads-credentials.json; never commit that file.
To run without a credentials file, for example in CI or on a schedule, set META_ACCESS_TOKEN. When it is set the adapters use it and do not read the file.
Replace the example account ID with one returned by --accounts:
python scripts/meta_insights.py --account act_123456789 --days 30
python scripts/meta_creatives.py --account act_123456789 --with-metrics
python scripts/meta_events.py --account act_123456789 --health-checkBoth 123456789 and act_123456789 are accepted and normalized to act_123456789. Data adapters print JSON to stdout.
This screenshot shows the actual Markdown report rendered for documentation, with synthetic campaign data. Reproduce it without a Meta account:
python scripts/meta_report.py --input examples/demo/account.json --format md --output report.md
python scripts/meta_report.py --input examples/demo/account.json --format html --output report.htmlRead the generated report or inspect the report input. The report input is an assembled report object, not the raw response from meta_insights.py.
With the repository's plugin and skills loaded, the router provides:
/meta-ads audit act_123456789
/meta-ads performance act_123456789
/meta-ads creative act_123456789
/meta-ads audience act_123456789
/meta-ads events act_123456789
/meta-ads budget act_123456789
/meta-ads delivery act_123456789
/meta-ads changes act_123456789
The audit skill distributes work across the specialists in agents/, then combines their findings. Other agent runtimes can follow AGENTS.md and run the underlying adapters directly.
python scripts/meta_insights.py --account act_123456789 --level adset --breakdown age --days 30
python scripts/meta_report.py --input examples/demo/account.json --format pdf --output report.pdf
python scripts/meta_report.py --input examples/demo/account.json --format csv --output csv-output
python scripts/meta_report.py --input current.json --compare previous.json --format md --output comparison.mdCampaign queries typically use 30 days; event checks use 7. Inspect the adapter's --help for overrides. Benchmark reference files in skills/meta-ads/references/ support interpretation; they are bundled reference material, not continuously updated market data.
python scripts/meta_creatives.py --account act_123456789 --fatigue --days 14Compares each ad's CTR and CPM in the second half of the period with the first half, reads its frequency for the period, and labels it fatigued, near_fatigue or ok with a rotation recommendation. Ads with fewer than --min-impressions (default 1000) in either half are listed as not scored.
python scripts/meta_delivery.py --account act_123456789 --days 7Lists active ad sets that Meta reports an issue on, that served nothing, or that underspend, and checks three causes: a bid or cost cap below the account's cost per optimisation event, learning limited status, and a weekly budget that buys fewer events than the learning phase needs. Findings are sorted and carry their evidence, so two runs on the same data produce the same output. Checks that cannot run are listed under not_evaluated with the reason.
python scripts/meta_changes.py --account act_123456789 --days 14 --window 3
python scripts/meta_changes.py --account act_123456789 --level ad --action-type offsite_conversion.fb_pixel_purchaseReads the ad account activity log and daily insights, and for every change to a campaign, ad set or ad compares spend per day, CPM and CTR (and CPA, when an action type is given) over the days before and after it. Changes followed by a move of 30% or more are listed first. This is a before and after comparison: it shows what moved together, not what caused it.
Responses use a 15-minute JSON cache under the OS temporary directory, in claude-meta-ads/. Pass --no-cache to refresh a query. Retryable rate-limit errors and network failures use exponential backoff.
The adapters call Marketing API v26.0, set in scripts/meta_utils.py. Field availability still depends on the account and its permissions.
A failed call exits with code 1 and prints a JSON error with an error_kind: auth (expired or revoked token), rate_limit (with retry_after_minutes when Meta reports it), too_much_data, network or api. Access tokens are removed from error text before it is printed, logged or cached.
Fatigue, event-health and change-history signals are heuristics to investigate, not proof of a cause.
python -m ruff check scripts/
python -m pytest scripts/ -qThe fixture-based suite requires no Meta account and covers auth and OAuth state validation, cache behavior, campaign and audience queries, creative scoring and fatigue, event health, delivery diagnosis, change history, report formats, error output without tokens, agent-command parsing and version consistency. It also checks every field the adapters request against the installed SDK's field lists. CI runs Python 3.10–3.13. See the release verification.
| Path | Purpose |
|---|---|
| scripts/ | Marketing API adapters, reports and tests |
| agents/ | Performance, creative, audience, events, budget, account, delivery, change history and attribution specialists |
| skills/ | /meta-ads commands and analysis reference material |
| examples/demo/ | Synthetic report input and generated Markdown |
| docs/ | App setup, releases, verification and the roadmap |
v1.1.0 — see the release notes for this release and the changelog for project history.
GitHub Releases include downloadable artifacts and checksums. Package-registry publication is a separate, opt-in workflow; a GitHub release does not imply that the same version is available on PyPI or npm. Maintainers can follow the release guide.
Read CONTRIBUTING.md, run the checks above, and include a minimal reproduction for bugs. Report vulnerabilities through SECURITY.md.
| Project | Use it for |
|---|---|
| Google Ads Agents | Paid media audits, tracking checks and reviewed changes. |
| Google Analytics Agent | GA4 data quality, funnels and property management. |
| Search Console Agent | Search performance, indexing and page experience. |
| GTM Diff | Review the changes in your Google Tag Manager exports. |
| Figma Taxonomy Gen | Turn interactive designs into a reviewable tracking plan. |
Maintained by Good Labs — measurement implementation, tracking plans and analytics audits.
MIT © Dilshat Rakhimov. This is an independent project; it is not an official product of the platform vendors.
