← All sessionsHomeSearch
AI Catalyst C3·Core Session - Week 9·3:00:10

Session 17: Facebook Ads Competitor Research & Replication

Harshit Trainer — returning mentor; n8n 'back to the roots' session, first session from the Outskill office with a new microphone; builds live as a self-described non-coder, delegating all code to ChatGPT in a split screen · Niharika Cohort manager (closing poll)

Session map

STRATEGYBUILD THE SPINESCRAPE & GENERATEWinning adslongevity · spend · CTAIntelligence, not copyingpattern in, your brand outA/B variantsreferences in, experiments outWorkflow as productform beats one-off CLIForm triggerinterface + validation gateAI builds AIJSON as context, code backPublic image URLthe Drive viewer trapBase64 bridgebinary → JSON-safe textApify scraperrented, maintained, JSON outLoop + filterone at a time, junk outAnalyze → generatevision + strict promptHuman review gateDrive, not the ad account
StrategyBuild the spineScrape & generate
click a node — its card pops up (drag it anywhere, × to close)
Concept

The map reads left to right — strategy flow into build the spine, then into scrape & generate. Click any node to open that idea here; every timestamp jumps into the recording.

The short version

  1. The session's product: a Meta ads intelligence workflow in n8n — form in (your product, competitor's Facebook URL, ad count), finished branded ad images out, dropped into Google Drive for human review.
  2. Why it works: Meta is legally required to publish every running ad in its Ad Library, and the longest-running ads are the proven winners — 'if they've been running the ad for 6 months, that means something is working.'
  3. The ethic and the economics: scrape for inspiration, never duplication — you inherit the competitor's proven structure but ship your own story, brand and copy, because 'you don't want to become another Nike.'
  4. The method is the bigger lesson: a non-coder builds a nine-node pipeline by copying the workflow JSON into ChatGPT and asking for each node's code — 'get into that habit of using AI to build AI. You don't have to know everything. All you have to know is the approach.'
  5. Real failures, debugged live: Google Drive share links serve an HTML viewer instead of the image, and the image generator inherited Spanish from Nespresso's regional ads until a stricter system prompt forced English-only output.

The concepts

01

Winning ads: longevity, spend, and the public Ad Library

0:20:23

Every ad your competitor is running right now is public by law — and the ones that have run longest are the ones printing money.

Meta is legally required to publish every active ad in its Ad Library. That turns your competitors' most expensive lesson — which creatives actually convert — into a free, public dataset. Agencies, rivals and new entrants all mine it; the session's whole workflow is built on this one fact.

The reading skill is knowing which ads are winners. Three signals: how long the ad has run (six months of continuous spend means it converts — nobody pours budget into a loser), how hard the advertiser is doubling down on it, and the strength of its call to action. Duration is the sharpest of the three, and the scraper returns start and end dates precisely so you can filter on it.

Worked example · from the session

Nespresso's Ad Library entries, pulled live via Apify: each ad arrives with published/start/end dates, images, copy and CTA — the trainer filters for the long-runners as the ones worth learning from.

Why it matters

This replaces guess-and-burn ad spend with evidence. Instead of A/B testing from a blank page, you start from creatives a competitor already paid to validate.

People get this wrong

Ad performance data is a competitor's private secret.

The creatives and their run dates are public by law in the Ad Library. What stays private is the spend and conversion numbers — but run duration is a reliable proxy.

Meta Ad Library every running ad, public by law read the winners, not the docs Longevity 6 months running = converting Sustained spend doubling down = it works CTA + engagement impressions, stickiness the sharpest signal Nobody funds a losing ad for six months — run duration is revealed preference. Garbage in, garbage out: the signals only help if you picked the right competitors first.
Three signals that an ad is a proven winner — and where the data legally lives
The longest running ad is the most successful one. Right? If they've been running the ad for 6 months, that means something is working.2:12:23
For your projects

law-o-matic sits in a paid-acquisition market (legal services is one of the priciest ad verticals). Before any spend there, this exact pipeline against the incumbent legal-tech advertisers is the cheap first move.

  • Run the Ad Library check on legal-services advertisers as a pre-spend audit for law-o-matic — the KB's first real use of this session.
Go deeper

In one line: Meta publishes all running ads in its Ad Library by legal requirement. Winning ads are identified by run duration (longest-running = proven), sustained spend, and CTA strength; the Apify scraper returns the date fields needed to filter for them.

Meta legally required to publish all ads — Ad Library is public access (0:22:24)

'The longest running ad is the most successful one… running for 6 months means something is working' (2:12:23)

Winning-ad signals: CTA strength and ad-spend doubling-down (0:30:30); impressions and engagement are the measurable tells (0:40:38)

'Garbage in, garbage out' — the workflow's output is only as good as the competitor set you point it at (0:38:36)

Try it now

Open facebook.com/ads/library, search a brand you compete with, and sort mentally by run time. The ads that have survived months are the ones to study.

▶ Watch this taught: 0:20:23

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why is competitor ad data available at all?

Meta is legally required to publish every running ad in its public Ad Library — transparency regulation turned competitors' creative testing into a free dataset.

Of the three winning-ad signals, which is sharpest and why?

Run duration. Nobody funds a losing ad for six months — sustained runtime is revealed preference, harder to fake than a strong CTA.

You point the workflow at the wrong competitors. What happens?

Garbage in, garbage out — the whole pipeline faithfully replicates creatives that were never winners for your market. Competitor selection is the foundation step.

02

Intelligence, not duplication

0:26:26

Copying a winning ad is plagiarism and slow brand suicide; extracting why it wins and shipping your own version is just competitive research.

Deborah asked the uncomfortable question directly: isn't this plagiarism? The trainer's line is clean. Duplication — same image, same copy, your logo — is plagiarism, and it also quietly destroys you: 'you don't want to become another Nike.' A me-too brand caps its own ceiling.

