How to Set a Minimum ROAS Floor in Meta Catalog Campaigns (So Low-Margin Products Stop Draining Budget)
Here's a scenario every catalog advertiser eventually runs into: your blended ROAS looks fine — 3.2x, comfortably profitable on paper — but when you break it down by product, half your ad spend is going toward a SKU with a 12% margin that needs a 5x+ return just to break even, and it's sitting at 2.8x. Meta's algorithm doesn't know that. It sees a product converting reasonably well and keeps feeding it budget, because "converts well" and "makes money" are not the same signal, and nothing in a default catalog campaign tells Meta the difference.
The fix people usually reach for first — "just set a minimum ROAS" — runs into a wall almost immediately, because of how Meta's floor mechanism actually works.
The Floor Is a Campaign-Level Setting, Not a Per-Product One
Meta's bid strategy for this is called ROAS Goal in Ads Manager (LOWEST_COST_WITH_MIN_ROAS at the API level, passed as a roas_average_floor value). Per Meta's own documentation, it's a goal-based bid strategy: you set a target average return, and "the ad delivery system uses AI to dynamically adjust bids to maximize conversion value while keeping your weekly average ROAS near your goal over the campaign lifetime."
roas_average_floor: 3.5 // valid range: 0.01 – 1000.0
optimization_goal: VALUE // prerequisite — must be enabled
scope: ad_set // NOT per-product, NOT per-SKU
Two things in that definition matter more than they first appear:
- "Weekly average" — this is a floor on the ad set's aggregate performance over time, not a rule that pauses any individual transaction or product below the line. A SKU can run well under your target for days at a time as long as the set's blended average holds.
- Ad set level — the floor applies to everything that ad set is delivering. If your catalog ad set is running your full product range, one high-margin bestseller can carry the average while a genuinely unprofitable product rides along underneath it, invisible in the aggregate number.
The Actual Fix: Margin Data in Your Feed, Then Structure Around It
The mechanism that gets you to "stop promoting this specific low-profit product" is a two-step combination that Meta supports natively but doesn't set up for you automatically.
Step 1: Put Gross Margin Into Your Feed as a Custom Label
Meta gives you five optional custom label fields per product — custom_label_0 through custom_label_4 — that exist specifically for advertiser-defined segmentation logic Meta doesn't capture natively. The standard use for profitability control is a margin tier:
| Gross Margin | custom_label_0 Value | Tier | Bidding Posture |
|---|---|---|---|
| > 40% | high_margin |
High | Aggressive — can absorb lower ROAS |
| 20–40% | medium_margin |
Medium | Moderate floor set at real breakeven |
| < 20% | low_margin |
Low | Strict ROAS floor or Cost Cap |
| ≤ 0% | negative_margin |
Excluded | Never promoted — excluded from all ad sets |
custom_label_0 when a cost or price shifts, a product that was 35% margin in January and discounted to 15% in a sale will keep running under its old, now-wrong bidding logic until someone catches it manually.
Step 2: Build Product Sets Filtered by That Label
In Commerce Manager → Catalog → Sets, create sets filtered on custom_label_0. At minimum, build one set per margin tier, plus a dedicated exclusion set for anything at or below breakeven. This last one is the actual answer to the original question — a negative-margin product set that simply never gets included in any ad you run. No floor, no bid strategy: it's excluded from the pool Meta is allowed to draw from at all.
Step 3: Give Each Remaining Tier Its Own Ad Set and Its Own Floor
For the tiers you do want running, don't put them all in one ad set with one blended ROAS Goal. Split them:
High-Margin Set
Can run with a lower ROAS floor — or no floor at all, prioritizing volume — because the unit economics tolerate a less efficient acquisition cost. Breakeven ROAS ≈ 1 ÷ 0.40 = 2.5x gives you real room to scale.
Medium-Margin Set
A moderate floor calculated off its own breakeven, not a round number that "feels safe." Runs with enough headroom that delivery stays consistent. Example at 30% margin: floor set at 3.1x–3.3x.
Low-Margin Set
Strict ROAS floor, or a Cost Cap strategy if conversion volume is too thin for value-based bidding to learn properly. Even small overspend erodes the already-thin margin quickly on this tier.
Negative-Margin Exclusion Set
Never touches an ad. Excluded at the product-set level across every campaign in the account. This is the actual mechanism for "stop promoting this." No bid strategy needed — it never enters the auction.
The Breakeven ROAS Formula — Use It, Don't Guess
The number to set each floor against is your breakeven ROAS, not a round number that feels safe. A product line at 35% margin breaks even around 2.9x — a floor of "3.5" on that set isn't a safety margin, it's telling Meta to hold a standard the auction may not clear consistently.
The documented failure mode across agency guidance is uniform on this point: an aspirational floor doesn't protect profit — it restricts delivery and leaves budget unspent while you're left wondering why the campaign stopped scaling. One Meta-focused agency's troubleshooting data on stalled Advantage+ spend found a cost or ROAS goal set too tight was the single largest cause of non-delivery, ahead of budget issues, ad review, and catalog errors combined.
What This Looks Like End to End
Put together, the structure looks less like "one catalog campaign with a ROAS floor" and more like a small portfolio:
- A negative-margin product set, excluded from every ad in the account — the actual mechanism for stopping promotion of specific SKUs.
- A low-margin product set in its own ad set, with a strict ROAS Goal set just above its real breakeven, or a Cost Cap if conversion volume is too thin for value-based bidding to learn properly.
- A medium-margin set in its own ad set, floor reflects its own economics, runs with moderate efficiency targets.
- A high-margin set running aggressively — lower floor or no floor — because the margin can absorb the acquisition cost.
Get the Sequencing Right Before You Set Any Floor
- Let the ad set exit learning before adding a floor. Meta's own guidance and multiple agency playbooks converge on the same number: don't introduce a ROAS constraint until an ad set has accumulated roughly 50 purchases in a recent 7-day window. Adding a floor before that just restricts an already-thin data set further.
- Set the floor at or slightly below your ad set's actual trailing performance. If a set has been averaging 2.4x, don't launch its floor at 3.0x "to be safe" — that's the exact pattern that produces underspend. Start at or just under the real number, then tighten gradually once delivery is stable.
- Re-audit your margin labels on a schedule, not once. Custom labels are static text until something updates them. Set a monthly calendar reminder to verify your feed is recomputing margin tiers correctly.
- Watch for existing-customer distortion. If you're running inside Advantage+ Shopping campaigns, the Existing Customer Budget Cap setting matters too — without it, ROAS on any product set can look artificially healthy because it's being propped up by cheap retargeting conversions, masking whether the set is actually acquiring new, profitable customers.
The Short Version
There's no field in Meta Ads Manager that says "minimum ROAS per SKU." The ROAS Goal / LOWEST_COST_WITH_MIN_ROAS bid strategy sets a floor on an ad set's blended average — not on individual products inside it. To get the outcome you actually want — specific low-profit products stop getting promoted — you build that outcome yourself:
- Custom labels to tag margin tiers in your feed
- Product Sets in Commerce Manager to separate those tiers
- Per-tier ad sets each carrying a floor set against that tier's real breakeven
- A hard exclusion set for anything at or below zero margin
The floor is the enforcement mechanism. The product-set structure is what makes it enforce the right thing.
Meta for Developers, Bid Strategy (Minimum ROAS bidding, roas_average_floor) — developers.facebook.com/docs/marketing-api/bidding/overview/bid-strategy/
Meta for Developers, Advantage+ Shopping Campaigns — developers.facebook.com/docs/marketing-api/advantage-shopping-campaigns/
Know Which Creatives Meta Is Merging Before You Spend
Creative clustering is the silent budget drain before your ROAS floor even kicks in. SellTheClick shows you which of your ads Meta sees as the same — so you stop running 5 variations of one idea.
Analyze My Creative Library →