Ads Manager says the campaign returned 3.1x ROAS. $8,200 spent, $25,500 in tracked “purchase” value, arrow pointing up and to the right. Then the CRM export lands: of the 1,020 signups Facebook counted as conversions, only 150 actually deposited. Real RevShare revenue from those 150 players over the next 30 days: $6,150. Real cost, including the ad spend and a $350 network processing fee: $8,550. Net result: a $2,400 loss on a campaign Facebook is telling you to scale harder. This isn’t a rare glitch — it’s what happens every time the platform reporting your ROAS can’t see the event that actually generates your revenue. If you want a number worth scaling or killing a campaign on, you have to calculate it yourself.
ROAS, ROI, and ROMI: The Formulas You Need
Three metrics get used interchangeably in media buying chats, and that’s exactly how people talk themselves into scaling a losing campaign. They answer different questions.
| Metric | Formula | What it answers |
|---|---|---|
| ROAS (Return on Ad Spend) | Revenue ÷ Ad Spend | ”For every $1 in ad spend, how much revenue came back?” |
| ROI (Return on Investment) | (Revenue − Total Cost) ÷ Total Cost × 100 | ”What percentage profit did I make on everything I spent, not just ads?” |
| ROMI (Return on Marketing Investment) | (Gross Profit − Marketing Spend) ÷ Marketing Spend × 100 | ”Isolating just the marketing spend, what’s my return?” |
ROAS = Revenue / Ad Spend
ROI = (Revenue - Total Cost) / Total Cost × 100
= Net Profit / Total Cost × 100
ROMI = (Gross Profit - Marketing Spend) / Marketing Spend × 100
ROAS is a ratio (“3.1x”) that ignores everything except ad spend. ROI is a percentage, and only means something if “Total Cost” includes every real cost — network fees, tracker/CRM subscription, chargebacks. ROMI scopes the same math to marketing spend alone, which matters once a business has costs outside marketing’s control (COGS, fulfillment). For a media buyer running paid traffic to affiliate offers, ad spend is usually close to the whole marketing cost, so ROMI and ROI tend to converge on the same number.
The trap: a 2x ROAS sounds great until you realize ROI can still be negative if your non-ad costs are high enough. Never let ROAS substitute for ROI when deciding whether to keep spending.
Break-Even ROAS and Break-Even CPA
Before calling a number “good,” you need to know the number below which you’re losing money — and it usually isn’t 1.0x.
Break-even ROAS = 1 + (Non-Ad Costs / Ad Spend)

