Mixed currencies break every threshold you set
An agency runs twenty ad accounts. Fifteen bill in Vietnamese dong, five bill in US dollars, which is an ordinary situation for anyone with regional clients. Somebody writes a sensible protection rule: alert when a campaign spends more than 500.
On a dollar account that is five hundred dollars, roughly twelve and a half million dong, and only the larger campaigns reach it. On a dong account it is five hundred dong, under two US cents, and every campaign running has already passed it. One line of configuration, two outcomes about twenty-five thousand times apart, and nothing on the screen tells you which one you are getting.
This article covers what to do about that: the three ways a tool can handle mixed currencies, why the most annoying of the three is the correct one, and how to find the same fault in your own setup. Currency is the clearest example of a wider problem — numbers that carry a unit which nobody wrote down.
A number without a currency is not a threshold
In storage, spend is a number. The currency is not stored with it — it lives somewhere else, as a property of the ad account.
When you type a threshold you are thinking in the currency of whichever account is in your head at that moment. The system compares your number against every account in the rule's scope. If that scope mixes currencies, the comparison stops meaning anything, and no error is raised because nothing has gone wrong from the software's point of view. It was asked to compare two numbers and it compared them.
That is the whole fault. It is not exotic and it is not rare. It requires only that somebody, once, wrote a number without writing what it was a number of.
How this surfaced
Not in design. In checking.
While going through every condition and every action in an automation module one by one, one item on the list was the helper text shown when you set a money threshold. That text named a currency. The data store held accounts in two.
So for anyone configuring a dollar account, the helper text was simply wrong. And for a rule whose scope covered both kinds of account, no helper text could have been right, because the comparison underneath it was already meaningless.
This belongs to the same family as a threshold of zero being read as no threshold: the system runs cleanly, nothing errors, the output reads plausibly, and it surfaces only when someone sits down and compares what a person meant against what the software did.
Three options, two of them wrong
Convert automatically at the live rate
The option that sounds most reasonable, and the one that took longest to reject. Fetch the current rate, normalise everything into one currency, compare. Nothing extra for anyone to do.
Three problems, and the third decides it.
Rates move. A fixed threshold stops being fixed. The number in your rule stands still while the amount it actually blocks drifts with the exchange rate, day after day.
A campaign does not match today and matches tomorrow, and the reason has nothing to do with the campaign. Nobody looking at that history can make sense of it.
Which rate, from where. Every source gives a slightly different number and every source occasionally fails. When the lookup does not respond, what should the rule do? Use yesterday's rate? Skip the run? Every answer introduces a new way to be wrong, and each one needs its own handling.
You cannot reconstruct the decision. Three months later somebody asks why a campaign was paused on the fifteenth of June. Answering means knowing the rate on that date, from which source, at what hour. If you did not store it, the answer does not exist. If you did store it, you are attaching a rate to every single record, which is far more machinery than the convenience was worth.
A decision to pause a campaign that cannot be explained afterwards is the kind of decision a system should not be making.
Ignore units and treat a number as a number
This is what the system was doing when the problem was found, and it is the worst of the three.
No warning, nothing for anyone to notice. On a dong account, a threshold of 500 matches every campaign in the account, and if the rule's action is to pause, that lands the same morning.
The only thing that limited the damage was a cap on how many campaigns one run may touch. That was a general safety limit doing its job, not anything specific to currency, and relying on it would have been luck rather than design.
Require a currency and refuse to run on a mixed scope
Every money threshold carries a currency. The system filters campaigns to that currency. If the rule's scope spans more than one, it refuses to run and says why.
One more click when you set a rule. One fewer way for the system to be silently wrong for months.
Why blocking is the hard call and the right one
As a product decision, blocking is the worst of the three. It adds a step, it creates an error state, it makes the flow longer. In any usability discussion, "stop the user" is the option everyone argues against, and they are usually right.
The argument for it here is short. With other people's money, friction beats guessing.
There is a second argument that gets missed. When the system blocks, you learn something you did not know: that the scope you selected mixes account types. A good blocking message does not only prevent an error, it tells you a fact about your own setup. When a system guesses instead, you learn nothing, and you do not know that there was anything to learn.
The cost is real and worth stating. Anyone with a single currency has to pick it every time, which is a redundant step. Portfolio-wide rules become impossible — an agency with thirty accounts across countries cannot write one rule that covers all of them and has to split by currency instead. And people who hit the block usually assume the software is broken rather than that their configuration was ambiguous, which means the wording of the message does a lot of work.
What happens if you skip this
Take the agency from the opening: fifteen dong accounts, five dollar accounts. They write a protection rule — if a campaign spends over 2,000,000 with no results, pause it. The intention is clear, because two million dong is a painful number domestically.
On the five dollar accounts, two million dollars is a figure nothing will ever reach. The rule never fires there. Those five accounts have no protection at all, while everyone believes all twenty are covered.
Nothing tells them. The run history reads "ran, no action taken", which is indistinguishable from a healthy account where nothing needed doing. From the outside it looks perfect.
Reverse the direction and the failure inverts. A threshold written from the dollar perspective — spend over 200 with no results — means two hundred dong on the domestic accounts, an amount that effectively does not exist. Every campaign qualifies, and if the action is to pause, the whole portfolio goes dark in one morning.
One version silently protects nothing. The other silently destroys everything. Both come from the same missing piece of information.
Where to put the currency so nobody misreads it
Having decided to require a currency, the next question is how to present it without the requirement feeling like paperwork. Three attempts, in order.
A separate selector beside the number field. Clear enough, but it cluttered the form, and people routinely skipped it because a control sitting next to a field looks like an optional extra.
The currency inside the input box. Tidier. The problem appeared when somebody needed to change it: there was no obvious thing to click.
The currency inside the label. Instead of "Spend threshold", the label reads "Spend threshold (choose currency)". You meet the question while reading the label, which is the one part of a form nobody skims past.
The same principle decided the blocking message. The first version said, in effect, "invalid scope" — technically correct and useless. The version in use states that the selected scope includes accounts billed in different currencies, and suggests splitting the rule or narrowing the scope. The difference between those two is not functionality. It is that the second one tells you what to do next, which is the only thing an error message is for.
If you build reports rather than tools, the same rule applies: the unit goes in the column heading, not in a footnote under the table. Footnotes do not survive a screenshot pasted into a chat window.
Four other advertising numbers with a missing unit
Currency is the most obvious case, not the only one. Four more have the same shape, and most tools carry all four.
Daily budget versus lifetime budget
A budget can be set per day or for the whole life of the campaign. The same figure is two entirely different commitments. A rule that says "increase budget by 20%" means more spend every day in the first case, and a longer or faster run in the second, depending on how the platform interprets it. Rules have to know which type they are looking at and treat the two separately rather than as one field.
Cost per result, and which result
"Cost per result" is unambiguous only until you ask what kind of result. A campaign optimising for landing page views and one optimising for purchases both report results, and both have a cost per result. Comparing those two numbers compares the price of a page view against the price of a sale.
This is the most common mistake in any rule that spans campaigns with different objectives, and the fix is to separate rules by objective rather than by account.
Attribution window
How many days after a click a conversion still counts is a setting, and defaults differ by platform. Twenty conversions on an account using a seven-day window and twenty on one using twenty-eight days are not the same quantity. Nothing on screen says so, and the two numbers will sit next to each other in a report looking perfectly comparable.
Whether spend includes tax
Depending on the platform and the country, reported spend may or may not include tax, and the gap is around ten percent. For a tightly set threshold that is enough to change the outcome. When marketing reconciles against finance, this is the single most common cause of the recurring argument that the two sets of numbers do not agree.
All four share the currency problem's structure: the numbers look alike, the meanings differ, and nothing warns you. Attribution windows and tax handling are still open here, which is worth saying rather than implying everything is airtight.
Write the unit next to the number
If this compresses to one portable rule, it is that every number carrying a unit must carry that unit everywhere it appears. In storage, in the interface, in the log, in the summary email, in your own internal documentation.
It reads as redundant. The price of skipping it is a category of error that never announces itself, and that category is expensive out of all proportion to a few extra characters on a screen.
There is a quick test for any system, including one you built yourself. Take any number it shows you and ask where the unit lives. If the answer is "in the developer's head" or "everyone in this industry knows", that is an error waiting for the right day. The good answer is that the unit sits beside the number, in the same record, and travels with it wherever the number goes.
Two consequences of that rule are worth stating separately, because they are the ones people skip. A column named spend_usd is a comment, not a constraint — the first time somebody writes a dong value into it, nothing stops them. And a log entry saying a campaign was paused for exceeding a threshold has to name the threshold with its currency, or the entry cannot be verified six months later, which defeats the point of keeping it.
A units audit you can run in one afternoon
This works with any tool and needs nothing but access to what you already have.
Build the currency table. Every account, its currency, one row each. Plenty of teams managing a dozen accounts have never written this down, and everything below depends on it.
Check every automated rule against it. For each rule with a money threshold, compare its scope against the table. Any rule whose scope spans more than one currency is currently doing something other than what its author intended, no matter how normally it appears to run.
Interrogate every aggregate figure. For each dashboard total that combines accounts, find out how it was computed. If nobody can answer, treat that number as unverified until somebody can.
Check the numbers in shared documents. Target cost per acquisition, budget ceilings, performance thresholds written in a shared doc — do they state a currency? Usually not, because everyone in the room shared an assumption that a new joiner or a new market will not.
Check your exports. Files leave the context that explained them. A spreadsheet emailed to a client has none of the interface around it, so the unit has to be inside the file.
The usual output of this exercise is two or three genuine discoveries and a slightly uncomfortable conversation about how long they have been true.
When your portfolio genuinely spans several currencies
You cannot solve this by restructuring accounts. Platforms fix an account's currency when it is created and do not let you change it afterwards, so the separation already exists whether you use it or not. What you can restructure is everything you built on top.
Keep one set of rules per currency. Name them so the currency is in the name — "Pause on wasted spend (VND)" rather than "Pause on wasted spend". The tidying instinct is what reintroduces this problem months after somebody fixed it: a person merges two rules that look like duplicates, and the merged rule spans both currencies.
Set the thresholds independently, not by conversion. A dong threshold that was arrived at by converting a dollar threshold inherits all the drift problems of automatic conversion, just frozen at one moment. Decide what a painful amount of wasted spend is in each market on its own terms. The answer is often not the converted figure, because the markets have different costs.
Review both sets on the same day. Currency rules diverge quietly. If the dollar set gets updated in March and the dong set does not, the two stop expressing the same policy, and nobody notices because both keep running.
Teams working in a single currency are not exempt from any of this. Portfolios acquire currencies without anyone deciding to: a client expands abroad, an agency takes on a regional account, a parent company consolidates reporting. Nobody sits down and declares themselves a multi-currency operation. It arrives one account at a time, and the rules written under the old assumption keep running exactly as before. The dangerous moment is not the first foreign account. It is the third, when nobody remembers the automation was written when there was only one.
When a campaign moves between accounts
An edge case worth knowing before it finds you.
Advertisers rebuild campaigns in a different account fairly often — consolidating after an acquisition, moving from an agency account to a client-owned one, splitting a portfolio by region. If the new account uses a different currency, every historical comparison across that boundary is broken.
The campaign looks continuous in your reporting because it kept its name and its purpose. The numbers before and after the move are in different units.
The symptom is a campaign that appears to have become dramatically cheaper or dramatically more expensive on one specific date, with no matching change in performance. The date always turns out to be the migration date.
What to do: treat the migration as a hard boundary in reporting and do not draw a trend line across it. If you need continuity, convert the historical side once, store the rate you used, and label the series as converted so the next person knows.
This is also the argument for storing the currency on every record rather than looking it up from the account when you read. Records keep their original unit even when the account changes, which is what keeps history interpretable after an account is closed or replaced.
The reporting problem this creates
Rules are half of it. The same gap distorts reporting, usually more visibly and often sooner.
Any dashboard that aggregates spend across accounts faces the identical question, and there are three honest answers.
Do not aggregate. Show each currency separately with no combined total. Least satisfying to look at, and the only version guaranteed correct. Several finance teams insist on exactly this, because they have been burned by the alternatives.
Aggregate with the rate and date stated. Show a combined figure, and next to it the rate used and when it was taken. This is what accounting does, and it works because the assumption travels with the number.
Aggregate silently. Show one number, convert internally, mention nothing. Common, comfortable, and the reason two people in the same meeting can hold different figures for the same month while reading the same dashboard.
The third is worth dwelling on because it is so widespread. It rarely produces a dramatic failure. It produces a slow erosion of trust in the numbers, where people stop treating the dashboard as authoritative and start keeping their own spreadsheet. That is how an organisation ends up with four versions of the truth and an argument every quarter.
One rule avoids most of it: never show a converted number without the rate beside it. If there is no room for the rate, there is no room for the converted number.
How to test your own tool for this
Four tests, in order, each one taking a few minutes.
Single currency, sensible threshold. Set a threshold that ought to match on one account and confirm it does. This is your baseline, and it tells you the rule works at all.
Single currency, wrong-currency threshold. Set a dollar-sized threshold on a dong account and confirm nothing matches. If something matches, the currency filter is not being applied and the tool is comparing bare numbers.
Mixed scope. Build a rule spanning both account types and see what happens. A block with a message naming the problem is the right answer. A rule that saves and runs happily is the fault this whole article is about.
A scope that becomes mixed later. Build a valid single-currency rule, save it, then add an account of another currency to its scope. Confirm you are stopped at that moment rather than the following morning.
That fourth test comes from a real oversight. The first version validated only at run time, which meant a rule could silently become invalid on Tuesday afternoon and you would find out on Wednesday, in a log entry you might never open. Validation while the person is still sitting there is worth far more than validation six hours later.
What to ask a tool before you trust it with money
If you are choosing between tools rather than building one, do not only ask what a tool can do. Ask what it does when it is not sure.
Good tools stop and ask. Poor tools guess and continue. Both demo perfectly, because they differ only at the edges, and edges do not appear in demos.
"Is there a currency selector on money thresholds?" The fastest check there is. If there is none, the tool is assuming something, and you should find out what.
"What happens when data is missing?" Skip the campaign, or treat the value as zero? Those two produce very different outcomes, and the second one is how healthy campaigns get paused.
"What happens when a data fetch fails?" Stop, or carry on with yesterday's numbers? Carrying on with stale data without saying so is a silent failure built in on purpose.
"What happens when two rules conflict?" Are you told, or does one quietly win?
"Is there any situation where it refuses to run?" If the answer is never, it always guesses. For something that moves money, always guessing is not a strength.
Frequently asked questions
Does this affect me if all my accounts use one currency?
Only in that you pick a currency once when creating a threshold. Everything else behaves normally. The reason to read the rest is that portfolios pick up a second currency without anyone planning it.
Why not detect the currency from the account automatically?
The account's currency is known. The difficulty is that thresholds belong to rules, and a rule can span accounts with different currencies. Somebody still has to say which currency they meant, because the rule is where the ambiguity lives.
Is there a downside to storing the currency on every record?
Slightly more storage and one more field to get right on write. Against that, it is the only way historical records stay interpretable when an account is closed, migrated or replaced, because looking the currency up from the account fails exactly when the account no longer exists in its original form.
Would automatic conversion ever be acceptable?
Only with two conditions met: the rate used is stored on every record so decisions can be reconstructed, and the interface shows plainly that conversion is happening. Without both, it should not be built, because it produces decisions nobody can explain.
What if an account needs to change currency?
Platforms generally do not allow it after creation. Where a change is genuinely needed, a new account is created, and every rule scope pointing at the old one has to be updated. Treat that as part of the migration work rather than something to discover afterwards.
Should I split my accounts by currency?
They already are, since the platform fixes the currency at creation. What is worth splitting is your rules: one set per currency, named clearly enough that nobody merges them later for tidiness.
Why not warn instead of blocking?
Warnings on a screen people see repeatedly stop being read within about a week. A warning that is always dismissed is functionally the same as no warning, except that everyone now believes the risk was communicated. If something is genuinely unsafe, block it. If it is safe enough to permit, do not warn about it.
What is the fastest check on any tool?
Open the place where money thresholds are set and look for a currency selector. Its absence means the tool is assuming something. Ask what.
Start with the currency table
Open a spreadsheet and list every ad account you touch with its currency, one row each. It takes twenty minutes and most teams have never done it.
Then hold every automated rule up against that list. Any rule whose scope covers more than one currency is not doing what its author meant, and has not been for as long as it has existed. That is usually the moment this stops being an abstract concern.
The wider habit is worth keeping past this one problem: every number in a system carries an implicit unit, and implicit is where errors are born. Until the unit is written next to the number, the system keeps a way of being wrong that nobody can see.
Related reading: allocating budget across platforms, spend guardrails and caps, and reconciling platform conversion numbers.
Orova Ads optimises campaigns for you
Connect Google, Meta and TikTok in one place. AI reads the numbers, proposes changes and executes under the rules you set.
Explore Orova Ads