RAW Chemistry — Meta ads: complete engagement record

Compiled 2026-08-30 UTC / 2026-08-29 evening PDT.

Written to be picked up cold by someone with no context. Everything is here: identifiers, every

ad day to the hour, every object and its state, every decision and its reasoning, every fix, every

mistake, every tool, every open question.

Companion docs (all in repo):

ADS-PLAN.md · LEARNINGS.md · sources/competitive-research/competitor-audit-2026-08-28/ ·

output/ufo-banner-2026-08-27/RECUT-NOTES.md · docs/META-ADS-MCP.md


PART 0 — TL;DR for someone picking this up right now

• One campaign is live. V81, CBO, currently $175/day (raised from $100 at 02:20 PDT Aug-29

by an out-of-session MCP call — operator has not confirmed this was intentional).

• Two ads running, both the same 30.1s UFO video. One shows the offer only on the end card

(control), one pins it on screen from 0.0s (banner). This is a one-variable test.

• Three days of data. Thu $6.11/ATC → Fri $6.13/ATC → Sat $11.60/ATC. Saturday broke the

pattern, but two things changed at once: the budget and it being the first weekend day.

They cannot be separated from history.

• Recommended immediate action, pending operator go: revert budget to $100. Saves ~$125.

Do not try to read Sunday. Monday vs Thu/Fri is the clean comparison.

• Campaign to date: $387.45 spend → $536.80 revenue, ROAS 1.39, 7 purchases, CAC $55.35.
• Blocked on four operator inputs: COGS, a true reason-why for the 70% offer, confirmation of

the budget change, and the go-forward budget.


PART 1 — Access, identifiers, credentials

1.1 Meta

itemvalue
Ad account928489503435693 — "Brett Ads"
Page107954045643337 — Raw Chemistry
Instagram user17841477912140752 — @rawchemistryus
Pixel622400256897443
Access routemcp__claude_ai_Meta__* MCP tools
TimezoneAmerica/Los_Angeles (PDT) — all "today" figures follow this, not UTC

instagram_user_id is mandatory on video ads under an all-placements ad set. Without it Meta

rejects with error 1772103. Statics do not need it.

1.2 Shopify

itemvalue
Storeraw-chemistry-store.myshopify.com
CurrencyUSD
MarketsUnited States (primary, localCurrencies:false) · International (localCurrencies:true)
Admin tokenpermanent offline shpat_ from own custom app
Custom app"Webbuildr 2", client ba66dfaf16713fd861fd4b70000ea92f
Credentials dir~/.config/admaker/credentials/ (mode 0600)
Health checknode tools/shopify-token-health.mjs → expect life OFFLINE

CAD warning. The operator browses from Canada and is served converted prices by the

International market. A discount shown as −$334.28 is the −$236.85 USD discount

(rate ≈ 1.4114). Convert before diagnosing any pricing "discrepancy". Our own checks run from a

US-routed host and always return USD — which is what the campaign actually transacts, since the ad

set is geo-US only.

1.3 Other

itemvalue
Competitor researchForeplay MCP (mcp__claude_ai_Foreplay__*)
Review hosthttp://15.204.83.60/ — static, read-only, mounts in /srv/www/_server/mounts.json
Repo/home/ubuntu/Documents/AdMaker
Ledgernode tools/history.mjs record / validate

PART 2 — Complete object inventory

2.1 Campaigns (13 total, 1 active)

campaignidstatus
**RAW \V81 Clean Test \UFO + LOOKUP + CUPID-R2 \save70 \Dark Posts**120249646488770611ACTIVE
RAW \V82 UFO Persistent-Offer \save70 \Dark Post120249669199670611PAUSED, never spent
RAW \V80 Single Test \3 Creatives \70% Arm120249645525260611PAUSED
RAW \V79 Video CBO \8 Creatives120249625544390611PAUSED
RAW \V79 Video ABO \4 Concepts x 2 Offers120249625270290611PAUSED
RAW \V77 ABO \6 Ad Sets x $10120249624812710611PAUSED
RAW \V77 Offer A/B \3 Concepts x 2 Offers120249615068040611PAUSED
RAW \V76 DCO Test \10 Concepts120249609686230611PAUSED
RAW \V76 Video \4 Creatives120249608591340611PAUSED
RAW \V76 Launch \6 Creatives120249599273780611PAUSED
RAW \Test120249424103750611PAUSED
RAW \Scale120249423872160611PAUSED
RAW \Prospecting \$100 Focused Test120249228401770611PAUSED
RAW \Prospecting \Main \7-Creative Portfolio120248830225130611PAUSED

2.2 The live ad set — 120249646492400611

Name: V81 | US 18-65 broad | FB+IG only | Purchase | no AN/WA/Threads


{"geo_locations": {"countries": ["US"], "location_types": ["frequently_in","home"]},
 "age_min": 18, "age_max": 65,
 "publisher_platforms": ["facebook","instagram"],
 "facebook_positions": ["feed","video_feeds","marketplace","story","search","facebook_reels","profile_feed"],
 "instagram_positions": ["stream","story","explore","reels","profile_feed","ig_search"],
 "device_platforms": ["mobile","desktop"],
 "targeting_automation": {"advantage_audience": 1}}
