CHATGPT ADS AdRails 0.8.0

Run ChatGPT Ads with an agent on rails you set

AdRails 0.5.0 supports ChatGPT Ads with 16 guarded tools: plan, validate-only apply, a pause-only spend guard and human approval to activate. Verification is partial: read paths, live spend reads, the guard and validation ran against a real OpenAI Ads account in read-only mode on 2026-11-06; creates, image upload, activation and conversion/audience commits are tested offline but not live yet.

Last reviewed 2026-11-06 with AdRails 0.8.0

CAPABILITIES

What can an AI agent do on ChatGPT Ads with AdRails?

Sixteen adsops_openai_* tools cover the loop end to end: read the account, draft a campaign, check the creative, plan, validate, commit — and pause when spend misbehaves.

Every write goes through one door

An agent cannot push a change by calling a create endpoint directly. It edits a committed desired-state file, runs adsops_openai_plan for a diff and a single-use plan_id, then adsops_openai_apply.

  • Validate first. Apply is validate-only unless commit=true, and commit needs mode=live, commit_policy.allow_commit, committed state and policy files, and the plan_id. selftest: qa_openai_ads
  • Paused on creation. Every new campaign, ad group and ad is created paused. O3 · selftest: qa_openai_ads
  • No duplicate creates. Every create carries an Idempotency-Key, so a retry cannot make a second campaign. O4 · selftest: qa_openai_ads
  • A person turns it on. Activation needs a single-use approval block bound to that campaign and a fresh guard heartbeat. O7, O8 · selftest: qa_openai_suite

The read side

  • Account. adsops_openai_account verifies the key and returns names, status, currency, timezone and brand review state. selftest: qa_openai_ads
  • Status. adsops_openai_status shows campaigns, ad groups, ads with review status and serving issues, spend today and lifetime, caps and the guard's pause point. selftest: qa_openai_ads
  • Insights. adsops_openai_insights returns daily impressions, clicks and spend for 1-90 days at campaign, ad group or ad level. selftest: qa_openai_ads
  • Geo. adsops_openai_geo_lookup resolves countries, regions and markets to the ids the state file needs. selftest: qa_openai_ads

The API key never appears in tool output, the audit chain or the usage meter. O16 · selftest: qa_openai_ads

SPEND CONTROL

Which spend controls stop an agent overspending?

Four layers, in order: a policy file the agent cannot edit, a cumulative cap with room for overdelivery, a pause-only guard, and a human approval before anything serves.

1. Caps the agent cannot touch

  • Limits live outside the agent. Max daily budget, max lifetime budget, max bid, allowed destination domains and required UTM tags sit in a policy file that tools cannot write. O5 · selftest: qa_openai_ads
  • Archiving is off by default. The same policy refuses archive operations unless explicitly allowed. O5 · selftest: qa_openai_ads
  • Cumulative cap. A lifetime spend cap runs per campaign, and optionally per account. O6 · selftest: qa_openai_ads
  • Blockers are visible. adsops_openai_plan lists spend-gate blockers and exposure increases before anything is applied. O5 · selftest: qa_openai_ads

2. Headroom check and the guard

  • 2x assumption. The room-under-cap check assumes OpenAI may deliver up to 2x the daily budget, so a plan that could breach the cap is refused up front. O9 · selftest: qa_openai_ads
  • Pause-only. adsops_openai_guard pauses when lifetime spend reaches the pause point (cap minus 2x-overdelivery headroom), when today's spend is anomalous, or when live budgets and bids exceed policy. It never activates or raises anything. O10 · selftest: qa_openai_ads
  • Out-of-band changes too. It also pauses budget raises and uncapped bids made outside AdRails, and orphaned campaigns. O11, O12 · selftest: qa_openai_ads
  • Fails closed. If spend cannot be read, the guard does not assume the best. O13 · selftest: qa_openai_ads

3. What the rails do not cover

  • Delivery is not bounded. AdRails does not bound what OpenAI delivers; a daily budget can overdeliver up to 2x. That is why the guard pauses on a computed pause point instead of promising a hard ceiling. O9 · selftest: qa_openai_ads
  • Shell access. An agent with shell access as the same OS user can bypass local rails unless you run the hardened install with a separate OS user; the privilege-boundary item is still open in the threat model. selftest: enterprise_tools
LAUNCH

How do I get my first ChatGPT Ads campaign live?

Nine steps from an API key to an active campaign. Nothing is created serving, and nothing spends before a person approves it.

01

Key per ad account

Store one OpenAI Ads API key per ad account in the config. Run adsops_openai_account to confirm the key, currency, timezone and brand review state before anything else.

02

Start in read-only

Set the adapter config to read-only mode. Pull status and insights for a week or two so you know the baseline spend and serving pattern before an agent proposes a change.

03

Look up locations

adsops_openai_geo_lookup resolves the countries, regions or markets you actually sell into and returns the ids for targeting.location_ids.

04

Draft from a brief

