Our own system · Competitor intelligence
Every brand shows its live ads in public. Nobody has time to sit and watch them. We built the thing that watches for us, keeps every ad it has ever seen, and tells us what a competitor has committed to.
Our own system, running today
40+ brands watched
The screen the team opens
One brand, in four numbers
How much we hold, how long it has been running, and what the system makes of it.
Competitor Ads Spy · one brand selected, read from the live records
What it runs on
The system reports back
Every run writes to Slack. One message goes up when a run starts and the same message is rewritten when it lands, so a single line in the channel is the whole run, start to finish.
The second channel is the one we watch. It only posts when an ad appeared or an old one stopped. A quiet day there means nothing moved, which is a thing we used to have to go and check for ourselves.
The counts are the run. Fetched, inserted, updated, moved to inactive. If a brand has nothing live at all, the message says so rather than going silent and leaving us guessing.
Two channels, two jobs
The run log
One message per run. Posted the moment it starts, rewritten with the counts when it finishes.
Slack · the run log, one message per brand per run
Every advertiser's live ads are public. That sounds like an advantage until you try to use it. Someone opens the Ad Library, picks a brand, scrolls, screenshots a few ads and drops them in a folder.
Two weeks later that folder is a snapshot of a week nobody remembers. Which ads are still running? Which ones stopped? Which angle has been live for five months and which one lasted nine days? We could not say.
We wanted the opposite of a screenshot folder. Somewhere that keeps looking after we have stopped, and can tell us what moved while we were not.
One pass of the system
This is one run, start to finish. It takes about three minutes and nobody starts it.
One brand name and the link to its public Ad Library page. Nothing else to configure.
40+brands watched
What we point it at
There is no private feed here. Our system reads the same page any person can open, and it reads it for every brand on the list, every run, without anybody deciding to look.
Behind that page sits the scraper. It is handed the same instructions every run, so a pull today and a pull in March collect the same thing.
That is the whole of what we point at a competitor. A public page and a fixed set of instructions.
Every run sends the same three instructions. Active ads only, every country, ad details on.
Four questions we kept re-answering by hand. Each one shaped a piece of what you have just seen, and none of them was answerable from a folder of screenshots.
What is this brand running right now? A scroll through a public page, on the day you happen to look.
What did they stop running? Invisible. An ad that disappears leaves nothing behind.
Which angle is actually working? The only honest signal in public is how long an ad has been live, and nobody was counting.
What is being said in the videos? Most of the spend is video. None of it was readable, let alone searchable.
Six steps. A person does only the first, once per brand.
A brand name and its public Ad Library link go into the watch list. Nothing else is configured.
"Competitor Ads Analysis started", the brand it is targeting, and a link straight to that brand's Ad Library page. The run is visible before it has a result.
Apify returns every active ad the brand is showing in public, with the creative, the copy, the start date and the platforms.
The model turns one ad into an angle, an offer, a funnel stage, the triggers it leans on and an inferred persona.
Open a row and you get the ad as it ran, then what the model made of it. Every field on this screen was written by a run. None of it was typed by a person.
A video ad and a static ad, same row, different evidence
A video ad, with the words that were said
The copy as published, the model's read on it, then the spoken script. We pull a transcript on demand, one ad at a time, from the Get button on the row.
Competitor Ads Spy · one captured video ad, expanded
Primary text, headline, call to action and landing page, as published.
One angle, one offer summary, one insight line, and the triggers it leans on.
Pulled on demand, so a script can be searched instead of watched. 14 ads carry one.
The read
Reading one ad tells you what one ad says. The useful question is what a brand is doing across everything it has live, and which of those things it has committed to.
What is this brand betting on right now, and which of those bets has it proven?
This is the question our team asks before writing a campaign, and the one a client asks on a call. It used to mean opening the Ad Library, scrolling a brand's live ads and forming an impression from whatever was on screen that day. Now it is asked of any brand on the list, and asked of everything we hold on it.
How we wired it
Nothing here needs access to anybody's ad account. Every layer reads what is already published.
Every advertiser's live ads, on the page Meta publishes for them. One page per brand, and the link is the only thing we store about how to reach it.
Why any of this matters
It is the closest thing to a public admission that something works. 176 days is the longest run on file across every brand we watch, and the screen sorts on it.
What we learn
This is the part we use. The system groups every captured ad by what it said, then counts how many ads carry each one.
A hook behind sixteen ads is a decision. An offer behind one is a trial. The count is the signal, and we do not do the counting.
Our team reads this before writing anything. Not to copy a competitor, but to know what has already been proven in the market we are about to speak into.
Counts move with every run. These are what the system held on this brand.
Four views of the same brand read
The hook bank
Every opening line the brand has used, and how many ads sit behind each one.
Competitor Ads Spy · hook bank, 35 hooks on one brand
Five parts. Every one of them is something the team already pays for or already works in.
Where every ad on this page comes from
Here is the split. A system that watches other people's advertising is only worth trusting if it is straight about what it can see.
Five brands pulled every morning, one run a minute
Every new ad inserted, every returning ad updated
Ads that disappear recorded with an end date
The run log posting and then editing itself with the counts
A second channel woken only when something moved
Our system reads public pages. It has no access to anybody's ad account, and nothing in it could change an ad even if it wanted to.
Everything it holds is something the advertiser chose to publish. We keep our own copy so we can tell what changed, which is the only thing the public page will never tell you.
No spend, no return on spend, no results. None of that is public, and the model is told not to invent it.
Audience and persona are inferred from the ad itself, not read from the advertiser's targeting.
The read carries an unverified badge on the screen, because it is a reading of public ads rather than a measurement.
Every figure here was read from the running system on 17 September 2026, not from a report about it.
Read straight from the two tables the system writes to. 3,030 ads captured, 1,825 video, 2,202 with an end date, 828 still live. 2,360 carry a model written angle, 2,363 an inferred persona.
The 26 runs n8n still holds, across five days. 24 clean, 2 failed. A successful run takes 3m06s at the median, between 2m29s and 5m23s.
Quoted from the workflow that posts them. A run log that posts on start and rewrites itself with the counts, and a second channel that fires only when a row was inserted or end dated.
Nobody scrolls the Ad Library any more 40+ brands are on the list and they are pulled on a schedule without anybody deciding to look.
The history is the point 2,202 ads that are no longer running are still on file, with the date they stopped.
Silence means nothing changed A quiet alert channel means nothing moved, which used to be the one thing we could never be sure of. If a brand goes dark entirely, the run says so outright.
A hook with sixteen ads behind it is a fact The banks turn a pile of creative into counts, so we can see what a brand has stood behind more than once.
Short list, and we would rather it stayed short.
Choosing which brands go on the list
Asking for a transcript when an ad is worth reading in full
Reading the strategic summary and deciding whether we agree
Turning any of it into our own creative
The system is ours first. It is built to be handed over.
Brands that buy media and keep losing the thread on what competitors are doing
Agencies that do competitor research manually for every client, every month
Teams that already have a Slack channel where this belongs
Related resources
We build the systems that watch the brands you care about, collect what they are advertising, and turn it into something your team can act on. Built on your stack, owned by you, running in weeks.
Five brands are pulled every morning, one run a minute. Active ads, every country, ad details on.
5runs a day
Apifyn8nOne message per run in the log. A second channel hears about it only if something moved.
3m06smedian run
SlackNew ads inserted, returning ads updated, and anything that disappeared gets an end date.
3,030ads kept
SupabaseEvery ad gets an angle. Then the whole brand gets one strategic read, written back on its record.
2,360classified
OpenAINew ads are inserted. Ads we already had are updated. Ads that are no longer there get today's date as their end date.
That same message becomes "Analysis complete" with four counts: fetched, inserted, updated, moved to inactive. The alert channel only gets a message if one of those last two is not zero. And when a brand has nothing live, the run says "No active ads found" rather than returning an empty result.
No spend, no return, no results. The fields that are not public are not on the screen.
What this does not do yet
The capability list is the analysis contract the system runs. The limits are written into the same prompt.
The same request for every brand on the schedule, five a morning, one a minute. Active ads, every country, ad details on. Slack opens and closes the run.
One row per ad per brand. Inserted when it is new, updated when it comes back, end dated when it goes. The creative, the copy, the start date and the transcript all live on that row.
Each ad read once for angle and offer, then the whole set read again for what the brand is committed to. Both land back on the record, and both surface on the screen.
Every tier is running today. The system only reads. It never touches an ad account.
What reads the page and what drives it
Where every ad we have ever seen is kept
What turns ads into a position
Where a person meets it
Deciding which brand is worth watching
Asking for a transcript on an ad worth reading
Judging if a long runner is a winner or a habit
Anything that becomes our own creative
Alerting on the change rather than on the run
Transcribing the long runners without being asked
Watching the landing page behind the ad, not just the ad
The same watch on channels beyond Meta
We do not publish the watch list. The only brand named on this page is our own.
A position, not a pile The read names what a brand is betting on and cites the ad counts and days running behind it.
2026-08-28