settingvalue
optimization_goalOFFSITE_CONVERSIONS
billing_eventIMPRESSIONS
destination / conversion locationWEBSITE
promoted_object{pixel_id: 622400256897443, custom_event_type: "PURCHASE"}
attribution7-day click + 1-day view
is_dynamic_creativefalse
bid strategyHighest volume (LOWEST_COST_WITHOUT_CAP), no cap

Meta narrows this further on its own — effective_facebook_positions routinely drops

video_feeds, and effective_instagram_positions drops explore. That is Meta's choice, not a

failed write. Compare effective_* against requested and report the delta rather than retrying.

2.3 All 14 ads in V81

adidcreativestatusspent
UFO control (end card)1202496542838806111356499863310834ACTIVE$220.48
UFO banner (offer @0.0s)1202496715034206111065147595893626ACTIVE$63.43
CUPID-R2 static save70 FINAL1202496542896406112138899159993629PAUSED$89.07
LOOKUP static save70 FINAL1202496542882906111068078835624142PAUSED$19.11
CUPID-R2 static save70 r21202496483130906111602876511241208PAUSED$0
UFO video b2g1120249646494080611953501277773660PAUSED$0
UFO video save70 r41202496485593406111570562491483849PAUSED$0
UFO video save701202496480219606111095709386226097PAUSED$0
LOOKUP static save70 r21202496483124706111389976239777840PAUSED$0
LOOKUP static save70120249648022840611949804804042637PAUSED$0
CUPID-R2 static save701202496480239506111810337963460700PAUSED$0
CUPID-R2 static b2g11202496473643906111783829736131871PAUSED$0
LOOKUP static b2g11202496464952306111037709372360910PAUSED$0
V47-05 static b2g11202496464961306111374909448090236PAUSED$0

Deleted: 120249662229150611 — duplicate of the banner ad, removed Aug-27 21:28 PDT.

2.4 V82 spare campaign

objectidstate
campaign120249669199670611PAUSED, $100/day configured, never spent
ad set120249669203280611PAUSED, Advantage+ Audience ON, mirrors V81 targeting
ad120249669207010611PAUSED, creative 1065147595893626 (same banner creative)

Built as a standalone home for the recut, then superseded by the decision to run the banner inside

V81 for a same-ad-set comparison. Retained as a spare.


PART 3 — The creative

3.1 What the live ads actually are

Both live ads are the same 30.1s video: UFO-V34, a "leaked interview" concept. A hooded,

unidentified source in a dark room describes building a pheromone blend as a skin-chemistry test;

intercut with Venice Beach footage of women turning to look as a man passes. Ends on the product.

• Control — offer appears only on the end card, at ~26s (≈86% into the runtime).
• Banner — a two-tone lockup, red 70% OFF + cream TODAY ONLY, **pinned from frame 0 to

frame 767 (25.57s)**, then fades as the end card takes over. Offer therefore on screen for the

entire runtime.

Both ship native 4:5 (1080×1350) and 9:16 (1080×1920) masters — separately rendered, never

derived. adapt_to_placement is OPT_OUT so Meta performs no reformatting; supplying both natives is

mandatory, not optional.

Masters: brands/raw-chemistry/output/ufo-banner-2026-08-27/masters-{4x5,9x16}/

Uploaded video IDs: 2005163350167527 (4:5) · 2170230443928592 (9:16)

Verification: 30.100s, 30fps, faststart confirmed by atom order (ftyp moov free mdat),

−14.46 LUFS, and decoded audio PCM sha256 identical to the control — proving the edit is

video-overlay-only.

3.2 Ad copy — verbatim, identical on both ads

Primary text:


Most cologne is built to smell good for an hour and then quietly quit on you.

RAW 27™ is pheromone-infused — the formula behind 500,000+ bottles since 2016.

★★★★★ 4.8/5 · 12,400+ reviews · Free shipping · 60-day guarantee
Get 70% off — today only.

Headline: Your Cologne Quit Two Hours Ago

Description: 70% off today only. Free shipping.

CTA: SHOP_NOW · Display link: RAWCHEMISTRY.COM

Destination: https://rawchemistry.com/pages/raw-pheromone-cologne

Copy was recovered by fetching the live ad's own preview iframe and parsing its payload — not

reconstructed from documentation. Docs drift; the served ad does not.

3.3 Creative configuration lock (every creative in this account)

• All 17 Advantage+ creative enhancements OPT_OUT via degrees_of_freedom_spec sent alone as

a JSON-encoded string: `image_touchups, text_optimizations, image_brightness_and_contrast,

image_templates, image_animation, image_uncrop, add_text_overlay, media_liquidity_animated_image,

adapt_to_placement, site_extensions, profile_card, enhance_cta, description_automation,

catalog_feed_tag, product_extensions, cv_transformation, inline_comment`

• self_ai_disclosure omitted entirely — never OPT_IN, never OPT_OUT. Immutable after creation.
• Dark posts via object_story_spec — nothing reaches the page timeline.
• placement_videos: 4:5 as the unscoped fallback, 9:16 scoped to FB story/reels + IG story/reels.

Exactly one unscoped entry is required by the API.

Traps: music is not a valid feature name and rejects the whole call. standard_enhancements

is deprecated. Validation stops at the first bad name, so the accepted 17 are expensive to

re-derive — reuse the list.


