martechdevs has been acquired by Growth and Analytics Partners LLC

Multi-Currency Marketing Reporting Without Misleading Growth

Jafrin Akter Alo

Data Engineer and Co-founder, martechdevs

Last updated 9 min read

Blog cover: Multi-Currency Marketing Reporting Without Misleading Growth

Multi-currency marketing reporting needs the original amount and currency, a documented conversion policy and a traceable rate for each converted value. Keep operational performance, constant-currency comparisons and actual settlement separate. Otherwise, currency movements can look like campaign improvement, customer expansion or a billing discrepancy when the underlying business activity has barely changed.

Last updated: 8 September 2026.

Decide what the converted number should mean

A founder wants one revenue number in USD. A regional marketer wants to know whether a EUR campaign improved. Finance wants to explain the USD amount received from a payment processor.

Those requests need different views of the same activity:

  • Operational reporting: translate eligible revenue and cost using the team's dated reporting-rate policy.
  • Constant-currency comparison: hold exchange rates fixed while comparing periods, so currency movements do not drive the comparison.
  • Settlement reconciliation: retain the actual processor amounts, rates and fees affecting balances.
  • Budget comparison: use the planning rate approved for the budget, while also showing actual performance separately.

Choose the view based on the decision. Do not let whichever rate happens to be easiest to download become the company's reporting policy.

The warehouse and customer-data model should retain all these views without overwriting the original values. This article covers operational analytics design; it does not prescribe accounting, tax or treasury treatment.

Preserve currency before you convert anything

Every source amount needs a currency code and a unit definition.

A value of 1000 could mean ten dollars in minor units, one thousand yen, or a value already expressed in major currency units. Formatting all three with a dollar sign does not normalize them.

Stripe documents amount values in currency minor units, including zero-decimal currencies and operation-specific exceptions. It also distinguishes the charge currency from settlement currency. Follow the source and operation rules rather than applying a universal divide-by-100 transform. Stripe currency documentation.

Maintain a normalized source record with:

  • Original source ID, account and source system.
  • Original amount exactly as received.
  • Original currency and source unit convention.
  • Normalized amount in major units.
  • Event timestamp, source timezone and chosen reporting date.
  • The measure represented, such as ad spend or invoice value excluding tax.
  • Extraction timestamp and correction/version information.

Never infer transaction currency from a customer's country. A UK customer can pay in USD, and an advertising account serving several countries can have one account currency.

If currency is missing, quarantine the amount from converted totals and expose the excluded value or record count. Silently calling it USD creates a number that looks complete while being impossible to defend.

Store rates with a direction you can read aloud

A rate field called fx_rate is too vague.

Prefer a definition such as “reporting currency units per one original currency unit.” Under that contract:

Plain text
reporting_amount =
  original_major_amount × reporting_units_per_original_unit

For a hypothetical rate of 1.10 USD per EUR, EUR 100 becomes USD 110. If you also store the reciprocal, label it independently. Multiplying by the wrong direction can produce a plausible-looking value that is still wrong.

Your rate record should include the original currency, reporting currency, effective date, publication or retrieval time, source, rate value and policy version. Add the rate set used for constant-currency or budget comparisons.

Require one eligible rate per currency pair, policy and effective date. A duplicate rate row can multiply revenue during a join just as easily as a duplicated customer record.

The European Central Bank publishes reference rates against the euro. They are normally updated on working days, excluding TARGET closing days, and are intended for information rather than transaction pricing. Those properties matter when choosing them for an analytical reporting policy. ECB reference-rate documentation.

A reference rate is not evidence of the rate a processor actually applied.

Convert cross-rates explicitly

Suppose an illustrative reference file says:

  • One EUR = 1.10 USD.
  • One EUR = 0.88 GBP.

These are invented round numbers for calculation, not current market quotations.

To convert GBP into USD, divide the USD-per-EUR rate by the GBP-per-EUR rate:

Plain text
USD per GBP = 1.10 / 0.88 = 1.25
GBP 80 × 1.25 = USD 100

The units explain why the division works: the euro basis cancels.

Now imagine a campaign cohort has eligible revenue of EUR 1,000 and GBP 800, with eligible spend of EUR 200 and GBP 160. Using that same illustrative rate set:

  • Revenue is USD 1,100 plus USD 1,000, giving USD 2,100.
  • Spend is USD 220 plus USD 200, giving USD 420.
  • Revenue divided by spend is 5.0.