If ad spend is your only cost, break-even ROAS is exactly 1.0x. Add a $150 network fee on top of $6,000 in spend and the floor moves:
Break-even ROAS = 1 + (150 / 6,000) = 1.025x
Below 1.025x on that campaign, you’re losing money — even though a naive read says “over 1x, we’re fine.”
For CPA offers, it’s more useful to flip the question around: what’s the most you can afford to pay per conversion on ads? That’s break-even CPA:
Break-even CPA = Payout per Conversion - Variable Cost per Conversion
If a nutra network pays $32 per confirmed FTD and tracker/processing cost is $1.33 per conversion, break-even CPA is $30.67. Bid up to that number and you’re structurally profitable; go over it and every conversion loses money regardless of what ROAS the dashboard shows.
Worked Example: Gambling RevShare Campaign
| Metric | Value |
|---|---|
| Ad spend | $6,000 |
| Clicks | 12,000 |
| CPC | $0.50 |
| Registrations | 600 |
| FTDs | 180 |
| RevShare revenue per FTD (30-day window) | $45 |
| Other direct costs (network fee) | $150 |
Total RevShare revenue = 180 FTDs × $45 = $8,100
ROAS = $8,100 / $6,000 = 1.35x
Total cost = $6,000 (ad spend) + $150 (network fee) = $6,150
Net profit = $8,100 - $6,150 = $1,950
ROI = $1,950 / $6,150 × 100 = 31.7%
Break-even ROAS = 1 + (150 / 6,000) = 1.025x
Actual ROAS (1.35x) clears break-even ROAS (1.025x) with room to spare — and it’s real profit, since the $8,100 is confirmed RevShare revenue from the operator’s postback, not an assumed pixel value.
The discipline: don’t price a RevShare campaign off day-1 FTD value alone. The $45-per-FTD figure above is the number after the 30-day window closes and rebills settle. Running this math on day one, before deposits mature, understates real revenue and can get a profitable campaign killed early (more on that in FTD tracking, explained).
Worked Example: Nutra CPA Campaign
| Metric | Value |
|---|---|
| Ad spend | $2,400 |
| Clicks | 6,000 |
| CPC | $0.40 |
| Confirmed FTDs (CPA conversions) | 90 |
| Payout per FTD | $32 |
| Tracker/processing cost | $120 total ($1.33/conversion) |
Revenue = 90 × $32 = $2,880
ROAS = $2,880 / $2,400 = 1.2x
Total cost = $2,400 + $120 = $2,520
Net profit = $2,880 - $2,520 = $360
ROI = $360 / $2,520 × 100 = 14.3%
Achieved CPA = $2,400 / 90 = $26.67
Break-even CPA = $32 - $1.33 = $30.67
Margin/conversion = $30.67 - $26.67 = $4.00 → $4.00 × 90 = $360 (matches net profit)
CPA math is cleaner than RevShare because the payout is fixed and confirmed the moment the postback fires — no lifetime-value guesswork. The tradeoff is a thinner margin: 1.2x ROAS here is a genuinely tight campaign, whereas 1.2x on a RevShare offer still mid-accrual would likely still be a loser once it fully matures.
EPC and EPV: The Inputs Behind Every ROAS Number
Earnings per click (EPC) and earnings per visit (EPV) are the building blocks behind your ROAS number, worth tracking on their own because they show where a campaign is winning or losing before the aggregate ROAS does.
EPC = Total Revenue / Total Clicks
EPV = Total Revenue / Verified Visits (post traffic-filtering)
Run it against the two worked examples above:
Gambling: EPC = $8,100 / 12,000 = $0.675
Nutra: EPC = $2,880 / 6,000 = $0.48
Notice that EPC ÷ CPC reproduces the same ROAS you already calculated:
Gambling: $0.675 / $0.50 = 1.35x (matches)
Nutra: $0.48 / $0.40 = 1.2x (matches)
That identity is useful before you spend a dollar: knowing your typical CPC and historical EPC on an offer lets you estimate expected ROAS in advance. It’s also why EPC broken out per traffic source, creative, or funnel status matters more than one blended number — a creative with a modest CTR but a high EPC can out-earn a “better performing” creative pulling more clicks at a lower EPC. DarkCore’s analytics breaks EPC out per conversion status and shows click-to-status and install-to-status conversion rates side by side, so you can see which stage of the funnel actually produces revenue instead of inferring it from a single ROAS line.
EPV differs only in the denominator: it’s calculated against verified, filtered visits rather than raw ad clicks. If a chunk of your paid clicks are bots or traffic your quality filtering rejects before it reaches the offer, EPC understates how well the offer converts — EPV, on clean visits, shows the true earning power of traffic that actually reached the page.
Why Facebook’s Reported ROAS Is Not Your Real ROAS
![]()
Back to the campaign from the intro. Facebook’s 3.1x figure wasn’t fabricated — it did exactly what it was configured to do: multiply a conversion count by a static value typed into the pixel event setup, then divide by spend. The pixel fired on signup completion with an assumed $25 “purchase” value per event (a common workaround in gambling verticals that don’t send Meta granular deposit data), and Facebook had no way to know 870 of those 1,020 signups never deposited a dollar. That’s structural, not a bug: a pixel — or even a server-side Conversions API event — can only report what you tell it, when you tell it. It can’t check your CRM three weeks later for a redeposit, a chargeback reversal, or RevShare coming in under forecast because an account got flagged for bonus abuse.
The fix isn’t to distrust Facebook and guess instead — it’s to attribute revenue at the source. DarkCore fires pixels and postbacks only on real, verified conversions pulled from the operator’s or network’s callback: a deposit becomes revenue once the postback lands, not when a page loads. That means the ROAS your dashboard shows is computed against money that actually arrived, and auto-rules can pause or scale a campaign on that real, deposit-based ROAS — something Facebook’s own automated rules structurally cannot do, since they only see the pixel-side number.
Rolling ROAS and ROI Into a Real P&L
A single campaign’s ROAS is a diagnostic, not a P&L. To know whether the account is actually making money, every campaign’s real revenue and real cost need to land in one ledger.