PART 4 — Every ad day, to the hour

4.1 Campaign daily

daydowbudgetspendimprreachfreqCPMCPCATC$/ATCICpurchrevenueROASCAC
Aug-27Thu$100$134.489577231.32$141$3.3622$6.11—3$218.901.63$44.83
Aug-28Fri$100$104.274393151.39$238$2.6717$6.13—3$218.902.10$34.76
Aug-29Sat$175~$151+675+——$266$3.0613$11.60—1$99.000.66$150+

Aug-29 was still running at time of writing (18:35 PDT, 77% elapsed, $147.48 at ad level).

Campaign lifetime: $387.45 · 50 ATC @ $7.75 · 10 IC · 7 purchases · $536.80 · ROAS 1.39 · CAC $55.35.

4.2 Aug-27 hourly (Thu, 3 ads, $100 budget)

hr PDTspendimprATCpurch
06$20.22941—
07$17.88772—
08$8.655131
09$16.63872—
10$13.9210741
11$6.487641
12$5.90531—
13$6.3155——
14$5.50732—
15$4.2038——
16$9.08561—
17$1.5640——
18$2.8535——
19$5.48512—
20$5.3642——
21$3.7221——
22$0.741——

Delivery began ~06:00. All 3 purchases landed 08:00-11:59. Spend spread broadly.

4.3 Aug-28 hourly (Fri, 2 ads, $100 budget)

hr PDTspendimprhr PDTspendimpr
00$1.851312$9.3724
01$1.88213$3.5122
02$0.08314$5.3129
03$0.06215$6.8323
04$0.47716$16.4137
05$2.391417$6.6340
06$2.22918$6.8227
07$7.771519$7.2820
08$3.481520$1.3718
09$0.761021$6.1333
10$1.57722$3.6727
11$4.901623$3.5126

Spend spread almost flat across 24h. Only $20.20 (19% of day) by 09:00.

Control-ad ATCs: 9 of 10 landed at or after 14:00. Biggest hour 16:00.

Why so slow in the morning: Aug-27 overdelivered to $134.48 (+34%). Meta balances across a

~weekly window, so Aug-28 was throttled early to repay it.

4.4 Aug-29 hourly (Sat, 2 ads, $175 budget) — through 14:59

hr PDTETspendCPMLPVATCpurch
0003$3.56$23721—
0104$1.65$1832——
0205$1.72$156———
0306$5.43$3192——
0407$9.96$255111
0508$9.62$19621—
0609$21.62$30561—
0710$15.04$30142—
0811$11.50$35921—
0912$6.45$19531—
1013$8.57$2451——
1114$3.16$316———
1215$6.61$264———
1316$2.30$121———
1417$2.70$159———

00:00-09:59 = $86.55 → 24 LPV, 8 ATC, 1 purchase.

10:00-14:59 = $23.34 → 1 LPV, 0 ATC, 0 purchase.

The 06:00-07:00 block took 51% of the day's early budget at the highest CPMs of the day

($305/$301 vs $121-196 later). That was not irrational: those are 09:00-11:00 Eastern, and the

morning produced every conversion. Meta optimises for predicted purchasers, not cheap impressions,

and paid a premium for the hours that convert.

Caution recorded: the 13:00-16:00 stretch looked like a dead zone and was then followed by

2 more control ATCs by 16:42. Dayparting cannot be judged intraday.

4.5 Per-ad lifetime

adstatusspendimprCTR$/LPVLPV$/ATCATCpurchrevenue
UFO controlACTIVE$220.489347.39%$3.8058$8.48265$377.85
UFO bannerACTIVE$63.433089.09%$3.7317$7.0591$59.95
CUPID-R2 staticPAUSED$89.077123.93%$4.0522$6.36141$99.00
LOOKUP staticPAUSED$19.111323.79%$4.784$6.3730—

4.6 Per-format CPM (Aug-27, the only day all formats ran)

adformatspendimprCPM$/ATC
CUPID-R2static$89.07712$125$6.85
LOOKUPstatic$19.11132$145$6.37
UFOvideo$25.20110$229$4.20

Video costs ~1.8× static per impression. 84% of Aug-27's impressions came from statics, which

is why that day's blended CPM was $141 — the cheapest of the three despite the highest spend.

4.7 Every funnel order (price-matched, PDT)

ordertimestamp PDTamountproductday
#164595Aug-27 08:18$59.95singleThu
#164597Aug-27 10:06$99.003-packThu
#164598Aug-27 11:05$59.95singleThu
#164608Aug-28 15:23$59.95singleFri
#164610Aug-28 18:22$99.003-packFri
#164612Aug-28 22:34$59.95singleFri
#164613Aug-29 04:52$99.003-packSat
$536.80

10 consecutive exact reconciliations between Meta-reported revenue and paid Shopify orders.

Identify funnel orders by PRICE. Shopify reports **every one of these as `firstVisit: direct,

lastVisit: direct` with no UTM, because the funnel converts through shop.app / Shop Pay, which

strips the referrer**. Non-funnel orders on the same days ($71.00, $67.50, $36.50, $34.50, $36.75)

are other products/channels.

4.8 Historical: FREE vs honest offers (90-day, pre-V81)