Intelligence is different: you take the competitor's proven structure — the messaging angle, the visual approach, the offer framing — and regenerate it with your product, your story, your positioning. That's why the workflow's generation prompt feeds the competitor's headline and body text in as *example context* while hard-constraining the output to 'only my product, only my brand.' The winner's skeleton, your flesh."

Worked example · from the session

The live build: Nespresso's ad supplies the reference structure, but the generation prompt is locked to Kenco's name, brief and product image — the output is a Kenco ad that has learned from Nespresso, not a Nespresso clone.

Why it matters

This is the difference between a sustainable system and a takedown request. It's also what makes the workflow sellable — 'intelligence system' is a product; 'ad copier' is a liability.

People get this wrong

If the ad data is public, reusing the creative is fair game.

Public visibility makes the *pattern* free to learn from. The creative itself is still theirs — and copying it caps your brand at 'discount imitation.'

Competitor's winning ad proven by real spend Duplication same image, same copy, your logo Me-too brand plagiarism + long-term dilution Intelligence extract angle, layout, offer framing Your branded ad your product, story, positioning the winner’s skeleton, your flesh “you don’t want to become another Nike”
Duplication copies the ad; intelligence extracts the pattern and ships your brand
You don't want to become another Nike. You don't want to become another Adidas.0:22:24
Go deeper

In one line: The workflow is an intelligence system, not a duplicator: competitor ads are ingested as structural inspiration (angle, layout, offer) while generation is constrained to your own brand, product and language. Outright copying dilutes the brand long-term.

▶ Watch this taught: 0:26:26

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Where exactly is the line between inspiration and plagiarism in this workflow?

The competitor's ad enters the prompt only as example context; the output is constrained to your product, brand and copy. Reusing their actual image or text crosses the line.

Why is duplication a bad strategy even if nobody sues?

It makes you a me-too brand — 'you don't want to become another Nike.' Long-term brand equity dies even when the short-term ad converts.

03

Reference images and A/B variants: why the pipeline makes several ads

0:38:36

You never ship one ad — you generate variants from reference images and let the market tell you which copy converts.

Two inputs precede any generation. First, reference images of your own product — five to ten, generated in ChatGPT or Gemini (Nano Banana) if you don't have real shots — because without a reference the AI has nothing of yours to build on. Second, the competitor's winning ads as structural inspiration.

From those, the pipeline produces multiple variants — Kenco ad 1, 2, 3 — usually the same image with small copy variations: 'grab your summer deal', 'buy 1 get 1', 'hurry up', 'limited slots'. That's A/B testing: you can't predict whether the urgency line or the offer line converts, because it depends on the audience, the brand language, and the ads' stickiness — whether they actually convert. One variant may win engagement while another wins conversions. The trainer's aside: Meta's delivery system itself is remarkably good at finding which works — 'our job is only to create the workflow, create these images, and push it to Meta. Meta does the rest.'

Worked example · from the session

The whiteboard walk-through: Kenco's reference image spawns three ads differing only in copy — a summer-deal line, a buy-one-get-one line, and a hurry-up line — each a live hypothesis about the audience's psychology.

Why it matters

This is why the workflow has a loop and an ad-count field at all: variant generation is the point. One perfect ad is a guess; three variants is an experiment.

People get this wrong

A good marketer can pick the winning copy upfront.

Even the trainer defers to the market: copy performance depends on audience, brand language and stickiness. You generate variants and measure — 'it totally depends on which one is actually working.'

Go deeper

In one line: Inputs: 5–10 reference images of your own product (generated via ChatGPT/Gemini if needed) plus competitor winning ads. Output: multiple ad variants with small copy variations for A/B testing; which converts depends on audience, brand language and stickiness, and engagement winners aren't always conversion winners.

▶ Watch this taught: 0:38:36

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why does the form ask how many ads to process instead of just taking one?

Variant generation is the point — each competitor ad seeds a variant, and A/B testing across variants is how you learn which copy converts rather than guessing.

Two variants: one gets far more engagement, the other more purchases. Which is the winning ad?

Depends on your goal — they measure different things. Conversion is usually the money metric; the session's point is precisely that you can't know beforehand, which is why you test.

04

Why a workflow instead of a one-off script

0:50:47

A CLI run solves today's problem; a form-fronted workflow is a product you can hand to a client — or sell.

Deborah asked why bother with a workflow when a Claude Code CLI session could scrape and generate in one shot. The answer is about what survives the run. A CLI transcript is a one-off: it worked, it's gone, and only you could drive it. An n8n workflow with a form on the front is infrastructure — anyone can submit the form, it runs identically every time, and it can be wrapped, branded and priced.

This is the session's business frame: the workflow *is* the product. Agencies, growth marketers and GTM teams all need exactly this; you can run it as a service, sell access to it, or drop a Lovable UI on top and productize it fully. The trainer built it on a 14-day n8n trial precisely to show there's no infrastructure moat."

Worked example · from the session

The finished pipeline: a marketer who has never seen n8n opens the form, picks 'Kenco Coffee', pastes Nespresso's Facebook URL, asks for 2 ads — and gets reviewed-ready branded creatives in a Drive folder.

Why it matters

This is the recurring Catalyst decision: one-off leverage (CLI) versus repeatable asset (workflow). Knowing which to reach for is what separates using AI from building with it.

People get this wrong

Workflows are the amateur option; real builders write code.

The asset class differs, not the sophistication. A workflow is packaged, repeatable capability — that's what clients buy. Code you ran once is capability that evaporated.

If you understand where to pick these Lego blocks and put them together, you can build out your product directly. That's the approach.2:24:38
For your projects