adsops_openai_draft_campaign turns account, landing page, offer, daily budget, lifetime cap, context hints and your agent-written ads into a desired-state file and a policy file the engine accepts.

05

Check every ad

adsops_openai_ad_check enforces title 3-50 characters, body up to 100, an https URL up to 2048, 1 or 4-6 images, allowed domains, required UTM tags, and flags duplicates across the account. O19 · selftest: qa_openai_ads

06

Upload the images

adsops_openai_upload_image checks dimensions (ad image at least 640x640, favicon at least 256x256) and returns a file_id. It only checks unless commit=true.

07

Plan

adsops_openai_plan diffs committed state against live and shows ops, notes, exposure increases, spend-gate blockers and a single-use plan_id. No writes happen here.

08

Apply, validate-only

Run adsops_openai_apply without commit=true. It returns schema and gate results. Fix what it flags; do not reach for the commit flag to get past a blocker.

09

Approve, then activate

A human approves the campaign-bound plan and the guard heartbeat is fresh; the commit then lands the campaign, still paused. Activation is the one step a person owns. O7, O8 · selftest: qa_openai_suite

MEASUREMENT

How do I know which ad is winning?

A leader, an interval, and a correction for looking at more than one pair. That is the difference between a winner and noise.

adsops_openai_ab_report

  • Per-ad rates. CTR per ad, plus conversion rate when the data is available, each with a 95% interval. O19 · selftest: qa_openai_ads
  • A named leader. The report ranks ads and states which one leads on the metric you asked for.
  • Corrected for multiple looks. Comparisons are Bonferroni-corrected, so five ads do not manufacture a winner. O19 · selftest: qa_openai_ads
  • Conservative pause advice. It recommends pausing only ads that are significantly worse, never one that is merely behind. O19 · selftest: qa_openai_ads

Getting clean input

  • Deduplicate before you test. adsops_openai_ad_check flags duplicate and near-duplicate chat cards across the account, so two ads are not the same ad twice. O19 · selftest: qa_openai_ads
  • Pull the raw days. adsops_openai_insights returns daily impressions, clicks and spend at ad level for 1-90 days, which is what the report reads. selftest: qa_openai_ads
  • Read review status first. adsops_openai_status shows review status and serving issues per ad. An ad that is not serving is not losing. selftest: qa_openai_ads
OPTIMISATION

How do I feed real leads back so ChatGPT Ads optimizes?

Two tools: one makes sure the pixel and the lead_created event exist, the other sends your CRM outcomes with personal data hashed on your machine.

Set the destination up once

  • Idempotent setup. adsops_openai_conversions_setup makes sure a web pixel and a lead_created event setting exist, reusing ones with the same names instead of making duplicates. O15 · selftest: qa_openai_ads
  • Key handling. It can create a Conversions API key and write it to the configured key file with chmod 600; the key itself is never printed. O15, O16 · selftest: qa_openai_ads
  • Prove the pipe. adsops_openai_test_event sends one lead_created event with validate_only=true, so it is never saved and never counted. O15 · selftest: qa_openai_ads

Send real outcomes

  • Hashed locally. adsops_openai_send_conversions normalises and SHA-256 hashes emails, phones and names on your machine; raw personal data never leaves it. O19 · selftest: qa_openai_ads
  • Stale events are dropped. Events older than 7 days are skipped rather than sent late and misattributed. O19 · selftest: qa_openai_ads
  • Re-sends dedupe. Deterministic event ids mean a retry after a timeout does not double-count a lead. O19 · selftest: qa_openai_ads
  • Validate-only by default. Nothing is sent until you pass commit=true. O19 · selftest: qa_openai_ads

Send qualified leads and closed sales, not just form fills. ChatGPT Ads optimizes toward whatever you send, so the event you choose is the behaviour you buy.

EXCLUSIONS

How do I exclude current customers?

Turn the customer list you already have into a custom audience, then keep paying for net-new demand instead of re-buying people who already bought.

adsops_openai_audience

  • Local hashing. Emails and phones are hashed on your machine into the documented email_sha256 and phone_number_sha256 files. O19 · selftest: qa_openai_ads
  • Four operations. op=create|add|remove|replace covers the first upload and every monthly refresh of the list. O19 · selftest: qa_openai_ads
  • Plan first. It is plan-only unless you pass commit=true, and it returns the plan and counts so you can check the match rate before committing. O19 · selftest: qa_openai_ads
  • Pairs with the policy caps. Audience work does not bypass the policy file: allowed domains, UTMs and budget caps still apply to anything the agent proposes. O5 · selftest: qa_openai_ads

List hygiene, briefly

Start from a clean CSV: one row per customer, lowercase emails, E.164 phone numbers where you have them, no internal test records. A list polluted with your own QA addresses excludes the wrong people and wastes the first week of learning.

Keep the source file out of the repo. Only the hashed output needs to reach the state directory, and the raw list should never be in a git commit or an agent's context.

EVIDENCE

What has been verified live, and what hasn't?