FREE adshonest-offer ads
spend$425.32$139.57
impressions10,1591,059
CPM$41.87$131.79
cost/LPV$1.49$4.65
revenue$73.00$218.90
ROAS0.171.57
revenue per LPV$0.26$7.30

Honest offers cost 3.1× the CPM and returned 9.2× the revenue per dollar and **28× the

revenue per landing page view**.


PART 5 — Chronology: what happened, when, and why

Aug-26 and earlier — the pre-history

Eleven campaigns had run (V76-V80, Prospecting, Test, Scale) on a funnel later proven broken.

Symptoms: cost per ATC $14-114, several days with zero purchases, and a Shopify attribution report

showing "Facebook/Instagram 0" in the last 16 orders — which was later shown to be **Shop Pay

stripping the referrer**, not an absence of ad-driven sales. Everything was paused to reach one

clean test.

Aug-27

whenwhatwhy
~04:45V81 built: 3 ads (UFO video, LOOKUP static, CUPID-R2 static), CBO $100/day, save70 armClean single-variable test after the funnel fixes
~06:00Delivery begins
08:18 / 10:06 / 11:05Three purchases land — $59.95 / $99.00 / $59.95Reconciled exactly to Meta's $218.90
13:33Banner recut added to V81 ad set as 120249662229150611, pausedOperator: "add it to the campaign but keep it paused"
19:27-19:28V82 campaign + ad set + ad created, all pausedOperator: "put it into its own campaign"
19:49V82 ad set corrected: advantage_audience 0 → 1Operator corrected me — A+A must stay ON; "no AI flags" means creative AI
21:28Duplicate ad 120249662229150611 deletedSame creative existed twice after two instructions
21:34CUPID-R2 and LOOKUP statics PAUSEDCost-per-ATC: UFO $4.20 vs $6.85/$6.37. CUPID-R2 had taken 66% of spend on the worst CTR
21:34Banner ad 120249671503420611 created in V81 ad set, activated 21:35To run banner vs control in the same ad set — one variable
21:37Meta approves the banner ad
day close$134.48, 22 ATC @ $6.11, 3 purchases, ROAS 1.63

Aug-28

whenwhat
all dayTwo ads only: UFO control + UFO banner. Budget $100
morningVery slow — $20.20 by 09:00 (19% of day). Cause: repaying Aug-27's +34% overdelivery
15:23 / 18:22 / 22:34Three purchases — $59.95 / $99.00 / $59.95
—9 of the control's 10 ATCs landed at or after 14:00
day close$104.27, 17 ATC @ $6.13, 3 purchases, ROAS 2.10 — best day of the three

Aug-29

whenwhat
02:20Campaign budget raised $100 → $175/day via ads MCP server, actor Brett Messinger. Not done in-session. Unconfirmed.
04:52One purchase, $99.00
06:00-07:5951% of early budget spent at the day's highest CPMs — but these hours produced the conversions
~10:00 onwardConversions stop; $23 spent 10:00-15:00 for 1 LPV
~16:00-16:42Two more control ATCs land — the "dead afternoon" read was premature
18:35$147.48 spent, 1 purchase, control ROAS 0.78 and falling
—Operator identifies Aug-29 is a Saturday — a second variable
—Operator rejects spending further to disambiguate; agreed to revert to $100

PART 6 — Everything paused, with reasoning and retrospective

whatwhenreasoning at the timeretrospective
CUPID-R2 staticAug-27 21:34$6.36/ATC vs UFO's $4.20; 66% of day-1 spend on the worst CTR (3.93%)Defensible on the chosen metric. But it was buying impressions at $125 CPM and never got worse than $6.36/ATC — the control later hit $15.90
LOOKUP staticAug-27 21:34$6.37/ATC, worst CTR, 0 purchases on $19.11Had briefly shown the account's best $/LPV ($3.55) at ~$14 spend, which inverted as the sample grew — a small-sample mirage I initially reported as promising
Duplicate banner ad 120249662229150611Aug-27 21:28Same creative in two placesCorrect; my own sequencing error created it
b2g1 arm (4 ads)pre-launchOperator selected the save70 armHeld as the week-2 arm test
r2/r4/superseded (6 ads)pre-launchEarlier renders replaced—
11 older campaignsAug-26/27Reduce to one clean test—
V82 campaignnever activatedBanner ran inside V81 instead for a same-ad-set comparisonCorrect — a separate campaign would have been a dirtier test and doubled spend

The consequential one. Pausing both statics left the campaign with two cuts of one video.

Blended CPM went $141 → $238 → $266 and impressions fell 957 → 439 → 269. Statics were the

cheap-reach layer. This did not, however, explain the Aug-29 spend pattern — see Part 8.


PART 7 — The funnel: every fix, with verification