The KB pipeline has the same split live: build_site.py is workflow-class (repeatable, anyone can run it), while each extraction sitting is CLI-class. The rule 'if it will run twice, give it a form' applies directly to the coming validate.py and any harvest tooling.

  • Wrap this session's exact pipeline behind a one-page form as a sellable 'ad intelligence report' — the trainer explicitly framed agencies and GTM teams as buyers.
Go deeper

In one line: CLI/agent runs are one-off executions; an n8n workflow with a form trigger is a reusable, sellable product — same capability, different asset class. Product surfaces: run-as-service, sell to agencies, or wrap in a Lovable UI.

▶ Watch this taught: 0:50:47

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Same capability is available in a CLI session — what does the workflow buy you?

Repeatability, a human-friendly interface, and an asset: it runs identically for anyone, which makes it a service or product rather than a personal trick.

When would the CLI actually be the right call?

A genuine one-off — an experiment or a personal research run where nobody else will ever need to trigger it and the result matters more than the machinery.

05

The n8n form trigger as product interface

0:48:46

One node gives the workflow both its start button and its user interface — and forces clean inputs before anything expensive runs.

The 'On form submission' node generates a hosted form and fires the workflow when it's submitted. Three fields here: a product dropdown (Kenco Coffee, HV Sneakers, HV Skincare — the trainer's point is any product type works), a text field for the competitor's Facebook URL with a placeholder showing the expected shape, and a number field for how many ads to process, capped at ten.

Every field is marked required, and that's doctrine rather than fussiness: the workflow spends real money downstream (scraper credits, image-generation tokens), so malformed or missing input has to die at the door. The form is simultaneously the product's UI — this is what a client would see — and its validation gate."

Worked example · from the session

Test submission, live: Kenco Coffee + Nespresso's Facebook URL + 2 ads. The three values flow into the mapping node and drive the entire three-hour build.

Why it matters

Interface and trigger in one free node is the fastest possible path from 'workflow' to 'thing a non-technical person can use' — the precondition for everything in workflow-as-product.

People get this wrong

Forms are for collecting data; workflows need programmatic triggers.

The form IS the product boundary — it's how capability gets handed to someone who will never open n8n.

Go deeper

In one line: n8n's form-submission node hosts a form and triggers the run: product dropdown, competitor Facebook URL (placeholder 'https://facebook.com/nike'), ad count (1–10, max 10), all fields required so no expensive downstream step runs on bad input.

▶ Watch this taught: 0:48:46

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why are all three form fields required rather than optional-with-defaults?

Downstream nodes spend money — scraper credits and image tokens. Required fields make bad input fail free at the form instead of expensive in the pipeline.

What two jobs is the form node doing at once?

Trigger (starts the run on submit) and interface (the hosted form is what a client or teammate actually uses) — which is what makes the workflow a product.

06

Use AI to build AI: ChatGPT writes every code node

1:09:06

The trainer doesn't write JavaScript — he pastes the whole workflow into ChatGPT and asks for the next node.

The working setup is a split screen: ChatGPT left, n8n right. The key move is context first — copy the entire workflow JSON out of n8n and paste it into the chat, so the model sees every node, field name and connection before being asked for anything. Then each request is small and specific: 'write the JavaScript for a code node that outputs product_name, product_image_URL, product_brief, competitor_URL, number_of_ads.'

Two disciplines make this reliable. Naming: ask for a standard output shape (snake_case keys) so every downstream node reads predictably. And economics: a code node runs free forever, while an OpenAI node burns tokens on every execution — so anything deterministic (mapping, filtering, parsing) gets generated once as code, and paid AI nodes are reserved for genuine judgment like image analysis and generation. When a node fails, the same loop debugs it: paste the error, get the fix. 'Best superpower is an LLM.'"

Worked example · from the session

The mapping node, end to end: workflow JSON pasted for context → prompt for the five output fields → ChatGPT returns code with an Unsplash placeholder image → pasted into the code node → test run outputs Kenco / image URL / brief / Nespresso URL / 2. Later the same loop diagnosed the Google Drive link failure and generated the Apify curl command.

Why it matters

This is the session's transferable method. n8n specifics will churn; 'context first, small asks, code for the deterministic parts, paid AI only for judgment' works in every builder tool you'll ever touch.

People get this wrong

You need to learn JavaScript before building serious n8n workflows.

You need to learn the approach — context, contracts, and where to place the Lego blocks. 'You don't have to know everything. All you have to know is the approach.'

ChatGPT (left screen) n8n (right screen) 1. Copy workflow JSON the whole pipeline as context 2. Small, specific ask code for ONE node, snake_case out 3. Code comes back placeholders included 4. Paste + test the node execute step, read output 5. Error? paste it back into the same chat same loop debugs it Deterministic steps → free code nodes, once. Paid AI nodes → judgment only.
The split-screen loop — workflow JSON out, node code back, paste, run, repeat
Get into that habit of using AI to build AI. You don't have to know everything. All you have to know is the approach.2:24:38
For your projects

This is literally the KB pipeline's own method — build_site.py grew the same way. The economics rule maps onto the two-pass extraction question directly: deterministic structure extraction should be cheap/scripted; paid judgment reserved for the editorial layer.

  • A 'workflow context pack' skill: one command that copies any n8n workflow's JSON plus its recent error output to the clipboard, pre-framed for the debugging loop.
Go deeper

In one line: The build method: split-screen ChatGPT + n8n; paste the full workflow JSON as context, request each node's code with an explicit snake_case output contract, paste back and test. Deterministic steps become free code nodes; token-burning AI nodes are reserved for judgment. Errors are debugged by pasting them into the same chat.

Context move: copy the entire workflow JSON into ChatGPT before asking for anything (1:11:07)