The calculation only becomes meaningful after “eligible” has been defined. A currency conversion cannot repair a mismatch between attributed revenue, total revenue, invoiced value and collected cash.

Convert the amounts first, sum them, then calculate the ratio. Do not average regional ROAS figures unless you have deliberately chosen the correct weights and can explain them.

See how an average rate distorts the answer

Daily conversion and converting a monthly total at an average rate are not generally equivalent.

Consider two illustrative EUR revenue days:

  • Day one: EUR 100 at 1.00 USD per EUR gives USD 100.
  • Day two: EUR 900 at 1.20 USD per EUR gives USD 1,080.

Transaction-day conversion totals USD 1,180.

The simple mean rate is 1.10. Applying it to EUR 1,000 gives USD 1,100, understating this particular result by USD 80. More of the activity happened on the higher-rate day.

A monthly average can still be a deliberate planning or reporting convention. Label it as such and assess whether the approximation changes a decision. Do not claim that it reproduces daily conversion.

For daily operational reporting, a useful design is to aggregate each measure by original currency and policy date, apply the corresponding rate, and then sum the converted amounts. This reduces processing volume without mixing dates or currencies prematurely.

Preserve sufficient decimal precision during conversion. Round for presentation at the documented stage rather than repeatedly rounding intermediate rates and amounts.

Separate exchange-rate movement from customer growth

Here is a second illustrative example with a single EUR-denominated customer cohort.

The opening recurring run rate is EUR 10,000. The ending run rate is EUR 11,000. The opening reporting rate is 1.10 USD per EUR and the ending rate is 1.20.

Translated at each period's rate:

  • Opening value: USD 11,000.
  • Ending value: USD 13,200.
  • Reported-currency growth: 20%.

Using the opening rate for both periods:

  • Opening value: USD 11,000.
  • Ending value: USD 12,100.
  • Constant-currency growth: 10%.

The reported increase is USD 2,200. Under this specific bridge, USD 1,100 comes from the local-currency increase translated at the opening rate, and USD 1,100 comes from translating the ending balance at the changed rate.

Neither view replaces the other. One describes the translated reporting amounts; the other isolates the comparison from rate movement under a declared convention.

For net revenue retention, hold both the customer cohort and the chosen constant-currency convention stable. Excluding churned customers or adding new customers would create a separate error that FX normalization cannot solve.

Explain why GA4, CRM and payment reports differ

Different systems can apply different conversion conventions even when their original amounts agree.

Google Analytics documents use of the prior day's exchange rate for local-currency transaction conversion. Its property reporting currency controls displayed monetary values, and changing it can affect historical reports. Raw transaction values in the BigQuery export retain local-currency values rather than simply adopting the property reporting currency. Google Analytics currency reference.

HubSpot's company-currency deal amounts use configured exchange rates, with different behavior for open and closed deals. Closed records also have date and historical-rate rules; some rate values can be changed through authorized edits or integrations. Export the relevant properties and history instead of assuming today's account rate explains every historical deal. HubSpot account-currency documentation.

Stripe balance transactions expose their own currency, gross amount, fee, net impact and, where applicable, exchange rate. The exchange rate describes the conversion direction between original and converted amounts. Use these actual records when explaining processor balance activity. Stripe Balance Transaction reference.

The practical response is a reconciliation bridge:

  1. Match the underlying transaction or agreement.
  2. Compare original currency and amount.
  3. Compare the measure definition and eligible events.
  4. Compare date, timezone and rate policy.
  5. Explain fees, tax and adjustments separately.

Do not replace the actual processor amount with an ECB-derived estimate simply to make the marketing dashboard agree. The Stripe-to-CRM reconciliation guide covers the underlying commercial and payment relationships.

Make weekends and missing rates a visible policy

A daily report can run before the selected provider has published today's rate. It can also encounter a weekend, holiday or unsupported currency.

Write the fallback rule before the first missing value occurs. For an analytical reference-rate policy, you might permit the latest available prior published rate within an agreed age limit. Record both the event date and the rate date used.

That is a team policy, not a universal provider guarantee. A Friday rate used on Sunday should be identifiable, and an old rate after an extended feed outage should fail the age test.

Never fill a missing cross-currency rate with 1. A rate of 1 is appropriate for identical original and reporting currencies under this model; it is not a generic error handler.

