How to Set a Minimum ROAS Floor in Meta Catalog Campaigns (So Low-Margin Products Stop Draining Budget)
Meta's minimum ROAS setting is a campaign average, not a rule for each product. So a low-margin item can keep taking budget at 2.8x while the campaign as a whole still hits your 3.2x goal.
In Ads Manager it's called ROAS goal. Meta says it keeps your weekly average ROAS near the number you set, and that it "works best when your ad set gets at least 50-100 weekly conversions." There is no setting for a minimum ROAS per product.
The fix is two steps: tag products by margin using custom labels in your feed, then split them into product sets so each group sits in its own campaign with its own ROAS goal. That is the only way the floor applies to the products you care about.
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 // Ads Manager accepts 0.001 – 1,000.00
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.
Text label or number? Custom labels are treated as text. Meta's developer changelog says numeric operators (greater than, less than) are "not available" on custom_label fields and points to custom_number_0–custom_number_4 instead. So if you'd rather store margin as a number (say, custom_number_0 = 18) and filter "less than 20", use a custom number field. Text tiers like low_margin work fine with "is" filters.
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: breakeven is 1 ÷ 0.30 ≈ 3.3x, so anything you set below that accepts a loss on paper.
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.
Set it too high and the cost shows up as unspent budget, not as better profit. Meta says so directly: ROAS goal "may spend less than your full budget when the market is competitive to protect your performance target." If the tier can't reach its breakeven at all, a ROAS goal won't fix that. The product needs a better price, a better margin, or to leave the ad pool.
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
- Check volume per tier before you split. Meta says ROAS goal works best with at least 50–100 conversions per week per ad set, and suggests consolidating ad sets that fall short. Splitting one catalog into four tiers splits the conversions too. If a tier can't get near that number, merge it with the next tier or leave it on Highest value until it can.
- Start below your real ROAS, not above it. Meta's best-practice page says to start with a goal "10–20% lower than your average ROAS." If a set has been averaging 3.0x, that's a starting goal of about 2.4x–2.7x. No history? Meta suggests running Highest value for at least two weeks first and using that result.
- Change it slowly. Meta says to judge ROAS goal on weekly averages, wait at least 7 days after any change, and move the goal in 5–10% steps: lower it if lots of budget is left unspent, raise it if budget is fully spent at well below target.
- 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.
Can You Exclude Low-Margin Products From Meta Catalog Ads?
Yes, and it's the most reliable part of this whole setup. A product set is just a filter on your catalog. Build one that leaves out negative_margin (or whatever label you use), and use that set in every catalog ad set. Products outside the set can't be shown, whatever the bid strategy.
Two things to check after you do it:
- Every catalog ad set uses the filtered set. One old ad set still pointing at "All products" brings the excluded items straight back.
- The set's item count matches what you expect. Commerce Manager shows how many items a set contains. If an exclusion set shows zero, your label values probably don't match the filter (a typo, or a feed that hasn't refreshed).
ROAS Goal vs Highest Value for Catalog Ads
Both bid strategies chase conversion value. The difference is what they give up when the auction gets expensive. From Meta's help page:
| ROAS goal | Highest value | |
|---|---|---|
| Priority | Keep weekly average ROAS near your number | Spend the full budget |
| When competition rises | May spend less than budget | Keeps spending, ROAS can drop |
| Use it for | Low- and medium-margin tiers | High-margin tier, or any tier while you collect two weeks of data |
Meta's own rule of thumb: "Choose ROAS goal bidding if maintaining a specific return matters most. Choose Highest value bidding if spending your full budget matters most."
A Worked Example
Our numbers, made up for illustration. A store has three tiers. Breakeven is 1 ÷ margin:
| Tier | Margin | Breakeven ROAS | Trailing ROAS | What to do |
|---|---|---|---|---|
| High | 45% | 2.2x | 3.1x | Highest value, push budget |
| Medium | 30% | 3.3x | 4.0x | ROAS goal ≈ 3.4x (15% under 4.0x, still above breakeven) |
| Low | 15% | 6.7x | 3.5x | No ROAS goal saves this; exclude, or fix price or margin |
The low tier is the one the original question is really about. It "converts", so Meta keeps spending on it, but at 3.5x on a 15% margin every sale loses money. A floor wouldn't help: to protect it you'd set 6.7x or more, and Meta would likely stop spending on it anyway. Excluding it says the same thing honestly and frees the budget for the tiers that make money.
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.
FAQ: Minimum ROAS in Meta Catalog Campaigns
Can I set a minimum ROAS per product in Meta?
No. ROAS goal applies to the whole ad set (or campaign, with Advantage+ campaign budget) and Meta keeps the weekly average near your number. To control individual products, group them by margin with custom labels and product sets, and give each group its own ad set and goal.
Where do I set a minimum ROAS in Meta Ads Manager?
Pick Maximise value of conversions as the performance goal at the ad set level, then choose ROAS goal as the bid strategy and enter the number. If you use Advantage+ campaign budget, Meta says to choose ROAS goal at the campaign level first, then set the value in each ad set.
Why did my catalog campaign stop spending after I set a ROAS goal?
Most likely the goal is higher than the auction can deliver right now. Meta says ROAS goal may spend less than the full budget in a competitive market. Its advice for this case is to lower the goal 5–10% and wait a week, or to consolidate ad sets that get fewer than 50–100 conversions a week.
What ROAS goal should I start with?
Meta suggests starting 10–20% below your average ROAS from Ads Manager, measured within your attribution setting. Then check it against your breakeven (1 ÷ margin). If the starting number is below breakeven, that product group is losing money at current performance, and the bid strategy won't change that.
How do I stop Meta promoting low-margin products?
Tag them in your feed with a custom label (or a custom number for the margin itself), build a product set that leaves them out, and use that set in every catalog ad set. Products outside the set can't be shown.
Should I use custom_label or custom_number for margin?
Use custom labels for text tiers like high_margin and low_margin. Use custom_number_0 to custom_number_4 if you want to store the margin as a number and filter with greater than or less than; Meta says numeric operators don't work on custom labels.
Meta Business Help Center, Best practices for ROAS goal — facebook.com/business/help/288309751798466
Meta for Developers, changelog Mar 3, 2022 (custom_label vs custom_number filters) — developers.facebook.com/docs/graph-api/changelog/non-versioned-changes/mar-3-2022
Facts checked Oct 29, 2026.
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 →