#problemdetailfixverified
1Checkout hid the offerShopify mobile renders the order summary collapsed — a cold buyer saw only "Order summary" and a number. No product, no quantity, no discountAnchor prices + automatic discounts so the saving appears on the payment screenRendered checkout in a real mobile browser
2Anchor pricing—3-pack 67395347546416 $335.85 → $99.00 (−$236.85); single 67395347513648 $99.00 → $59.95 (−$39.05)API readback + live checkout
3Quantity overchargeDiscounts were fixed-amount with appliesOnEachItem:false — discount subtracted once per order while the anchor multiplied per unit. 3-pack ×2 charged $434.85 instead of $198.00Set appliesOnEachItem: true on both6 cart shapes re-tested: 3-pack ×1/×2/×3 = $99.00/$198.00/$297.00; single ×1/×2 = $59.95/$119.90; mixed = $158.95. No customer was ever affected — all funnel orders qty 1, no qty selector on the page
4Internal name leaking to buyersCheckout displayed RAW REVEAL V110 - 3 BOTTLES + FREE ROLL-ON (-$236.85) — Shopify prints the discount title verbatimRenamed to 70% Off Today - 3 Bottles + Free Roll-On and Today's Price - Single Bottle; tools/raw-offer-pricing.mjs corrected so a revert can't reintroduce themOrder summary expanded in a real browser: v110/RAW Reveal absent
5Shipping label contradictionDrawer promised FREE EXPRESS; checkout said EconomyDelivery profile 132870603056, holding only the two funnel variants, rate named FREE Express Shipping (2–4 days)node tools/raw-shipping-label.mjs verify
6Stale offer badgesUP TO 70% OFF contradicted the flat 70% claimRemoved0 remaining; 8 CTAs read GET 70% OFF TODAY
7Pixel fired too latePageView only after 30s or interactionsendBeacon PageView at a fixed 2,500ms, eid dedup key, _fbp/_fbc set incl. fbclid capture. Original 30s runtime loader left intactReal headless browser: one PageView at 2.73s, no interaction, zero JS errors
8Page speed regressionA 3-second tracking timer shipped and crashed live PSI to 71 / TBT 1,540msReverted within minutesPSI mobile 99/100/100/100, TBT 0ms; desktop 100/100/100/100; Core Web Vitals field data PASSED (LCP 2s, INP 162ms, CLS 0.02)

Discount node IDs: 3-pack 1616747659568 · single 1616747692336. Both ACTIVE, no end date.

24 code discounts exist and do NOT stack on these automatics — verified.

Funnel state now: click → LP (PSI 99, pixel at 2.5s) → drawer (offer visible) → checkout

(discount visible, correct name, free express labelled) → Shop Pay.


PART 8 — The open question: Saturday vs budget

Aug-29 broke a two-day pattern. $/ATC $6.11 → $6.13 → $11.60. ROAS 1.63 → 2.10 → 0.66.

Two variables changed simultaneously:

1. Campaign budget $100 → $175 at 02:20 PDT
2. Thursday/Friday → Saturday — the campaign's first weekend day

What the data can and cannot say

Purchase count proves nothing. At the Aug-27/28 rate (2.33/day), P(observing ≤1 purchase on a

given day) = 32%. One-versus-three is unremarkable.

Cost-per-ATC is the real signal — 13 events, not 1 — and it roughly doubled.

A single ad DOES absorb budget linearly. Hour-matched, the control ad only, hours 00:00-10:59

on both days:

Aug-28 ($100)Aug-29 ($175)ratio
spend$8.98$85.499.5×
impressions323109.7×
CPM$281$2760.98× — flat
ATC06

So budget does not inherently inflate cost. That kills the simplest explanation.

No weekend baseline exists. The account's only prior Saturday is Aug-08: $5.43 spend, 1 ATC.

Everything material changed since — creative, offer, checkout fix, pixel. Pre-Aug-27 days ran

different creative on a broken funnel ($/ATC $14-114). Nothing to compare against.

Agreed plan

• Revert budget $175 → $100. At 18:35 the campaign had spent $147.48, already past $100, so this

also halts remaining Saturday spend. Saves ~$40 tonight + ~$85 Sunday ≈ $125.

• Do not read Sunday. It differs from Thu/Fri on both weekend and budget.
• Monday Aug-31 at $100 vs Thursday/Friday at $100 is the clean like-for-like weekday read.
• Re-test $175 later on a weekday, with a wider creative base.
• Begin accumulating a day-of-week baseline — the account has never had one.

Rationale for not spending to disambiguate: the same answer is available later for the same money,

on a weekday, with better creative. Buying it now on a ROAS-0.66 day is paying a premium for a

tidier chart.


PART 9 — Banner vs control: where the test actually stands

control (end card)banner (offer @ 0.0s)
spend$220.48$63.43
impressions934308
CTR7.39%9.09%
$/LPV$3.80$3.73
$/ATC$8.48$7.05
ATC269
initiated checkout71
purchases51
revenue$377.85$59.95

Both cleared the 10-ATC gate cumulatively. The banner leads every cost metric; the control leads

purchases — but has had 3.5× the delivery, so the purchase gap partly reflects budget share.

Day by day the story flipped repeatedly:

Aug-28 $/ATCAug-29 $/ATC
control$6.36$15.90
banner$6.98$6.77

Not resolvable while Aug-29 is confounded. Carry into the Monday read.

What the competitor evidence predicted: short ads (≤35s) place the offer at a median 0.0s,

5/5 within five seconds; GODA's longest-running live ad pins its offer and a Buy 2, Get 1 FREE

badge from frame 0 and never removes them. That predicted the banner should win. **Our own money has

not confirmed it.**


PART 10 — Competitive intelligence (Foreplay, 2026-08-28)

Four brands, 250-ad newest-first samples, all creatives opened and measured.

