AI Systems · AdFlow · Live, public demo

AdFlow runs client Meta accounts through the API, and keeps a person on every change

A campaign workspace built on the Meta Marketing API. An agent drafts the campaign, the ad sets, the creative and the copy, then reads the results back. Every change the agent proposes passes a guardrail, a named approver and a typed confirmation before it reaches the account, because the fastest way to lose an ad account is an automated change nobody reviewed.

8 workspacesmonitor, investigate, decide, test, control, measure
3 write switchesall three must allow a change before it runs
Why I built it

Running client ad accounts by hand is where the mistakes live

Managing Meta for other people means working across five surfaces at once. Ads Manager holds the account state, a reporting view holds the trend, a spreadsheet holds the comparison, a doc holds the reasoning, and a chat thread holds the approval. The reasoning behind a change lives in whichever one the person happened to open that day.

The cost of that is account risk. A budget doubled on the wrong campaign. A paused ad set nobody meant to touch. A creative pushed live without a check. Every one of those starts as an edit made faster than it was reviewed, and every one of them can get an account restricted.

So I built the layer Ads Manager leaves out: the trail from a campaign signal to a controlled action, with the account-changing step fenced off behind its own approval.

01 · Notice Spot the movement in Ads Manager

Delivery shifted, or cost per result climbed. The account tells you that much and stops there.

no comparison
02 · Compare Export to a spreadsheet

Ads Manager compares two windows awkwardly, so the real comparison gets rebuilt by hand every time.

rebuilt each week
03 · Agree Reason in a doc, approve in chat

The thinking lands in a note that forgets which campaigns produced it, and the yes arrives in a thread that is attached to a message rather than to the change.

both come unlinked
04 · Change Edit the account

Someone types a new budget. Six weeks later nobody can say what the number was before, who agreed to it, or what evidence it rested on.

untraceable
5 surfaces Ads Manager, a reporting view, a spreadsheet, a doc and a chat thread. The change is the only part that survives, and it survives without its reasoning.
The loop

Monitor, investigate, decide, test, control, measure

Six moves, and each one hands a named object to the next. A frozen snapshot becomes evidence, evidence becomes a finding, a finding becomes a reviewable recommendation, and only an approved plan reaches the account.

One campaign question, six objects each step hands the next one its context Scopecampaigns + dates Snapshotfrozen, reproducible Analysisfindings + evidence Experimentone variable, one metric Execution planapproved, then run Metathe account the green edge is where authority changes hands Everything left of it reads. Every agent-proposed change writes through the plan, and only after a person types the plan ID and then the word EXECUTE.
Analysis, recommendations and experiment design never touch the account. The transition into write authority is a separate object with its own approval, which is what makes an automated system safe to point at a client’s ad account.
What I tried first

The tools that exist solve a different half of the problem

Automation for Meta is a crowded category. Every option below is good at what it was built for, and none of them keeps the reasoning attached to the change.

OptionWhat it gaveWhere it brokeVerdict
Meta Automated Rules

Free, native, and genuinely useful for the mechanical cases: pause on a cost threshold, scale on a ROAS floor.

A rule fires on a condition and leaves no record of why the condition was the right one. There is no evidence behind it, no approval on it, and no way to ask later what the value was before.

Kept, narrowly
Revealbot, Smartly and the rule-engine tools

Far richer automation than the native rules, with cross-account management and scheduled actions on top.

They automate the action and assume the decision. The judgment about whether a change is worth making, and the test that would prove it, still happens in a spreadsheet next to the tool.

Rejected
A reporting layer plus a spreadsheet

Complete control over the comparison, and a place to keep the reasoning next to the numbers.

Nothing connects it to the account. The sheet cannot see that a budget changed yesterday, and the account cannot see that the sheet ever had an opinion.

Became the snapshot
Letting an AI agent hold the API token

The fastest path from a question to a change, and the demo everyone wants to see.

A fluent answer earns account authority it has not proved it deserves. One confident wrong write on a client account costs more than every hour the automation saved.

Rejected
The product

Eight workspaces, and each one answers a different question

meta.hi-daniel.com/app
AdFlow campaigns dashboard listing campaigns with status, budget, conversions and spend
AdFlow performance reporting with KPI cards and campaign scope controls
AdFlow Campaign Analyst screen stating every finding must identify a campaign and evidence
AdFlow recommendations queue with review states
AdFlow execution plans screen
AdFlow experiments screen with control and variant cells
AdFlow settings screen showing the safety switches
AdFlow create campaign wizard
The agent

It builds the campaign, and it hands you a draft rather than a live ad

The agent reads performance back through the Marketing API, writes the analysis against a frozen data snapshot, and proposes what to change next. It also drafts campaign structure, ad sets, creative and copy into the same wizard a person walks, so what reaches the account was assembled once and checked twice.

What it does not get is authority. The analysis layer is read-only by construction. A recommendation is a candidate with a status, and accepting one changes the status rather than the account. Turning a recommendation into a real change means designing an experiment, validating the live setup, and generating a plan that a person approves.

Deterministic code owns the numbers. Spend, results, CPA, contribution and outliers are calculated in application code, and the model explains that evidence rather than producing it. Where the inputs support it, a confidence interval decides the winner. A language model never does.

8 analysis recipes · 50 campaigns per run · findings must cite the campaign and the evidence
What the agent may do
Draft campaign, ad sets, creative, copyyes
Read performance and explain ityes
Propose a recommendationyes
Change a live campaignnever
Declare an experiment winnernever
The guardrails

Six checks stand between an agent and a client’s ad account