Output contract requested explicitly: product_name, product_image_URL, product_brief, competitor_URL, number_of_ads — snake_case for readability in n8n (1:15:11)

Economics rule: code nodes execute free; OpenAI nodes charge per run — 'instead of always burning AI tokens' (1:23:20)

Debugging is the same loop: paste the failing output, get the diagnosis — used live on the Google Drive HTML-viewer bug (1:43:36) and the Apify curl command (2:22:37)

n8n's own Ask-AI assistant used once for an HTTP body fix (2:28:44); it also auto-flagged a hardcoded API token and converted it to a credential (2:30:47)

Try it now

Open any existing n8n workflow, copy its JSON into ChatGPT, and ask for one new node. The quality jump from having full context is immediately visible.

▶ Watch this taught: 1:09:06

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

What does the trainer paste into ChatGPT before asking for any code, and why?

The entire workflow JSON. With every node, field name and connection in context, the generated code fits the pipeline instead of being generic.

State the code-node-vs-AI-node economics rule.

Code nodes run free forever; AI nodes burn tokens every execution. Generate code once for anything deterministic; pay per-run only for judgment (vision, generation).

A node throws an error you don't understand. What's the move?

Paste the error and the node's output into the same ChatGPT conversation — it already has the workflow context to diagnose it. That's how the Drive link bug was fixed live.

07

Getting your product image behind a public URL (the Drive trap)

1:25:23

The pipeline needs your product shot as a plain downloadable URL — and the obvious way to host it, a Google Drive share link, silently serves a webpage instead of the image.

Downstream nodes need your product image as binary data, fetched by an HTTP GET from a public URL. Any host works: your own site, a CDN, Unsplash for placeholders, free hosts like ImgBB, or Google Drive. The trainer generated a Kenco shot with Gemini, uploaded it to Drive, shared it, pasted the link — and the node returned an HTML doctype instead of an image.

The trap: Drive's share link points to Google's HTML *viewer page*, not the file. Browsers render that fine, so humans never notice; an HTTP node just sees a webpage where an image should be. The fix (via the ChatGPT debugging loop) is converting to Drive's direct-download URL form. The general lesson outlives Drive: 'public link' and 'direct file URL' are different things, and automation needs the second."

Worked example · from the session

First run: Drive share link → HTML doctype error. ChatGPT: 'Google's view link points to an HTML viewer, not the page.' Corrected direct URL → second run, the Kenco image lands in n8n as binary.

Why it matters

This exact failure — viewer URL where a file URL is needed — recurs across Drive, Dropbox, SharePoint and Notion. Recognizing 'I got HTML instead of my file' saves an hour every time.

People get this wrong

If the link opens the image in my browser, an automation can download it.

The browser is rendering a webpage around the image. Automation needs the direct file URL — a different link that most sharing UIs hide.

Best superpower is an LLM. It's a personal agent.1:45:46
Go deeper

In one line: Product images must be reachable as direct public file URLs for HTTP download into n8n. Google Drive share links serve an HTML viewer by default and must be converted to direct-download form; alternatives are your own site, image hosts (ImgBB), or stock URLs for testing.

Try it now

Take any Drive share link and fetch it with curl. Seeing the HTML come back once makes the failure unforgettable.

▶ Watch this taught: 1:25:23

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

The HTTP node returns something starting with '<!DOCTYPE html' instead of your image. What happened?