brandactiveindexedVIDEOIMAGEDCOkill speed
Hypnosis by Cupids4523,24491%9%0%9.8h / 31h
Goda Perfume3878,9988%30%62%mixed
IM823214,49410%90%~0%slow
SALT & STONE82512,44014%23%62%barely kills — 93% still live

10.1 Findings

• Two operating models, no middle. Specialists (Cupids video / IM8 static) or DCO operators.
• Cupids: one concept, ten lengths. Their ten longest-running live ads share the identical

headline "Secret to Attention 👉" and are ten different files at **14.88, 38.19, 39.27, 39.83,

40.75, 46.53, 46.95, 60.67, 74.88, 91.9s. Live range spans 7.99s–93.18s**.

• Cupids kills on a schedule, not a curve — dead ads cluster at exactly 9.8h and 31h, no

3/5/7-day tail. Survivors from the same day run 94h+.

• Cupids launches in bursts — ~152 ads on Aug-26, 7 on Aug-27.
• Polish is not the winning variable. Cupids' survivors are phone-shot UGC: car selfies,

"testing pheromone cologne on my sisters hot friend", club footage, a screenshot of a review

captioned "The 500,000+ positive reviews weren't LYING".

• GODA: the copy carries the sale. Their DCO static is a flat offer card — cream circle,

wordmark, LAST CHANCE, 50% OFF, two clipart alarm clocks. No product, no model. Attached to

~600 words of first-person advertorial signed "Michelle D."

• GODA's video uses AI-generated dolls with cracked porcelain skin as a literal metaphor for

crepey skin, smoothing over a day-1→60 arc. No model, no shoot, no likeness rights.

• GODA gives the discount a reason-why. Their longest-running live ad: *"We Made Too Much Body

Oil / PLEASE HELP US EMPTY OUR WAREHOUSE" + "Buy 2, Get 1 FREE"*, both pinned from 0.0s, over a

spoken apology: "I told you that was the best price you'd ever get — and then we overproduced."

Ours asserts 70% OFF TODAY ONLY with nothing behind it.

• GODA statics are blunt pain-first — "F\*CK BEING 'JUST FRIENDS'", "Need A Relationship Spark?",

"Do Not Try This IF you enjoy being the only one making an effort" — plus hard price anchoring

($78 → $14/bottle) and review badges.

• Salt & Stone — clean product photography, press borrowing ("AS SEEN IN MARIE CLAIRE"),

scarcity ("Mini set. Big waitlist." / "SOLD OUT 3X").

• IM8 — restrained editorial, research-led ("You're Allowed To Stop Taking 12 Supplements").
• 30 seconds — our only length — is the length neither leader leans on.

10.2 Companion pages — confirmed

