I audited $383K of Meta tROAS spend country by country. 7% had been failing on the exact metric the algorithm optimizes and it was hard to catch it.
Somewhere inside a campaign that was hitting its tROAS target, one country had been running at 28% All ROAS for three months. Finding a gap that big, for that long, was a shock for me. The target was 70%, no dashboard flagged it, but I found it because I went looking.
This is the story of that audit, and the scoring framework that came out of it.
The setup
A subscription app on Meta. Five tROAS campaigns split by platform and geo tier. March 1 to May 29. $383K in spend across 200+ countries with plenty of ad sets.
Quick vocabulary so we read the same numbers the same way. tROAS means Meta bids toward a total ROAS target. That target is the algorithm’s job description. D0 ROAS is our early signal. In this app, most initial revenue lands on install day, so D0 tells you fast whether a cohort makes sense. When I tested that on 38 other Meta campaigns, day 0 ROAS predicted day 28 ROAS better than cost per purchase did.
I judged the campaigns the way most teams judge them, by blended ROAS against target. That number looked on point all quarter.
One blended number hides everything
The Tier1 iOS campaign from that period had a blended D0 of 26%. Inside it:
| Country | D0 ROAS | All ROAS | What was happening |
|---|---|---|---|
| France | 49% | 66% | Strong, but All ROAS slid from 57% to 40% over the quarter |
| US | 23% | 62% | Below target, and the biggest spender in the campaign at $49K |
| Germany | 16% | 31% | Below target for three straight months. Going nowhere |
Blended D0 says 26%. The countries inside say otherwise.
Three completely different situations were hiding inside one blended number, and the hard part to accept is that the algorithm didn’t seem to care.
Why the algorithm might not have fixed this
tROAS answers to one blended target, an average across every country an ad set targets. Meta can use location when it bids, but nothing in the target asks it to hold each country to 70%.
So a bad country hides inside a campaign that looks fine blended. That country running at 28% All ROAS while its campaign printed 70% was failing on the target itself, the exact metric the algorithm optimizes. D0 flagged it early, All ROAS confirmed it, and the number at campaign level never blinked.
Good countries subsidize bad ones. The blend stays mediocre, and mediocre looks like business as usual.
This is not about questioning the algorithm. The algorithm answers to one blended number, never one per country, so covering countries manually falls to you. For the record, other possible breakdowns like age or gender looked very normal and expected, so this got me by surprise.
The framework: two metrics, three colors, three buckets
I used this scoring system to separate keep from cut. It runs on a country breakdown export and about thirty minutes a month.
Step 1: score each metric independently
I give each country two grades, one for D0 ROAS and one for All ROAS, each green, yellow, or red against bands built off the campaign’s target. This app’s bands came from its 70% tROAS target. Green All ROAS starts at the target, and the D0 bands come from what historically maps to hitting it. Steal the structure, but derive the numbers yourself, from your own target and your own curve from D0 to All ROAS.
D0 gives you the initial signal that I look at. All ROAS gives you truth, which is what the campaign is optimizing for. Here All ROAS means Meta’s reported purchase ROAS within the campaign’s attribution window. Pull it with the campaign’s own attribution window and value definition, or the comparison with the target is off before you start. A country at 25% D0 and 80% All is a different animal from 25% D0 and 30% All, and a single metric would blur them together.
Step 2: combine into three buckets
Green scores 2, yellow 1, red 0. Add both metrics.
| D0 grade | All ROAS green (2) | All ROAS yellow (1) | All ROAS red (0) |
|---|---|---|---|
| Green (2) | 4, Good | 3, Good | 2, Watch |
| Yellow (1) | 3, Good | 2, Watch | 1, Exclude |
| Red (0) | 2, Watch | 1, Exclude | 0, Exclude |
Good (3 or 4): keep, don’t touch. Watch (2): check monthly. Exclude (1 or 0): the algorithm won’t fix it, because the blended target still looks fine.
Step 3: add the time dimension
Averages hide direction. Two countries can carry the same quarterly verdict and be moving in opposite directions.
PH in the worldwide campaign declined from 33% to 24% to 17% D0, with All ROAS at 28% in a month where the campaign hit 70%. GB dipped to 17% in April and came back to 29% in May, with All ROAS hovering near target the whole time. The verdict is the same, but the trajectories are opposite. The monthly view tells you which one deserves patience.
Step 4: act on it
Exclude the countries red on both metrics that stayed red for three months with meaningful spend behind them. With 200+ countries, a few will look red by chance, which is why I wait for three months. Set a spend floor before judging anything, because a country with $80 behind it has a noisy ROAS, not a verdict. I checked the same question for ads, and in one account ROAS predicted the next week best once an ad had 50 or more purchases. Put the yellows on the watch list and check again monthly. Leave Good alone. After an exclusion, judge the whole campaign the next month on its blended ROAS and its volume, because the budget moves to other countries.
What it surfaced
None of this is visible at campaign level.
A full bar would be 50% of spend. One subscription app, five tROAS campaigns, March 1 to May 29.
The biggest three in that red group: PH in the worldwide campaign ($7.1K at 21% D0), MX on Android ($6.2K at 23%), DE in Tier1 ($2.1K at 16%).
That $27.6K stays parked where it is until someone manually looks. No alert fires and nothing turns red in Ads Manager. The campaign view said everything was fine while it happened. If you are not sure whether your blended target is hiding a country like this, the growth audit is where I check it for an account, and you can book it on its own at any spend level.
Excluding those countries does not hand the $27.6K back either. The spend moves to other geos, and costs and volume there move with it.
The takeaway
The algorithm is good at finding buyers. In this account, it was not good at abandoning geos that stopped converting. I saw the same thing with ads, where Meta kept scaling five ads that never reached the D0 target.
The whole system fits in four lines:
- Two metrics: D0 for speed, All ROAS for truth.
- Three colors per metric, scored against your own target.
- Three buckets: keep, check monthly, exclude.
- One monthly calendar reminder.
If you’d rather have a second pair of eyes run this audit on your account, my inbox is open.