Combine the two worked examples above into a single week:
| Line item | Amount |
|---|---|
| Ad spend — gambling campaign | $6,000 |
| Ad spend — nutra campaign | $2,400 |
| Total ad spend | $8,400 |
| RevShare revenue (gambling) | $8,100 |
| CPA revenue (nutra) | $2,880 |
| Total revenue | $10,980 |
| Network/tracker fees | $270 |
| Total cost | $8,670 |
| Net profit | $2,310 |
Blended ROAS = $10,980 / $8,400 = 1.31x
Blended ROI = $2,310 / $8,670 × 100 = 26.6%
This is the level double-entry accounting operates at: ad spend and network fees post as debits, confirmed revenue postbacks post as credits, and net profit is whatever’s left once every real transaction is on the books — not an estimate, a ledger. DarkCore’s finance module keeps this per workspace automatically, so “blended ROAS” isn’t a spreadsheet you rebuild every Monday.
One caution: blended numbers hide which campaign is doing the work. The gambling campaign alone carries a 31.7% ROI while nutra sits at 14.3% — a blended 26.6% looks healthy, but would look different tomorrow if the gambling traffic source got banned. Keep the marginal, per-campaign number next to the blended one.
Common Mistakes
- Counting registrations or pixel “purchase” events as revenue. Facebook counted 1,020 signups; only 150 ever deposited — scaling on signup count instead of confirmed deposits is how a “3.1x ROAS” campaign turns into a $2,400 loss.
- Calculating RevShare ROAS off day-1 FTD value only. RevShare accrues over the full attribution window — rebills, redeposits, ongoing play. Pricing off the first deposit alone understates revenue and gets profitable campaigns killed before they mature.
- Using blended ROAS instead of marginal ROAS per campaign or adset. A blended 1.3x can be one winning adset carrying three losers. Kill decisions need the marginal number, not the account-level average.
- Leaving non-ad costs out of ROI. Network fees, tracker/CRM subscription, chargebacks, and refunds all reduce real profit. A campaign can show 1.4x ROAS and still post negative ROI once every real cost is counted.
- Treating CPA and RevShare offers as comparable on raw ROAS. A 1.2x ROAS on a fixed CPA payout and a 1.2x ROAS on a RevShare offer mid-accrual carry very different risk — the CPA number is final the moment the postback fires, the RevShare number is still moving.
FAQ
What’s a good ROAS for paid traffic to affiliate offers?
There’s no universal number — it depends on payout model and cost structure. CPA offers need to clear break-even ROAS (often 1.15x–1.3x once tracker and network fees are counted) to be worth running. RevShare offers typically need more cushion — 1.3x–1.5x or higher on FTD-window numbers — because part of that ratio still has to absorb rebill volatility and churn you can’t predict on day one.
What’s the difference between ROAS and ROI?
ROAS is revenue divided by ad spend only — it ignores every other cost. ROI is net profit (revenue minus total cost, including non-ad costs) divided by total cost, as a percentage. A campaign can post a strong ROAS and still have a negative ROI if non-ad costs are high enough.
Is ROMI the same thing as ROI?
Functionally, yes — same formula, narrower scope. ROMI isolates the return on marketing spend specifically, which matters once you have costs sitting outside marketing (COGS, fulfillment). For a media buyer whose main cost is ad spend plus a network/tracker fee, ROMI and ROI will usually land on the same number.
How do I quickly check if a campaign is profitable?
Compare its real ROAS — revenue from confirmed conversions, not pixel-assumed value — to its break-even ROAS (1 + non-ad costs ÷ ad spend). If real ROAS clears break-even ROAS, you’re in profit; if it doesn’t, no CTR or CPM metric elsewhere in the dashboard changes that.
Every formula above is simple arithmetic — the hard part is feeding it real numbers instead of the numbers a platform is willing to show you. Facebook will always report against whatever event you handed it, whenever you handed it, and it will never check your CRM for the deposit that landed nineteen days later. If you’re scaling or killing campaigns off Ads Manager’s ROAS alone, run the same math against your confirmed conversions for one week and see how far apart the two numbers sit. DarkCore attributes revenue on real deposit and CPA postbacks by default, so ROAS, ROI, and auto-rules all operate on the number that’s actually true. Talk to us on Telegram or log in and check your real numbers.