Every one of these exists because the alternative is an automated change that nobody reviewed, which is how ad accounts get restricted and how client trust gets spent.

01

A narrow write surface

The controlled route accepts explicit campaign status and daily-budget changes and rejects any shape it does not recognise. The API client can do far more than the product will let it.

02

Guardrails on the value

Protected campaigns cannot be paused. A budget change cannot exceed the configured maximum percentage. A plan that trips either one enters a blocked state instead of running.

03

Three switches, all of them

A global kill switch, an account-level switch, and an agent-execute switch that is off by default. Every one has to allow the change. Agent execution stays opt-in even when writes are generally enabled.

04

Typed approval, twice

An approver types the exact plan ID to approve it. The operator then types EXECUTE <plan-id> to run it. An approved plan without that exact confirmation does not execute.

05

The live value wins

Immediately before writing, AdFlow re-reads the account. If the current status or budget no longer matches what the diff was written against, the plan blocks and has to be regenerated. Stale input is dangerous when the next step mutates an account.

06

Failure stays inspectable

Each object keeps its own result, so a run is completed, partial or failed rather than flattened into one word. Retry covers only what failed, rollback only what succeeded, and both are new plans with their own approval.

One change, end to end

What happens when the account moved while you were deciding

This is the case the whole structure exists for, and it is the one a rule engine cannot see.

Monday. Spend on the retargeting campaign is running ahead of plan and cost per result is holding. The analyst freezes the scope, the analysis names the campaign and cites the evidence, and the finding becomes a recommendation: raise the daily budget from $50 to $65.

The recommendation goes into an experiment so the change is measurable rather than hopeful. Control and variant are named, the isolation variable is the budget and nothing else, and the stopping rule is set before anything launches. The approver reads the diff and types the plan ID.

Tuesday morning, the operator types EXECUTE. AdFlow calls Meta before writing anything and finds the campaign sitting at $60, not $50. Somebody edited it in Ads Manager overnight.

The plan blocks. It does not write $65 over a number it was never reviewed against, and it does not quietly re-baseline and continue. It reports the drift and asks for a fresh diff, so the approval that gets executed is an approval of the change that is actually about to happen.

The guardrail that matters is the one between the approval and the write
Latest-value check
Plan says before$50.00
Plan says after$65.00
Meta says now$60.00
Resultblocked
Built for an agency

Every account I run makes the next one safer

This started as the tool I wanted for my own client work, and it is designed to hold more than one account. Today it runs one client while the write paths and the tenant keys harden. The structure I am building toward is one workspace per account, one set of guardrails, and an audit trail that survives the person who made the change.

The compounding is in the rules. Every campaign I run teaches something about what breaks a Meta account. The budget jump that trips a review. The creative that should never have gone live. The bulk edit that hits the wrong ad set. Each of those becomes a guardrail or an agent skill rather than a lesson I have to remember.

That is the difference between an agency that scales and one that just takes on more accounts. The knowledge stops living in whoever happened to be on the account, and starts living in the system that runs it.

5 roles · shared guardrails · an append-only audit the database refuses to edit
What compounds across clients
Guardrail thresholdsshared
Agent skills and recipesshared
Experiment templatesnext
Campaign data and auditper account
Approvers and rolesper account
Testing

A test has cells, one variable and a stopping rule, or it is just a change

meta.hi-daniel.com/marketing
AdFlow marketing page showing the four product objects and their authority
AdFlow experiments marketing page
AdFlow intelligence marketing page
AdFlow platform marketing page
Under it

What it runs on

Application

Next.js logoNext.js 16App Router, route handlers, and the proxy boundary, running as one process. React logoReact 19Client and server components across the eight workspaces. TypeScript logoTypeScript 5Data contracts, route handlers, and the shape of every workflow object. Vercel logoVercelHosting for the public read-only demo.

Data

SQLite, WAL modeSettings, frozen snapshots, workflow objects, execution attempts and the append-only audit table. Meta logoMeta Graph APICampaigns, insights, breakdowns, targeting, audiences and creatives, plus the supported writes.

Models

OpenAI logoOpenAIOptional narrative layer, low temperature, explaining evidence the code already calculated. Gemini logoGeminiThe alternate provider. If either call fails, the deterministic analysis still stands. No UI frameworkCSS modules, no Redux, no component library. Fewer dependencies, more control over the dense operator screens.

Two data policies run side by side, because they answer different questions. Analysis reads from frozen snapshots so a finding can be reproduced weeks later, with a cache key hashed from the account, the resource and a normalised scope. Execution reads live, every time, immediately before the write. Snapshots for reproducibility, live reads for correctness.

Where it stands

What is running, and what I am not claiming

A working product with a public demo, built to a standard I would put a client account behind. The parts that are not there yet are named rather than implied.

Running

Eight workspaces and the full object chain from scope to controlled execution. The guardrail and approval path, per-object results with retry and rollback, and an audit table the database itself refuses to update or delete.

Next

Multi-account workspaces, so one operator runs several clients side by side. Secrets move to a managed store, roles get uniform enforcement on every route, and the remaining manual write paths move behind the same plan safety model.

Not claimed

No client performance numbers. The product is a prototype running one account, and the guardrails are designed against the failure modes I have seen rather than validated against a published incident rate.

The system, in numbers
Workspaces8
Analysis recipes8
Campaigns per analysis run50 max
Roles5
Write switches, all required3
Data states, never collapsed8

Want this pointed at your ad account?

The demo is public and read-only. Open it, walk the loop from a campaign signal to an approved change, and see where the authority lines sit.