The exact wording from the claims ledger, unedited. If a vendor page is vaguer than this about live testing, treat the gap as real.

Ran against a real account

"read paths, live spend reads, the guard and validation ran against a real OpenAI Ads account in read-only mode on 2026-11-06; that live run found and fixed an insights rule the offline mock missed." O17 · selftest: qa_openai_ads

Tested offline only

"Creates, image upload, activation and the conversion/audience commits are tested offline but have NOT yet run against a live account." O17 · selftest: qa_openai_ads

What that means for your first week

  • Offline test weight. adrails --selftest runs 2,704 checks, all passing; the ChatGPT Ads suites alone are qa_openai_ads 160/0 and qa_openai_suite 24/0. selftest: qa_openai_ads, qa_openai_suite
  • Independent checks. 35 independent black-box suites and 22 hand-written aggressive tests pass against the release. selftest: qa_openai_suite
  • Run step 8 first. Do your first apply validate-only, read the returned gate results, then commit. The rails are the same on the first run as on the fiftieth.
  • Verify the code. adsops_sbom emits a CycloneDX 1.5 SBOM and a SHA-256 manifest of every package file, so you can check the code you run is the code that was released. selftest: sbom
COMPARISON

How does it compare with other ChatGPT Ads MCP servers?

Two released open-source options, different centre of gravity: breadth of coverage versus governance of spend.

trakkr's OpenAI Ads MCP

  • Coverage. 27 tools in 8 groups, MIT licensed, v0.1.7, installed via npx, uvx, Docker or the MCP Registry, with a hosted Streamable HTTP endpoint that is read-only. source: trakkr.ai/openai-ads-mcp, read 2026-11-06
  • Its safety rails. A read-only env flag hides write tools, new campaigns and ads are created paused, and a budget ceiling env var defaults to $100 with an explicit confirm to exceed it.
  • What its page does not state. No built-in approval mechanism, no validate/dry-run, no audit log and no cumulative spend cap are described. source: trakkr.ai/openai-ads-mcp, read 2026-11-06

AdRails 0.5.0

  • Released too. ChatGPT Ads shipped in 0.5.0; the current release is PyPI adrails 0.8.0, MCP Registry dev.adrails/adrails 0.8.0, with 82 tools across 8 groups. selftest: qa_openai_ads
  • Built for spend governance. Policy caps the agent cannot edit, cumulative caps, 2x-overdelivery headroom, a pause-only guard, and approval before activation. O5, O6, O9, O10 · selftest: qa_openai_ads
  • They compose. Run trakkr hosted read-only for reporting and AdRails for guarded writes; both are open source and both speak to the same account.
  • Full breakdown. AdRails vs trakkr for ChatGPT Ads MCP.
FAQ

Straight answers.

Is ChatGPT Ads support in AdRails released?

Yes. AdRails 0.5.0 is released on PyPI as adrails 0.5.0, in the MCP Registry as dev.adrails/adrails 0.5.0 and as GitHub release v0.5.0, with 82 MCP tools in 8 groups. Sixteen of those tools are the adsops_openai_* ChatGPT Ads group.

Have creates actually run against a live OpenAI Ads account?

No. The exact ledger wording is: read paths, live spend reads, the guard and validation ran against a real OpenAI Ads account in read-only mode on 2026-11-06; that live run found and fixed an insights rule the offline mock missed. Creates, image upload, activation and the conversion/audience commits are tested offline but have NOT yet run against a live account. Run your first campaign validate-only and watch it.

Can the agent raise a budget by itself?

No. Max daily budget, max lifetime budget, max bid, allowed destination domains and required UTM tags live in a policy file the tools cannot write. Plans that increase exposure are refused when the guard heartbeat is stale, and activation needs a single-use human approval bound to that campaign plus a fresh heartbeat. The guard can pause; it can never enable or raise anything.

How do I stop an agent spending past a lifetime cap?

Three layers stack. A cumulative spend cap is set per campaign and optionally per account. The room-under-cap check assumes OpenAI may deliver up to 2x the daily budget, so a plan that could breach the cap is refused before commit. adsops_openai_guard then pauses at cap minus the 2x-overdelivery headroom, and fails closed if spend cannot be read.

How are conversions and customer lists handled?

Emails, phones and names are normalised and SHA-256 hashed locally, so raw personal data never leaves your machine. send_conversions is validate-only unless commit=true, skips events older than 7 days and uses deterministic event ids so re-sends dedupe. audience writes the documented email_sha256 and phone_number_sha256 files and is plan-only unless you commit.

How does this compare with trakkr's OpenAI Ads MCP?

Both are open source and both are released. trakkr has broader coverage at 27 tools, including audiences and A/B context hint workflows, plus a hosted read-only endpoint. AdRails has the spend-governance layer: policy caps an agent cannot edit, cumulative caps, a pause-only guard with 2x headroom and approval to activate. They can run side by side: trakkr hosted read-only for reporting, AdRails for guarded writes.