brandmodelpages
Cupidsfake editorialGents Secrets (categorised Magazine), Hypnosis by Cupids (categorised Musician/band, no website, 452 active vs main page's 199)
GODAinvented personasEmily The Fragrance Girl, Steve The Perfumer, Over 40 & Fabulous
IM8real authoritiesDr. James DiNicolantonio, Tim Gray, David Beckham (blue-verified), New York Post, Athleats Nutrition — plus 4 legitimate own-brand pages
Salt & Stonesingle page—

Satellite pages demonstrably outrun motherships. All three flavours are available options; the

choice is the operator's.

10.3 DCO — investigated and closed

Foreplay's display_format: DCO means **any multi-asset creative, including plain placement

customization**. Proven symmetrically:

• Salt & Stone "pools": 720×1280 + 720×900 pairs, 2 of 3 identical in duration to six decimals.
• GODA "pools": byte-identical duplicate cards across 4 opened ads.
• Our own ads: 11 of the newest 25 carry the DCO label. The UFO ad's two cards measure

720×1280 and 720×900 at identical 30.164042s with identical audio sha256.

There is no DCO gap. We have shipped the mechanism since V76. Do not reopen without new

primary evidence.

Boards published:

http://15.204.83.60/raw-chemistry/competitor-creatives/ · /raw-chemistry/offer-timing/


PART 11 — Everything learned

Full text in LEARNINGS.md. Complete list, grouped.

11.1 Offer and price

1. "FREE" trains Meta to find people who want free things. See Part 4.8. Cheap CPM is a

warning, not a win — a proposed rule to kill ads above $120 CPM would have killed every

profitable ad and protected every unprofitable one.

2. Higher price changes what a "bad" CAC is. AOV $72.97. CAC $43 against $73 AOV is a different

business from CAC $20 against $30. But breakeven CAC is still unknown without COGS.

3. An offer with a reason behind it beats a naked number (GODA evidence, untested for us).

11.2 Funnel

4. The offer must be visible at the moment of payment. Caveat carried: the famous "3 of 3 vs

5.3%" comparison used a double-counted denominator — IC fired twice (drawer + Shopify).

Real Aug-24 funnel: 129 LPV → 9 buy-button clicks → 1 purchase. Direction holds, magnitude was

inflated.

5. Promise-to-page continuity is a conversion gate. Stale badges, contradictory shipping labels,

hidden discounts — all fixable in an afternoon and worth more than a new creative.

6. Tracking must be verified in a real browser. Three false-negative traps: waiting <31s without

interacting; parsing ev= from a query string when Meta posts URL-encoded bodies; comparing

against a non-deferred page.

7. A dev-theme performance pass is not a live-site gate.
8. Fixed-amount discounts multiply wrong — test qty 2 and mixed carts.
9. Anything named that reaches Shopify is buyer-visible — discounts, shipping rates, delivery

profiles. No versions, run IDs or codenames.

10. The operator browses in CAD; the store and campaign are USD. Convert before diagnosing.

11.3 Creative

11. Format is not the variable; the specific creative is. We were wrong in both directions —

"video beats statics" (wrong on the metric that matters: statics bought LPVs at $1.53 vs $2.91

over 90 days) and then the UFO video beat both statics in V81.

12. Put the offer on screen from second zero — frame-verified across 40 competitor breakdowns.

Being tested; our own money has not confirmed it.

13. One concept, many lengths — Cupids' ten survivors, 7.99s–93.18s.
14. Polish is not what wins.
15. The copy can carry the sale — GODA's flat offer plate + 600-word advertorial.
16. Pain-first, named explicitly.

11.4 Measurement and decision-making

17. Add-to-cart is the decision currency, not purchases. ~20 ATC/day vs ~3 purchases.
18. Small samples produce confident mirages — four times in one week: LOOKUP's $3.55/LPV; the

banner's 29.6% CTR on 27 impressions; a "dead afternoon" that revived; a "$16.49/ATC" alarm that

was a partial-day artifact.

19. Never compare a partial day to a full day. Cost-per-outcome inside a partial day is not a

rate — impressions land before conversions.

20. A token's prefix does not tell you its lifetime — trust expires_in, never shpat_.
21. Budget scales linearly for a single ad — 9.5× spend → 9.7× impressions, CPM flat.
22. The learning phase is unreachable at this budget (~17 purchases/wk vs ~50). Never argue

from it.

23. Meta overdelivers the daily budget (+34% observed) and repays across the week. Spend pacing

is a multi-day system.

24. Verify by readback; never trust the write response. updated_fields echoes the request.
25. Reconcile revenue against the store by price — Shopify says direct for everything.
26. Check the activity log before explaining any delivery change.
27. Narrowing a campaign raises blended CPM — but does not explain day-to-day pacing.

11.5 Platform mechanics

28. Advantage+ Audience ≠ Advantage+ Creative. Audience is a delivery control, stays ON.

Creative mutates the ad — all 17 OPT_OUT.

29. Enhancements default ON if degrees_of_freedom_spec is omitted.
30. Placements default to Advantage+, which delivered us to Audience Network rewarded video,

WhatsApp status, Threads, Messenger. Pin FB+IG explicitly.

31. advantage_audience: 1 demotes age limits to suggestions.
32. self_ai_disclosure is immutable after creation.
33. Numbers in documentation carry their original context — an age_min: 25 was lifted from a

doc describing a UI dropdown limitation and applied as strategy.

34. Foreplay's DCO label = multi-asset creative, including placement customization.

11.6 Research method

35. Longevity is a proxy for profitability, not a measurement. Foreplay exposes no ROAS.
36. Competitor ad counts are not creative output.
37. Model-generated timestamps need frame verification — Gemini writes end = runtime for

anything that reads persistent. One badge claimed 0.0→31.209s; pixels show it gone by 6.9s.


PART 12 — Mistakes made, and how each was caught

Recorded because the pattern repeats and recognising it early is worth more than any single finding.

#mistakehow it was caughtrule adopted
1Claimed the LP had no trackingRepo had already documented and corrected this oncePrimary source before assertion
2"Video beats statics 2:1"Inherited from a handoff; 90-day data inverted it on cost/LPVNever inherit an unmeasured claim
3Picked the wrong static set from filenamesOperator: "that's the old run"Folder names lie; sort by mtime
4age_min: 25 from a UI-limitation docOperator: "18-65 is fine why did you do 25"Read the surrounding sentence
5AI enhancements left defaulted ONOperator asked "no creative enhancements?"Set every field explicitly
6Swept advantage_audience to 0Operator corrected — A+A must stay on"No AI flags" = creative AI
7Proposed a CPM>$120 kill ruleOperator: "we aren't saying free anymore"CPM describes who, not how well
8Shipped a 3s tracking timer → PSI 71Live PSI re-measureDev-theme pass is not a live gate
9Prevalence-as-proof on DCO — twiceOperator asked "is it genuinely more effective?"Presence ≠ performance
10Said shpat_ = permanent, "revoked not expired"The exchange returned expires_in: 86353Trust expires_in, not the prefix
11Blamed sandbox for exit 144It was pkill -f matching its own shellNever pkill -f a pattern in your own argv
12"The CLI hangs on auth"app list doesn't exist in CLI 4.6.1 — subcommand error misreadVerify the command exists before diagnosing
13Blamed campaign narrowing for front-loaded spendOperator: "yesterday had no statics either"Verify the cause actually changed
14Blamed multi-day pacing for the same thingActivity log showed the budget had been raisedCheck the change log first
15"CPM rises with budget"Hour-matched data showed CPM flat at 9.5× spendNever compare partial vs full day
16Called the afternoon deadTwo ATCs landed an hour laterDayparts can't be judged intraday
17Wrote a decision rule ignoring the weekdayOperator: "it's also Saturday"Enumerate variables before committing a rule
18Proposed spending ~$85 to disambiguateOperator: "so just waste money lol"The same answer is often available later, cheaper

**The dominant pattern: reaching for a plausible mechanism instead of checking whether the

suspected variable actually changed.** Items 13, 14, 15 and 17 are all the same error.


PART 13 — Tools built (all in tools/, all runnable)

toolwhat it does
shopify-oauth-paste.mjsPKCE paste-back OAuth for a headless host. Defaults to our own app; --cli falls back. Writes a .meta.json sidecar with real expires_in
shopify-token-health.mjsStructure + liveness + granted scopes; reports hours remaining, warns <6h. life OFFLINE = permanent
shopify-token-receive.mjsOne-shot paste form for an Admin API token — random path, verifies before storing, exits after one success
shopify-admin.mjsGeneric Admin GraphQL runner
raw-offer-pricing.mjssnapshot / apply / revert anchor prices + automatic discounts. Titles are customer-facing
raw-shipping-label.mjsCreates/verifies the surgical delivery profile
raw-pixel-verify.mjsVerifies the Meta event sequence through the funnel
raw-funnel-walk.mjs · funnel-walk-audit.mjsFull instrumented walk at iPhone viewport
audit-page-tracking.mjsDoes the page actually fire tracking? Documents the 3 false-negative traps
raw-trust-signal-audit.mjsWhere does a given string actually appear on the live page?
shopify-theme-file.mjsRead theme files into a local directory
history.mjsThe append-only ledger — record / validate
brands/raw-chemistry/scripts/analyze_competitor_offer_timing.pyOffer-timing analysis over Gemini breakdowns
brands/raw-chemistry/scripts/render-ufo-banner-2026-08-27.shRenders a banner master through the house chain

Skills created

skillcovers
build-meta-ad-objectsEvery campaign/ad set/ad/creative build. The Advantage+ split, broad targeting, placement lock, dark posts, self_ai_disclosure, plus scripts/verify-ad-objects.mjs which asserts the whole config from readback JSON and exits non-zero on failure
connect-shopify-admin-apiPermanent tokens on a headless host: PKCE paste-back, why the CLI client gives 24h tokens, the empty redirect_urls trap, fixing app config via CLI deploy, plus references/traps.md indexed by error string

PART 14 — Blockers (all operator inputs)

1. COGS / fulfilment / payment fees / refund reserve. Without it there is no breakeven CAC.

At $72.97 AOV:

| contribution margin | breakeven CAC |

|---|---|

| 70% | $51.08 |

| 60% | $43.78 |

| 50% | $36.48 |

| 40% | $29.19 |

Measured CAC has run $34.76 → $150+. At 50% margin the account is roughly breakeven; at 40%

it is losing money; at 70% it has room. **This single number converts every scale decision from

opinion into arithmetic.**

2. A true reason-why for the 70% — overstock, batch sellthrough, packaging changeover, 3-pack

launch inventory. Must be genuinely true; it is checkable by customers.

3. Confirm the 02:20 Aug-29 budget change was intentional — made via MCP, not in-session.
4. Go-forward budget — hold $100, or a step plan.

PART 15 — Next actions, in order

1. Revert budget $175 → $100 (pending operator go — recommended tonight, saves ~$125).
2. Let Sunday run. Do not read it — confounded on both weekend and budget.
3. Monday Aug-31: full-day $/ATC vs the Thu/Fri $100 baseline. Answers budget-vs-weekend and

resolves the banner test.

4. Build width (ADS-PLAN.md Phase 1): UFO at 12s and 60s alongside 30s; revive a static.

Target 5-8 distinct live ads before any further budget increase.

5. Phase 2: long-form advertorial copy behind a cheap offer plate; reason-why offer variant;

pain-first sharpening of the next static batch.

6. Phase 3: repurpose V82 as a $50/day testing campaign, 5-7 new ads/week, promote at 10 ATCs.
7. Only then step budget +20-30%, 2-3 days per step, judged on full-day $/ATC.

PART 16 — Standing rules (do not relitigate)

• Advantage+ Audience ON (advantage_audience: 1). Advantage+ Creative OFF (17 × OPT_OUT).
• Age 18-65, US, broad. No interests, behaviours, lookalikes, custom audiences.
• FB + IG only — forced by adapt_to_placement: OPT_OUT and native-master authoring.
• self_ai_disclosure omitted entirely, forever.
• Dark posts only.
• Verify by readback, never the create/update response.
• Judge on cost-per-ATC; confirm on purchases later.
• No kill/promote decision below ~10 ATCs per arm.
• Never compare a partial day to a full day.
• Risk/compliance analysis is pull-only — the operator will ask for it.
• Record every material change: node tools/history.mjs record --workstream ads.

Reproduction commands


node tools/shopify-token-health.mjs                    # expect: life OFFLINE
node tools/raw-shipping-label.mjs verify               # delivery profile 132870603056
node tools/history.mjs validate                        # ledger integrity
node ~/.codex/skills/build-meta-ad-objects/scripts/verify-ad-objects.mjs < readback.json
node tools/shopify-admin.mjs '{ shop { name currencyCode } }'

Published copy: http://15.204.83.60/raw-chemistry/handoff/

Source of truth: this file, in the repo.

⬇ .md