Skip to main content
Thirdwatchthirdwatch
E-commerce & products

Automate Currency Conversion for E-Commerce Catalogs

Convert a product catalog's prices across currencies with current FX rates as JSON, with a repeatable pipeline instead of spreadsheet guesswork.

Sep 21, 2026 · 3 min read · 623 words
See the scraper →

TL;DR — The Currency Rates Scraper converts catalog prices across 340+ currencies with dated, provider-named rate records. Run it on a schedule, apply your buffer and rounding rules, and keep multi-currency prices current without spreadsheet drift.

Why catalog currency conversion drifts

Stores that localize prices usually convert once at launch and never again. The BIS triennial survey counts $7.5 trillion in daily FX turnover — rates move every day, and a catalog converted six months ago quietly misprices every international order.

The fix is a conversion step that is repeatable: pull current rates, apply your markup and rounding rules, push updates only where the drift justifies it.

How does this compare to the alternatives?

Manual spreadsheet Platform FX feature Thirdwatch actor
Cost Free but error-prone Bundled, opaque spread Pay per result
Reliability Stale fast Black-box rates Named dated sources
Setup time Minutes, then forever Zero Minutes
Maintenance You remember to update Vendor decides Scheduled runs

Platform auto-conversion is convenient but hides the rate it used. If you want to know — and defend — the number behind every localized price, you need the rate as data.

How to automate catalog conversion in 4 steps

How do I pull the rate table for my markets?

import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thirdwatch/currency-rates-scraper").call(
    run_input={
        "baseCurrencies": ["USD"],
        "targetCurrencies": ["EUR", "GBP", "INR", "JPY", "AUD"],
        "provider": "auto",
        "amount": 1,
        "maxResults": 10,
    }
)
rates = {r["pair"]: r["rate"] for r in
         client.dataset(run["defaultDatasetId"]).iterate_items()}

One call returns every market pair you sell into, each with its date and provider.

How do I convert a price list?

Join rates to your catalog and apply your pricing rules:

import pandas as pd

catalog = pd.read_csv("catalog.csv")  # sku, usd_price
BUFFER = 1.03  # market buffer over mid-market
def local_price(usd, pair):
    raw = usd * rates[pair] * BUFFER
    return round(raw) - 0.01  # .99 price points

catalog["EUR"] = catalog["usd_price"].map(lambda p: local_price(p, "USD/EUR"))

The actor supplies honest mid-market rates; buffer and rounding stay your merchandising decision.

How do I decide when to push updates?

Compare against the last applied rate and only reprice where drift exceeds your band:

applied = {"USD/EUR": 0.91}
for pair, rate in rates.items():
    if pair in applied and abs(rate - applied[pair]) / applied[pair] > 0.02:
        print(f"Reprice {pair}: {applied[pair]} -> {rate}")

Repricing on a 2% band avoids churning prices on noise while catching real moves.

How do I keep the evidence?

Append each run's records to a JSONL log keyed by date:

import json, pathlib
with open("fx_applied.jsonl", "a") as f:
    for r in client.dataset(run["defaultDatasetId"]).iterate_items():
        f.write(json.dumps(r) + "\n")

When finance asks why EU prices moved in March, the dated provider-named record answers it.

Sample output

{"base_currency": "USD", "quote_currency": "JPY", "pair": "USD/JPY",
 "date": "2026-09-11", "rate": 147.21, "inverse_rate": 0.0067933,
 "amount": 1, "converted_amount": 147.21,
 "provider": "erapi", "provider_name": "ExchangeRate-API open access"}

rate is mid-market; your buffer applies on top. provider_name documents the source behind every localized price.

Common pitfalls

Mid-market rates are not the rate your payment processor gives customers — expect a few percent of spread and price accordingly. Free sources fix daily, so flash sales keyed to live rates need the day's fix, not streaming ticks. Localized price points drift off .99 endings when rates move — re-round after conversion, not before. The actor's per-record provider field keeps every conversion attributable when two sources disagree.

Related use cases

Frequently asked questions

How often should catalog prices be reconverted?

Weekly is a common cadence, or on a drift trigger. Run the actor on a schedule, compare rates to the last applied fix, and reprice only pairs that moved beyond your threshold.

Does the actor handle rounding for display prices?

It returns the raw converted amount; rounding to price points like .99 stays in your pipeline. That separation keeps the rate data honest and the merchandising rules yours.

Can I cover every currency my store supports?

The target list takes any of 340+ fiat and crypto codes. Add a market buffer in your pricing logic rather than passing the raw rate to the shelf.

What about markets without a local currency option?

Keep those on your base currency and still record the rate — the audit trail explains every displayed price later.

Related

Try it yourself

100 free credits, no credit card.

About 30 real searches. Add the MCP to Claude or Cursor in two minutes.