Push bulk changes to live ad accounts. See exactly what will change first.
Outfitter is the execution layer for paid media, built around Google, Microsoft, Meta and OpenAI Ads. Build a batch of changes, dry-run it against the live account, then publish only what a person approved. The preview is computed by the same code that does the publishing, so what you approve is what runs. Google Ads publishes today.
Google Ads publishes today. Meta is built and in verification. Publishing ships turned off and stays off until you turn it on.
Four steps, and the account only changes on the last one
A changeset is a batch of proposed edits against one connected ad account. It moves through the same four states every time, and it cannot skip one.
Build the batch
Pick operations from a fixed list and point them at entities Outfitter already synced from the account. Nothing is typed free-hand at the platform.
Dry run
Compile the batch against current account state. Each item comes back as publishable, excluded with a reason, or flagged for review. Money rows show the old value, the new value, and the percentage move.
Approve
A person with the right role signs off. The approval is bound to a hash of that exact plan, not to the changeset in general.
Publish
Outfitter recompiles from live state and compares. If anything moved since the approval, the publish refuses. If nothing moved, it sends, item by item, and records the result of each one.
The preview is computed by the same code that publishes
Most bulk tools show you a summary screen assembled by different code than the code that sends the request. Outfitter compiles the plan with one pure function, no database, no clock, no network, and runs it again at publish time to check that the world has not moved.
Approval is bound to a hash
Compiling produces two fingerprints: one over the plan itself, including every exclusion, and one over the rules that produced it. An approval carries both. It approves that plan, not the changeset.
Drift refuses the publish
At publish time the plan is recomputed from current account state. Any difference stops the run. There is no confirm-anyway button, because the point of the check is that it cannot be clicked past.
The operation list is closed
27 operations exist in the current vocabulary. A field that is not on the list has no way to be expressed, so a malformed or creative instruction fails at the schema rather than at the ad account.
New things arrive paused
Created ads, keywords and creatives land paused. Turning them on at publish is a separate checkbox that has to be approved along with everything else.
The journal is written first
Outfitter commits a pending row before it makes the network call. An item with no row provably never reached the platform, which is what makes an interrupted publish safe to resume.
Invalid never publishes
Spec violations and cap breaches exclude at compile time with a machine-readable reason attached to the row. They are never downgraded to a warning you can scroll past.
Budget and bid changes get their own lock
Six of the 27 operations move money. Those carry rules the other twenty-one do not, because a fat finger on a budget field costs real spend before anyone notices.
- Owner approval, not admin. A batch containing any money operation needs the highest role in the workspace.
- Type the number. The approver types the aggregate delta by hand before the approval is accepted.
- Two people when two exist. Two distinct eligible approvers must sign the same plan. When the workspace genuinely has only one, one is enough, and the run records why.
- Caps in code. Per item, the default ceiling is a 20% move, and the hard ceiling is 50%. Per batch, the aggregate daily-budget delta is capped for the workspace.
- Stale data blocks, it does not warn. A money operation will not compile against inventory older than an hour.
- Recent changes get flagged. Touch a target that moved in the last 14 days and the dry run says so, because bid strategies need a learning window to settle.
The approval panel states the requirement, then shows whether it has been met. An unmet requirement leaves the publish button inert.
What Outfitter will not do
The short list of things this tool refuses is the reason it can be trusted with the rest. None of these are on a roadmap. They are design decisions.
- It does not build campaigns. Nothing above the ad level gets created. Campaigns, ad groups and ad sets have to already exist, which means Outfitter can only edit an account someone deliberately structured.
- It does not touch targeting. Geo, audiences, placements and schedules are out of reach entirely. There is no operation for them, so there is no accident available.
- It does not switch bid strategies. Target values move. Strategy types never change. A tool that can flip a campaign from one bidding model to another can erase months of learning in a click.
- It is not an autopilot. Nothing publishes on a schedule, on a trigger, or on a recommendation. Every publish traces back to a person who approved a specific plan.
- It cannot be driven by an API key. The public API is read-only. There is no programmatic path to publishing, on purpose, because an API key cannot be held accountable for a budget change.
- It does not edit conversion settings. Measurement configuration stays where it lives. Outfitter changes what runs, not how results are counted.
Where Outfitter can read, and where it can publish
Reading an account and writing to one are separate problems, and we ship them separately. This table is the current state, not the plan.
| Platform | Read and inventory | Publish changes | Notes |
|---|---|---|---|
| Google Ads | Live | Live | 20 operations in the vocabulary, 14 implemented, 10 verified end to end against a live account with a real budget change and a real revert. |
| Meta | Beta | In verification | 9 operations are built and registered. Every one of them is switched off until the write path clears an adversarial review. |
| Microsoft Ads | Beta | Planned | Structure reads are built. The write adapter is not. |
| OpenAI Ads (ChatGPT) | In development | Planned | Reads are gated off while the platform's structure endpoints settle. |
Beta means the code is written and the platform has not been exercised end to end against a live account yet. We would rather label it than let you find out.
Every change Outfitter can make, on one list
27 operations, versioned as a unit. Bumping the version invalidates approvals that were signed under the old one, which is the point: an approval means something specific or it means nothing.
Ads and creative
Build responsive search ads, update the ones that exist, upload images, and wire creative into Performance Max asset groups.
- rsa.create
- rsa.update
- image_asset.upload
- ad_creative.create
- ad.create
- ad.creative.set
- pmax.asset_group_text.link
- pmax.asset_group_text.unlink
- pmax.asset_group_image.link
- pmax.asset_group_image.unlink
Keywords and negatives
Add and remove keywords, manage campaign negatives, and attach or detach shared negative lists.
- keyword.add
- keyword.remove
- campaign_negative.add
- campaign_negative.remove
- shared_negative_set.attach
- shared_negative_set.detach
Statuses
Pause and enable at every level Outfitter can see. Status operations are their own inverse, so they roll back cleanly.
- campaign.status.set
- ad_group.status.set
- ad_set.status.set
- ad.status.set
- keyword.status.set
Budgets and bid targets
The six money operations. These are the ones that carry owner approval, a typed confirmation, and the percentage caps.
- campaign_budget.amount.set
- campaign.daily_budget.set
- ad_set.daily_budget.set
- ad_set.bid_amount.set
- keyword.cpc_bid.set
- bid_strategy.target.set
Operations are scoped per platform. Google supports 20 of them, Meta 9, and the dry run excludes anything the target platform cannot do rather than attempting it and failing halfway.
Undo is a new plan, through the same gate
There is no one-click revert, and that is deliberate. A fast undo path is a second way to write to a live account, and a second way to write is a second way to be wrong.
Reverting drafts a fresh changeset that inverts only the items that provably landed. It compiles, it gets approved, and it publishes, exactly like the batch it is undoing.
Some operations cannot be inverted. Creating a responsive search ad, a Meta creative or a Meta ad has no opposite operation in the vocabulary. The rollback preview lists those separately and tells you they need a person. We would rather say so on a marketing page than in a support ticket.
- Three failure states, named. Never sent, failed, and sent but unconfirmed are tracked apart, because only the third one needs a human to go look.
- 51 audited actions. Compiles, approvals, publishes, drift refusals, rollback drafts, connector mode changes and breaker trips are all typed events with a reader API behind them.
Every step of the gate writes an audited event. The log is readable in the product and exportable through the read-only API.
Analyze, attribute, act
Outfitter is the third piece. Each one stands alone, and each one answers a question the other two cannot.
TrailMap
Turns ad exports from six platforms into a ranked action plan. Answers what the platforms are claiming, and what to fix first.
findtrailmap.com →TrailHead
Traces every ad click through to real revenue on your own domain, then writes that revenue back to the platforms. Answers what actually happened.
discovertrailhead.com →Outfitter
Pushes the change, once a person has approved exactly what it will do. Answers the part where somebody has to go into the account and edit something.
You are hereThe three products run independently today. Handing a TrailMap finding straight to Outfitter as a prefilled changeset is on the roadmap, and is not built yet.
Roles that mean something, across every client
The approval model only works if the roles behind it are real, so the workspace layer was built before the write path was.
Multi-workspace
One agency account, a workspace per client, and a switcher between them. Cross workspace access does not return an error, it returns nothing at all.
Roles and approvals
Viewer, analyst, admin and owner. Money operations need an owner, and the approval requirement is re-checked as a live query at publish time rather than trusted from a stored flag.
Single sign-on
OIDC for teams that need identity handled centrally, alongside the audit trail that makes it worth doing.
Read-only public API
Pull inventory, changesets and audit records into your own reporting. API keys can read everything and publish nothing.
Asset library
Content-addressed uploads with immutable versions, so the creative that got approved is the creative that went out.
Spec validation
149 platform ad-spec rules, 107 enforced and 42 advisory, compiled from 203 measurements taken out of platform documentation with the source recorded next to each one.
Questions, answered straight
How is this different from the bulk editors the platforms ship?
Different job. Platform editors are built for an operator making changes quickly in an account they own. Outfitter is built for the case where the person making the change and the person accountable for the spend are not the same person, or are the same person on a bad day. The dry run, the role requirement, the typed confirmation and the audit trail exist to put a reviewable step between intent and spend. Outfitter reads and writes through the platforms' own APIs and is designed to sit alongside their tools, not replace them.
What happens if the account changed between the approval and the publish?
The publish refuses. Outfitter recompiles the plan from current account state and compares it to the plan that was approved. Any difference stops the run and tells you what moved. You re-run the dry run, look at the new plan, and approve that one instead.
Can I undo a publish?
Mostly. Reverting drafts a new changeset that inverts the items that landed, and it goes through compile, approval and publish like any other batch. Operations that create something new, a responsive search ad or a Meta creative, have no inverse operation, so the rollback preview lists them as items a person has to handle. Every mutating operation snapshots the prior state when it runs, which is what makes the inversion possible at all.
Do you need my ad account credentials?
Yes, and they are encrypted at rest with a key that lives outside the database. In the current release you paste credentials rather than running an OAuth flow, and a connection starts in sandbox mode pointed at test endpoints. Moving it to production is a deliberate, separately recorded action.
Why does publishing ship turned off?
Because the safe default for a tool that spends money is off. Four switches have to be on before anything reaches a platform: a global flag, a workspace toggle, a production authorization on the specific connection, and a per-platform allowlist. They are checked in that order and the first failure stops the whole publish.
When does Meta go live?
The adapter is written, registered and covered by tests, and all nine of its operations are switched off in code until the write path has been through the same adversarial review the Google path went through. Writing to accounts you do not own also needs Meta business verification, which is a separate process on their side. We would rather give you a date after the review than before it.
How big a batch can I push?
25 items by default, raisable by an owner, and 200 as a hard ceiling that cannot be configured away. Blast radius is a safety property, so it gets a limit rather than a setting.
What does early access mean in practice?
It means Google Ads publishing works and has been verified end to end, and the rest of the platform matrix is honest about where it stands. Pricing is not set. If you run enough Google spend that an unreviewed bulk change would ruin your week, you are who we want to talk to.
Ready to put a gate in front of your ad changes?
Early access is open for teams running Google Ads at a scale where a bad bulk edit matters. Tell us what you run and we will get you set up.