S
SellTheClick
⚙️ Catalog Campaigns · Bid Strategy · Margin Control

How to Set a Minimum ROAS Floor in Meta Catalog Campaigns (So Low-Margin Products Stop Draining Budget)

By SellTheClick Team · Aug 17, 2026 · ⏱ 11 min read · Catalog Ads · ROAS Bidding · Feed Optimization

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."

📡 Meta Marketing API — bid_strategy
bid_strategy: LOWEST_COST_WITH_MIN_ROAS
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:

The key insight: "Set a minimum ROAS" alone doesn't solve the problem. It protects the account average. It does nothing about the specific product quietly losing money underneath a healthy-looking headline number — unless you first separate that product out.

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
⚠️ Stale labels are worse than no labels. A margin label should update automatically as prices or costs change. If your feed tool doesn't recompute 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.

Breakeven ROAS = 1 ÷ Gross Margin %

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:

This is more setup than typing a number into one field, but it's the only version of "minimum ROAS" that actually maps onto the real question — which product should Meta stop spending on — rather than the question Meta's native floor actually answers, which is closer to "keep my blended average acceptable."

Get the Sequencing Right Before You Set Any Floor

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:

  1. Custom labels to tag margin tiers in your feed
  2. Product Sets in Commerce Manager to separate those tiers
  3. Per-tier ad sets each carrying a floor set against that tier's real breakeven
  4. 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.

📚 Sources
Meta Business Help Center, About ROAS goal — facebook.com/business/help/1113453135474912
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 →
AV

SellTheClick Team

Founder, SellTheClick. Building AI ad intelligence tools for DTC brands and media buyers. Focused on creative distinctness analysis and how small teams can compete without a bigger budget.

Back to all playbooks