Separate expected non-publication days from ingestion failures. Alerting on every weekend creates noise. Treating a broken rate feed as another weekend conceals a growing reporting problem.

If a currency is unsupported, retain its local-currency totals and show the unconverted coverage. Add a documented alternative source only after agreeing its conventions and history.

How the workflow fits together
Original amount validation and policy selection lead to traceable conversion or explicit rate exceptions before comparable totals are published
Open full diagram

Handle refunds without rewriting the original sale

Keep the refund as a linked event with its own original amount, currency and timing.

A cash-activity report can translate the refund under its event-date policy. A campaign-cohort performance report might use the original sale's rate to remove the refunded value from that cohort. Those are different analytical choices.

For example, EUR 100 originally translated at 1.10 produces USD 110. Refunding EUR 100 when the selected rate is 1.20 produces USD 120 under an event-date convention. The extra USD 10 reflects the chosen translation basis; it is not evidence that the customer received more than EUR 100.

Label the policy and keep actual processor settlement separate. Do not let a BI tool automatically net unlike converted measures because both columns happen to be called revenue.

When a source transaction is corrected or a rate is revised, retain the previous published result and record which periods were restated. This belongs in the metric contract, alongside the owner and refresh policy.

Test the conversion layer before using it for budgets

  • EUR 100 at 1.10 USD per EUR produces USD 110.
  • The illustrative GBP cross-rate produces USD 100 from GBP 80.
  • The mixed-currency cohort produces USD 2,100 revenue, USD 420 spend and 5.0 ROAS.
  • The uneven daily-volume example produces USD 1,180, not USD 1,100.
  • The growth example shows 20% at period-specific rates and 10% at constant currency.
  • Missing, duplicate and stale rates produce explicit exceptions.
  • Currency-specific source units normalize correctly before FX conversion.
  • Refund and restatement policies preserve the original records and conversion lineage.
  • Dashboard labels identify the reporting currency, rate policy and unconverted coverage.

Start with the currencies and measures that drive an actual spending decision. Once the model can explain one campaign's revenue, cost, refunds and exchange-rate effects, expand its coverage. The goal is to make a budget decision more reliable, not merely to put the same currency symbol on every chart.

Questions people ask

Should every marketing report use the same exchange rate?

Use a consistent policy for measures intended to be compared, but keep different analytical purposes separate. Actual settlement, constant-currency growth and a budget-rate comparison need different treatments. Label each view so readers know what changed.

Can I use today's rate for historical revenue?

You can create a deliberately labelled current-rate scenario, but it will change as exchange rates move. It should not silently replace a historical reporting policy. Preserve original values and dated rates so prior reports remain reproducible.

Why does converted GA4 revenue differ from Stripe?

Check original amounts, eligibility, transaction coverage and date policy before blaming FX. The systems can also use different conversion conventions and represent different measures. Processor fees, tax, refunds and collection status require separate reconciliation.

Is an average monthly rate wrong?

It can be a legitimate chosen convention, but it does not generally reproduce daily conversion when activity is uneven. Assess the materiality of the difference and label the method. Use the same agreed method on comparable inputs.

How should I show a currency without an available rate?

Keep the original-currency amount visible and exclude it from the converted total with a clear coverage warning. Route it for an approved alternative source or repair. A missing rate must not become 1 or silently remove the record from every view.

Sources

  1. Stripe supported currencies and amount conventions. Accessed 8 September 2026.
  2. ECB euro reference exchange rates. Accessed 8 September 2026.
  3. Google Analytics currency reference. Accessed 8 September 2026.
  4. HubSpot account currencies. Accessed 8 September 2026.
  5. Stripe Balance Transaction object. Accessed 8 September 2026.

Written by

Jafrin Akter Alo

Data Engineer and Co-founder, martechdevs

Jafrin Akter Alo is a data engineer and co-founder of martechdevs, where the team has delivered 74+ martech, data and growth stack implementations.

Book a Free Audit

A free audit of your stack and what it needs. No pitch.

Thirty minutes, and you leave with a plan

We look at what you have, what it is costing you and what to do about it first.

  • 30 minutes
  • Video call, link on booking
  • No obligation

What we'll cover

  • Your current stack and where it hurts
  • Quick wins we can ship first
  • An integration roadmap
  • Timeline, scope and next steps

Calendar not loading? Open it in a new tab or email hello@martechdevs.com.