The URL points at a viewer page (Drive's default share link), not the file. Convert it to the direct-download URL form.

Why do humans never hit this bug in normal use?

Browsers happily render the viewer page, so the share link 'works' for people. Only a machine fetching bytes exposes the difference.

08

Base64: turning an image into API-friendly text

2:04:15

APIs eat JSON, and JSON can't hold a binary image — base64 is the standard trick that turns the image into a long text string.

Once the product image is downloaded as binary, the AI nodes ahead want it in a form they can accept inside a JSON payload. Base64 encoding rewrites the binary as plain text — a very long string of letters and digits — which travels inside JSON like any other field.

In n8n this needs no code at all: 'Extract from File' plus 'Move to Base64 String' are prebuilt nodes, chained after the download. The trainer also framed a cost angle: with the image held once as a compact string and referenced by later steps, you avoid repeatedly shipping raw binary through multiple AI nodes as the workflow fans out into ad variants."

Worked example · from the session

Live: download node → Extract from File → Move to Base64 String → output is one long readable string, ready for the analyze and generate nodes.

Why it matters

Base64 shows up everywhere in AI plumbing — vision API payloads, inline images in HTML email, data URLs. Knowing 'binary → text for JSON transport' demystifies all of them.

People get this wrong

Base64 compresses the image.

It's an encoding, not compression — the text form is actually ~33% larger than the binary. Its virtue is transportability, not size.

Go deeper

In one line: Base64 encodes binary image data as a text string so it can ride inside JSON API payloads; n8n's Extract-from-File + Move-to-Base64-String nodes do the conversion without custom code, after the image exists as binary.

▶ Watch this taught: 2:04:15

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why can't the raw downloaded image go straight into an API call's JSON body?

JSON is a text format — it can't carry raw binary. Base64 rewrites the bytes as a text string that JSON transports happily.

What has to exist before the base64 node can run?

The binary image, already downloaded into the workflow — you encode bytes you have, not a URL.

09

Apify's Facebook Ads Scraper as the data source

2:08:20

You don't scrape Facebook yourself — you rent a maintained scraper from Apify's marketplace and call it like an API.

Apify is a marketplace of hosted scrapers ('actors'). Search 'Facebook ads scraper', take the official one — built by Apify itself, ~29,000 users, generous free plan — give it a brand's Facebook URL, and it finds the Ad Library entries on its own and returns structured JSON: page info, and per-ad images, copy text, CTA, placement network, and the crucial published/start/end dates.

Integration into n8n is the ChatGPT loop again: paste a sample of the scraper's JSON into the chat, ask for a curl command that calls the actor via Apify's API, and import that curl straight into an n8n HTTP node — n8n converts a pasted curl into a configured node. Add your Apify API credential (n8n flagged the hardcoded token and moved it into a proper credential automatically), and the workflow now pulls fresh competitor ads on every run."

Worked example · from the session

Live run against Nespresso: actor executes in about a minute; JSON lands with profile image, ad links and per-ad fields — including several image-only regional ads in Spanish that later trip up the generation step.

Why it matters

The rent-don't-build rule for scrapers: Facebook's markup churns constantly, and a maintained actor with thousands of users absorbs that churn so your workflow doesn't.

People get this wrong

Scraping Facebook's Ad Library requires fighting anti-bot defenses yourself.

That fight is exactly what you're renting from Apify — the actor's maintainers own the cat-and-mouse; you consume clean JSON.

Go deeper

In one line: Apify hosts maintained scrapers callable by API. The official Facebook Ads Scraper (~29k users, free plan adequate for small runs) takes a brand's Facebook URL, locates its Ad Library entries, and returns per-ad JSON including images, copy, CTA, network and run dates; n8n integration via a ChatGPT-generated curl imported into an HTTP node.

Official Apify-built actor chosen over third-party clones; ~29,000 users at recording (2:10:21)

Input is just the brand's Facebook URL — the actor finds the Ad Library itself (2:12:23)

curl command generated by ChatGPT from the scraper docs, imported directly into the HTTP node (2:22:37–2:24:38)

n8n auto-flagged the hardcoded API token and converted it into a stored credential (2:30:47)

Anomaly kept honest: a test against Shein returned Nike ads — unexplained, suspected cookie/cache or sample data (2:14:26)

Try it now

Make a free Apify account, run the Facebook Ads Scraper on one competitor from its web UI, and export the JSON — reading real output is the fastest way to understand the data shape.

▶ Watch this taught: 2:08:20

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why rent an Apify actor instead of writing your own Facebook scraper?

Facebook's structure churns constantly. A maintained actor with ~29k users absorbs the breakage; your own script makes every change your problem — the same vendor-maintenance argument as MCP over DIY API tools.

How did the scraper get into n8n without reading API docs?

ChatGPT generated a curl command for the actor's API; n8n imports a pasted curl directly into an HTTP-request node. Credentials then move into n8n's credential store.

What do you do when a scraper returns inexplicable data, as the Shein→Nike run did?

Treat it as untrusted: re-run fresh (cookies/cache cleared), verify against the source UI, and don't build downstream logic on an output you can't explain.

10

Loop, then filter: processing ads one at a time, keeping only usable ones

2:32:48

The scraper returns a messy pile of ads; two cheap nodes turn it into a clean one-at-a-time stream of only the ads worth processing.

First, Loop Over Items with batch size 1: instead of the whole ad array flooding downstream nodes at once, each ad flows through the expensive analyze-and-generate steps individually — sequential, debuggable, and each iteration independently visible.

Second, filtering — because Apify's JSON is heterogeneous. Different ads store their images in different fields (cards, image, previews), some are video-only, some are logo-only with no copy. A ChatGPT-generated code node normalizes each ad and marks whether it has an image, body text, headline, CTA and page name; a Filter node then passes only has_usable_image = true. Everything downstream sees clean, uniform objects — which both saves tokens and removes the junk inputs that make generation models hallucinate."

Worked example · from the session

Live: loop node added after the scraper, batch size 1; filter code (a pre-generated snippet, in the interest of time) marks usable ads; Filter node drops the video-only and logo-only entries; only real image ads reach the paid generation node.

Why it matters

Loop-then-filter is the universal shape for 'API returned a messy list, and each item costs money to process.' You'll rebuild this pair in every scraping workflow you ever make.

People get this wrong

More data into the AI step means better results.

Unusable items in the stream are pure cost and hallucination risk. The pipeline gets better by what you remove before the paid nodes.

Go deeper

In one line: Loop Over Items (batch size 1) serializes the ad array for per-item processing; a code node normalizes heterogeneous ad JSON (images may live under cards/image/previews) and flags usable ads (image + body text + headline + CTA + page name); a Filter node passes only has_usable_image = true, skipping videos and mockups.

▶ Watch this taught: 2:32:48

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why batch size 1 in the loop?

Each ad then moves through the paid analyze/generate steps individually — sequential, debuggable, and a single bad ad can't poison the whole run.

Why filter before the AI nodes rather than letting the model cope?

Tokens and hallucination. Junk inputs (video-only, logo-only ads) burn money and push the generator toward garbage output. Filter early, spend late.

Why is a code node needed at all — why not filter directly?

Apify's output is heterogeneous: images hide in different fields per ad type. The code node normalizes shape first so a simple boolean filter can work.

11

Vision analysis + constrained generation (and the Spanish surprise)

2:43:00

The competitor's image goes in as understanding, not pixels — a vision node describes it, and a hard-constrained prompt regenerates the idea for your brand.

Two paid AI nodes close the pipeline, both running on n8n's built-in OpenAI credits (about $2 of free usage — no API key needed to follow along). First, an Analyze Image node (model as heard: 'GPT 5.5') reads the competitor's downloaded ad image — as binary, from the earlier download — and produces a text understanding of its visual approach. That understanding, not the pixels, feeds generation: the plagiarism boundary made mechanical.

Second, a Generate Image node on GPT Image 2 ('gives much better results', per the trainer) runs a system prompt that ChatGPT itself drafted: 'You are a senior performance ad creative director…' with template slots for product name, brief and reference image, plus the competitor's headline and body as example context. The first run produced a fluent ad — in Spanish, because Nespresso's scraped regional ads were Spanish and the model inherited the language of its inputs. The fix was a stricter prompt version with hard rules: only my product, only my brand, only English text; no competitors, no foreign language, no watermarks, no mockups. Second run: clean English ad — 'Rich coffee, real moments… shop now.'"

Worked example · from the session

Full chain live: Nespresso ad image → vision description → creative-director prompt with Kenco's details → first output Spanish (input contamination) → stricter prompt → final English Kenco ad uploaded to Drive.

Why it matters

The Spanish failure is the teachable moment: generation models inherit properties of their inputs unless you explicitly constrain the output. 'What must NOT appear' belongs in every production generation prompt.

People get this wrong

A good creative prompt is about describing what you want.

Production prompts are half exclusions. The v1→v2 fix added no new wants — only nos — and that's what made the output shippable.

Competitor ad image downloaded binary Analyze Image vision → text understanding Generate Image GPT Image 2 Strict system prompt “senior ad creative director” Your product inputs name · brief · reference image Your branded ad to Drive for human review v1 failure: Nespresso’s ads were Spanish → the generated ad came out Spanish fix: hard constraints — only my product, only my brand, only English; no competitors, watermarks, mockups Understanding crosses over — pixels never do. That is the plagiarism boundary, mechanically enforced.
Competitor image → vision description → strict system prompt → your branded ad
For your projects

Directly reusable for law-o-matic marketing assets: the creative-director prompt with a strict exclusions block, pointed at legal-services reference ads, is a ready-made asset generator.

Go deeper

In one line: Chain: Analyze Image (vision, model as heard 'GPT 5.5') describes the competitor creative from binary; Generate Image on GPT Image 2 renders from a ChatGPT-drafted 'senior performance ad creative director' system prompt with {{product_name}}/{{product_brief}}/{{product_image_URL}} slots and competitor headline/body as example context. V2 prompt adds hard output constraints (English-only, own brand only, no competitors/watermarks/mockups) after the first run inherited Spanish from the input ads. Both nodes run on n8n's built-in ~$2 OpenAI credits.

Vision-then-generate keeps the competitor image as understanding, not source pixels — the inspiration boundary, mechanically enforced (2:43:00)

GPT Image 2 chosen for generation — 'gives much better results'; Nano Banana (Gemini) named as an equally valid alternative (2:45:01)

Both AI nodes ride n8n's built-in OpenAI credits (~$2 free) — no API key required to reproduce the session (2:43:00)

The system prompt was itself written by ChatGPT on request — prompts are generateable artifacts too (2:49:06)

Failure mode found live: output language inherited from Spanish input ads; fixed by explicit English-only constraint (2:51:08 → 2:55:11)

Final output copy: 'Rich coffee, real moments, indulge in the rich, smooth taste, shop now' (2:55:11)

Try it now

Take any generation prompt you use and add a constraints block: language, brand exclusivity, no watermarks/mockups. Compare ten outputs before and after — the variance collapse is the lesson.

▶ Watch this taught: 2:43:00

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why does the competitor image go through a vision-description step instead of straight into generation?

So the generator works from an interpretation of the approach, not the pixels — that's the mechanical enforcement of inspiration-not-plagiarism.

Why did the first generated ad come out in Spanish, and what's the general rule?

Nespresso's scraped ads were Spanish and the model inherited its inputs' language. Rule: generation output inherits input properties unless the prompt explicitly constrains them.

Name three constraints the v2 prompt hard-codes.

Only my product/brand, only English text, no competitors / foreign language / watermarks / mockups.

12

The human-review gate: generate to Drive, not to the ad account

2:49:06

The workflow deliberately stops one step short of posting — every generated ad lands in a Drive folder for a human to approve.

Technically, nothing prevents wiring the pipeline straight into Meta's ad platform. The trainer refuses on purpose: these images represent your brand, generation is probabilistic, and one bad ad shipped automatically costs more reputation than the automation saves. So the final node uploads each generated creative to Google Drive, where a human reviews before anything goes live.

This is the general pattern: fully automate the expensive research and production, keep a cheap human checkpoint at the exact spot where errors become public. The trainer's own final check demonstrated the gate working — confirming English text, a clear CTA, and no competitor bleed-through before calling it done."

Worked example · from the session

Final run: the Kenco ad generates, uploads to Drive, and the last minutes of the session are the human review itself — text in English, CTA present, brand clean.

Why it matters

Where to put the human is a design decision every automation needs. The rule from this build: automate production, gate publication.

People get this wrong

A workflow with a manual step is only half automated.

The manual step is placed engineering. Research and production are fully automated; the five-second approval is the highest-leverage human act in the pipeline.

Go deeper

In one line: Generated ads upload to Google Drive rather than posting automatically; human review before publication is a deliberate design choice protecting brand reputation against probabilistic output. Automate production; gate publication.

▶ Watch this taught: 2:49:06

Check yourself

Answer from memory first — the recall attempt is what makes it stick. Then reveal.

Why not wire the pipeline straight into the Meta ads account?

Generation is probabilistic and the output is your public brand. The Drive gate costs seconds; one auto-shipped bad ad costs reputation.

Where, generally, does the human checkpoint belong in an automation?

At the boundary where errors become public or irreversible — automate everything up to it, gate the crossing.

Every concept, three clicks deep

The same concepts as a quick reference: the closed row is the glance, open is the study card, and every timestamp jumps into the recording.

01Winning ads: longevity, spend, and the public Ad LibraryMeta publishes all running ads in its Ad Library by legal requirement.0:20:23

Meta publishes all running ads in its Ad Library by legal requirement. Winning ads are identified by run duration (longest-running = proven), sustained spend, and CTA strength; the Apify scraper returns the date fields needed to filter for them.

Meta legally required to publish all ads — Ad Library is public access (0:22:24)

'The longest running ad is the most successful one… running for 6 months means something is working' (2:12:23)

Winning-ad signals: CTA strength and ad-spend doubling-down (0:30:30); impressions and engagement are the measurable tells (0:40:38)

'Garbage in, garbage out' — the workflow's output is only as good as the competitor set you point it at (0:38:36)

02Intelligence, not duplicationThe workflow is an intelligence system, not a duplicator: competitor ads are ingested as structural inspira…0:26:26

The workflow is an intelligence system, not a duplicator: competitor ads are ingested as structural inspiration (angle, layout, offer) while generation is constrained to your own brand, product and language. Outright copying dilutes the brand long-term.

03Reference images and A/B variants: why the pipeline makes several adsInputs: 5–10 reference images of your own product (generated via ChatGPT/Gemini if needed) plus competitor…0:38:36

Inputs: 5–10 reference images of your own product (generated via ChatGPT/Gemini if needed) plus competitor winning ads. Output: multiple ad variants with small copy variations for A/B testing; which converts depends on audience, brand language and stickiness, and engagement winners aren't always conversion winners.

04Why a workflow instead of a one-off scriptCLI/agent runs are one-off executions;0:50:47

CLI/agent runs are one-off executions; an n8n workflow with a form trigger is a reusable, sellable product — same capability, different asset class. Product surfaces: run-as-service, sell to agencies, or wrap in a Lovable UI.

05The n8n form trigger as product interfacen8n's form-submission node hosts a form and triggers the run: product dropdown, competitor Facebook URL (pl…0:48:46

n8n's form-submission node hosts a form and triggers the run: product dropdown, competitor Facebook URL (placeholder 'https://facebook.com/nike'), ad count (1–10, max 10), all fields required so no expensive downstream step runs on bad input.

06Use AI to build AI: ChatGPT writes every code nodeThe build method: split-screen ChatGPT + n8n;1:09:06

The build method: split-screen ChatGPT + n8n; paste the full workflow JSON as context, request each node's code with an explicit snake_case output contract, paste back and test. Deterministic steps become free code nodes; token-burning AI nodes are reserved for judgment. Errors are debugged by pasting them into the same chat.

Context move: copy the entire workflow JSON into ChatGPT before asking for anything (1:11:07)

Output contract requested explicitly: product_name, product_image_URL, product_brief, competitor_URL, number_of_ads — snake_case for readability in n8n (1:15:11)

Economics rule: code nodes execute free; OpenAI nodes charge per run — 'instead of always burning AI tokens' (1:23:20)

Debugging is the same loop: paste the failing output, get the diagnosis — used live on the Google Drive HTML-viewer bug (1:43:36) and the Apify curl command (2:22:37)

n8n's own Ask-AI assistant used once for an HTTP body fix (2:28:44); it also auto-flagged a hardcoded API token and converted it to a credential (2:30:47)

07Getting your product image behind a public URL (the Drive trap)Product images must be reachable as direct public file URLs for HTTP download into n8n.1:25:23

Product images must be reachable as direct public file URLs for HTTP download into n8n. Google Drive share links serve an HTML viewer by default and must be converted to direct-download form; alternatives are your own site, image hosts (ImgBB), or stock URLs for testing.

08Base64: turning an image into API-friendly textBase64 encodes binary image data as a text string so it can ride inside JSON API payloads;2:04:15

Base64 encodes binary image data as a text string so it can ride inside JSON API payloads; n8n's Extract-from-File + Move-to-Base64-String nodes do the conversion without custom code, after the image exists as binary.

09Apify's Facebook Ads Scraper as the data sourceApify hosts maintained scrapers callable by API.2:08:20

Apify hosts maintained scrapers callable by API. The official Facebook Ads Scraper (~29k users, free plan adequate for small runs) takes a brand's Facebook URL, locates its Ad Library entries, and returns per-ad JSON including images, copy, CTA, network and run dates; n8n integration via a ChatGPT-generated curl imported into an HTTP node.

Official Apify-built actor chosen over third-party clones; ~29,000 users at recording (2:10:21)

Input is just the brand's Facebook URL — the actor finds the Ad Library itself (2:12:23)

curl command generated by ChatGPT from the scraper docs, imported directly into the HTTP node (2:22:37–2:24:38)

n8n auto-flagged the hardcoded API token and converted it into a stored credential (2:30:47)

Anomaly kept honest: a test against Shein returned Nike ads — unexplained, suspected cookie/cache or sample data (2:14:26)

10Loop, then filter: processing ads one at a time, keeping only usable onesLoop Over Items (batch size 1) serializes the ad array for per-item processing;2:32:48

Loop Over Items (batch size 1) serializes the ad array for per-item processing; a code node normalizes heterogeneous ad JSON (images may live under cards/image/previews) and flags usable ads (image + body text + headline + CTA + page name); a Filter node passes only has_usable_image = true, skipping videos and mockups.

11Vision analysis + constrained generation (and the Spanish surprise)Chain: Analyze Image (vision, model as heard 'GPT 5.5') describes the competitor creative from binary;2:43:00

Chain: Analyze Image (vision, model as heard 'GPT 5.5') describes the competitor creative from binary; Generate Image on GPT Image 2 renders from a ChatGPT-drafted 'senior performance ad creative director' system prompt with {{product_name}}/{{product_brief}}/{{product_image_URL}} slots and competitor headline/body as example context. V2 prompt adds hard output constraints (English-only, own brand only, no competitors/watermarks/mockups) after the first run inherited Spanish from the input ads. Both nodes run on n8n's built-in ~$2 OpenAI credits.

Vision-then-generate keeps the competitor image as understanding, not source pixels — the inspiration boundary, mechanically enforced (2:43:00)

GPT Image 2 chosen for generation — 'gives much better results'; Nano Banana (Gemini) named as an equally valid alternative (2:45:01)

Both AI nodes ride n8n's built-in OpenAI credits (~$2 free) — no API key required to reproduce the session (2:43:00)

The system prompt was itself written by ChatGPT on request — prompts are generateable artifacts too (2:49:06)

Failure mode found live: output language inherited from Spanish input ads; fixed by explicit English-only constraint (2:51:08 → 2:55:11)

Final output copy: 'Rich coffee, real moments, indulge in the rich, smooth taste, shop now' (2:55:11)

12The human-review gate: generate to Drive, not to the ad accountGenerated ads upload to Google Drive rather than posting automatically;2:49:06

Generated ads upload to Google Drive rather than posting automatically; human review before publication is a deliberate design choice protecting brand reputation against probabilistic output. Automate production; gate publication.

Tools referenced

ToolCoverageMomentContext
n8ndemonstrated0:52:49Entire nine-node pipeline built live on a 14-day free trial; UI recently updated with an AI assistant panel; Ask-AI used once for an HTTP body fix; auto-converted a hardcoded API token into a credential
ChatGPTdemonstrated1:09:06Split-screen code generator for every code node, the Apify curl, the JSON parsing, the ad-generation system prompt, and live debugging; trainer's paid subscription
Apifydemonstrated2:08:20Official Facebook Ads Scraper actor (~29k users), free plan; called via API from an n8n HTTP node using a ChatGPT-generated curl
Google Drivedemonstrated1:35:29Two roles: hosting the product image (where the share-link HTML-viewer trap surfaced) and receiving generated ads for the human-review gate
GPT Image 2 (OpenAI, via n8n Generate Image node)demonstrated2:45:01'GPT image 2 gives much better results'; produced the final Kenco ad after the English-only prompt fix; ran on n8n's built-in ~$2 OpenAI credits
OpenAI vision (n8n Analyze Image node)demonstrated2:43:00Described the competitor ad image from binary; model as heard 'GPT 5.5' — exact version string ASR-blurred
Gemini (Nano Banana)demonstrated1:29:26Nano Banana — Google's image model — generated a Kenco product shot, compared against ChatGPT's for contrast; the cohort ultimately picked learner Sayed's image instead ('Sayed GPT')
Meta Ads Library MCP / Meta ads CLImentioned0:30:30Trainer has used the Meta ads library MCP 'inside Claude Code — it's really good'; a Meta ads CLI link was dropped in chat (0:48:46) as the one-off alternative to the workflow
Excalidrawmentioned0:12:12Workflow roadmap diagram with input/output notes per node; shared with the cohort after the session
Lovablementioned0:50:47Named as the UI wrapper if the workflow were productized fully
Claudementioned2:24:38'Opus 5 just released, and I think it's also really smart' — endorsed as an alternative code generator to ChatGPT
Claude Codementioned0:50:47The CLI alternative discussed in the why-a-workflow Q&A (ASR renders it 'cloud code'); prior sessions' tool, contrasted with n8n's product shape
Unsplashmentioned1:19:18Placeholder product-image source in ChatGPT's generated mapping code
ImgBBmentioned1:37:31Learner-suggested free image host for making product shots publicly fetchable (ASR: 'ImageBB')
GitHubmentioned0:08:09Callback to the prior session's GitHub + Lovable workflow homework
Wispr Flow / FreeFlowmentioned2:49:06Trainer's dictation tools aside: FreeFlow named as the free open-source option, slower than the paid one (ASR garbles the names; identities uncertain)

Session materials

Archived locally on V: — click to open. Companion pages link to the LMS.

Action items

Resources mentioned

Resources
  • docExcalidraw workflow roadmap — full node sequence with input/output notes, shared after session 0:12:12
  • docComplete n8n workflow JSON (form → mapping → download → base64 → scrape → filter → analyze → generate → Drive) — shared in LMS after session 2:54:43
  • docTrainer's full ChatGPT conversation (all code generation, parsing and debugging) — shared after session 2:54:43
  • docAd-generation system prompt for the GPT Image node (v2, strict) — built live with ChatGPT 2:53:10
  • docProduct-details mapping code snippet (ChatGPT-generated JavaScript for the code node) 1:09:06
  • docApify curl command for the Facebook Ads Scraper actor (imported into the n8n HTTP node) 2:22:37
  • docAd-filtering JavaScript (usable-ads normalizer; pre-generated snippet used in the interest of time) 2:34:50
  • docSayed's Kenco coffee product image (learner-shared, high quality — 'Sayed GPT'); trainer asked Sayed to share his prompt too 1:33:28
  • docMeta ads CLI link — dropped in chat as the Claude Code one-off alternative to the workflow 0:48:46

Extraction notes

This page was built from an auto-generated transcript, which garbles product and people's names. Those were corrected silently in everything above and logged here for transparency. The warnings flag claims that were true on the recording day but change fast.

Transcript corrections applied

The transcript saysThe trainer actually means
ChargeGPT / Chargebee / ChargegbtChatGPT
n a 10 / NA 10 / anytimen8n
cloud code / cloth codeClaude Code
OutscaleOutskill (the company/office)
x Cali draw / XcalidrawExcalidraw
ImageBBImgBB (image host)
SavoySayed (learner)
imagin Gen / ImageGenimage generation
Desperate masSpanish ad copy in the Nespresso creative (trainer couldn't read it)
GPT 5.5 / 5.6 whole / image 2as-heard model labels for the n8n OpenAI analyze/generate nodes — exact versions uncertain
Outskill your product / filters Outskill'Upload your product' / 'filters out' — the ASR substitutes the brand name for similar-sounding words
Apple pieApify
Harshid / Harshad / AshitHarshit (trainer)

True on recording day — verify before relying