There’s a moment in every global startup founder’s life when they realise someone in Lagos and someone in San Francisco are paying the same £9.99 for a PDF. Both will only buy if it’s worth 1–2 hours of their labour. That PDF costs you the same to serve. But the maths doesn’t work for either of them—and it definitely doesn’t work for you. You need Stripe PPP.
Enter The Economist’s Big Mac Index: a deceptively simple tool that measures currency parity by asking a single question: how much does a Big Mac cost where you live? If a Big Mac costs $5.15 in the US and £4.19 in the UK, there’s your exchange rate adjusted for actual purchasing power. Not a bank’s rate. Yours.
This is the basis of Price Point Parity (PPP)—and someone has built a script that makes it invisible, algorithmic, and borderline automated. It’s a magic trick that’s actually honest.
How the Magic of Stripe PPP Works (And Where It Breaks)
Imagine your Stripe product—a template, course, design pack—priced at $49. A developer in Buenos Aires visits your site from Argentina. Behind the scenes:
- The script has fetched The Economist’s live Big Mac Index (updated regularly when you run it)
- It’s calculated Argentina’s purchasing power relative to your base currency
- It’s created a new Stripe price specifically tagged for Argentina at ~$18 (because a Big Mac in Buenos Aires costs proportionally less)
- Stripe’s geo-detection shows only that price to customers in Argentina
- To them, it’s invisible. They see a fair local price. You see more sales in markets that otherwise couldn’t afford you.
The honest part: This is not a subscription API. It’s a one-time script runner. You fetch the CSV, it creates prices, they stack up in Stripe like geological layers. There’s no “delete all PPP prices” button—Stripe’s API doesn’t support bulk deletion. It can automatically disable them individually, but they linger. So you need to:
- Run this script deliberately, with intention
- Test in dry-run mode first (always)
- Accept that tweaking later means manual dashboard clicks or careful pricing strategy
- Plan for this if you’re doing PPP pricing across multiple products
It’s not a set-and-forget to keep the prices updated. But it’s not complicated either.
The Actual Stripe PPP Script
Here’s the implementation. Clone it, read it, run it. It’s Python, so you’ll need pip install stripe requests and a working Python environment.
#!/usr/bin/env python3
"""
Stripe Product Big Mac PPP Pricer
Fetches The Economist's Big Mac Index and creates country-specific prices
"""
import stripe
import requests
import csv
import os
from io import StringIO
from typing import Dict, List
# Configuration - REPLACE THESE
STRIPE_API_KEY = "sk_test_YOUR_API_KEY"
STRIPE_PRODUCT_ID = "prod_YOUR_PRODUCT_ID"
DRY_RUN = True # Set to False to actually create prices
# Currency map: country name → ISO 4217 code
CURRENCY_MAP = {
"Argentina": "ARS",
"Australia": "AUD",
"Brazil": "BRL",
"Canada": "CAD",
"Chile": "CLP",
"China": "CNY",
"Colombia": "COP",
"Costa Rica": "CRC",
"Czech Republic": "CZK",
"Denmark": "DKK",
"Egypt": "EGP",
"Euro area": "EUR",
"Hong Kong": "HKD",
"Hungary": "HUF",
"India": "INR",
"Indonesia": "IDR",
"Israel": "ILS",
"Japan": "JPY",
"Malaysia": "MYR",
"Mexico": "MXN",
"New Zealand": "NZD",
"Norway": "NOK",
"Pakistan": "PKR",
"Peru": "PEN",
"Philippines": "PHP",
"Poland": "PLN",
"Russia": "RUB",
"Saudi Arabia": "SAR",
"Singapore": "SGD",
"South Africa": "ZAR",
"South Korea": "KRW",
"Sweden": "SEK",
"Switzerland": "CHF",
"Taiwan": "TWD",
"Thailand": "THB",
"Turkey": "TRY",
"United Kingdom": "GBP",
"United States": "USD",
"Venezuela": "VES",
}
stripe.api_key = STRIPE_API_KEY
def fetch_big_mac_index() -> Dict[str, float]:
"""
Fetches The Economist's Big Mac Index CSV and returns
price data as {country: usd_equivalent}
"""
url = "https://raw.githubusercontent.com/TheEconomist/big-mac-data/master/output-data/big-mac-full-index.csv"
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
print("[✓] Big Mac Index CSV fetched successfully")
except requests.RequestException as e:
print(f"[✗] Error fetching Big Mac Index: {e}")
return {}
# Parse CSV
reader = csv.DictReader(StringIO(response.text))
big_mac_data = {}
for row in reader:
country = row.get("country")
price_usd = row.get("usd_price")
if country and price_usd:
try:
big_mac_data[country] = float(price_usd)
except ValueError:
continue
print(f"[✓] Parsed {len(big_mac_data)} country price points")
return big_mac_data
def get_product_base_price(product_id: str) -> Dict:
"""
Retrieves the product's default price from Stripe
"""
try:
prices = stripe.Price.list(product=product_id, limit=100)
default_prices = [p for p in prices.data if p.type == "recurring" or p.billing_scheme == "per_unit"]
if not default_prices:
print(f"[✗] No prices found for product {product_id}")
return None
base_price = default_prices[0]
print(f"[✓] Base price: {base_price.unit_amount / 100} {base_price.currency.upper()}")
return base_price
except stripe.error.InvalidRequestError as e:
print(f"[✗] Error retrieving product: {e}")
return None
def calculate_country_price(base_amount: int, base_price_usd: float, country_price_usd: float) -> int:
"""
Calculates PPP-adjusted price for a country
Returns amount in cents (Stripe standard)
"""
ppp_ratio = country_price_usd / base_price_usd
adjusted_amount = int(base_amount * ppp_ratio)
# Enforce sensible minimums/maximums
min_amount = 50 # $0.50 minimum
max_amount = base_amount * 2 # Don't let PPP create absurd prices
return max(min_amount, min(adjusted_amount, max_amount))
def create_ppp_prices(product_id: str, base_price: Dict, big_mac_data: Dict) -> List[str]:
"""
Creates country-specific prices based on PPP
"""
created_prices = []
base_amount = base_price.unit_amount
base_currency = base_price.currency.lower()
# Find base country's Big Mac price in USD
base_country = None
base_big_mac_usd = None
# Try to infer base country from currency
currency_to_country = {v: k for k, v in CURRENCY_MAP.items()}
base_country = currency_to_country.get(base_currency.upper(), "United States")
if base_country in big_mac_data:
base_big_mac_usd = big_mac_data[base_country]
print(f"[✓] Base country: {base_country}, Big Mac: ${base_big_mac_usd}")
else:
# Default to US if we can't determine base
base_big_mac_usd = big_mac_data.get("United States", 5.15)
print(f"[⚠] Defaulting to US Big Mac price: ${base_big_mac_usd}")
# Create prices for each country
for country, iso_code in CURRENCY_MAP.items():
if country not in big_mac_data:
print(f"[⚠] Skipping {country}: no Big Mac data")
continue
if iso_code.lower() == base_currency:
print(f"[→] Skipping {country}: same as base currency")
continue
big_mac_usd = big_mac_data[country]
ppp_amount = calculate_country_price(base_amount, base_big_mac_usd, big_mac_usd)
price_data = {
"unit_amount": ppp_amount,
"currency": iso_code.lower(),
"product": product_id,
"metadata": {
"ppp": "true",
"country": country,
"big_mac_price_usd": str(big_mac_usd),
"ppp_ratio": str(big_mac_usd / base_big_mac_usd),
},
}
if DRY_RUN:
print(f"[DRY] {country} ({iso_code}): {ppp_amount / 100:.2f} {iso_code} (Big Mac: ${big_mac_usd})")
created_prices.append(f"[SIMULATED] {country}")
else:
try:
price = stripe.Price.create(**price_data)
print(f"[✓] {country} ({iso_code}): {ppp_amount / 100:.2f} {iso_code} (ID: {price.id})")
created_prices.append(f"{country}: {price.id}")
except stripe.error.StripeError as e:
print(f"[✗] Error creating price for {country}: {e}")
continue
return created_prices
def main():
print("=" * 70)
print("STRIPE BIG MAC PRICE POINT PARITY PRICER")
print("=" * 70)
if DRY_RUN:
print("[MODE: DRY RUN - No prices will be created]")
else:
print("[MODE: LIVE - Prices WILL be created on Stripe]")
print()
# Fetch Big Mac data
big_mac_data = fetch_big_mac_index()
if not big_mac_data:
print("[✗] Cannot proceed without Big Mac data")
return
print()
# Get base price
base_price = get_product_base_price(STRIPE_PRODUCT_ID)
if not base_price:
print("[✗] Cannot proceed without base price")
return
print()
# Create PPP prices
print("Creating PPP prices...")
created = create_ppp_prices(STRIPE_PRODUCT_ID, base_price, big_mac_data)
print()
print(f"[DONE] {len(created)} prices processed")
print("=" * 70)
if DRY_RUN:
print("Ready to go live? Set DRY_RUN = False and run again.")
if __name__ == "__main__":
main()
Running It (Three Steps)
- Get your keys: Stripe API key (from Dashboard → API keys) and your product ID (Stripe → Products → click a product → ID field at the top). Paste them at the top of the script.
- Test dry-run: Keep
DRY_RUN = True, runpython main.py. You’ll see exactly what prices it would create. No charges to Stripe, no changes. - Go live: If the output looks right, change
DRY_RUN = Falseand run again. Prices appear in your Stripe dashboard tagged withmetadata: {ppp: "true"}for tracking.
What happens next: When a customer from Argentina hits your checkout from an `.ar` IP address, Stripe’s geo-detection shows them the Argentina price. Same for every other country in the list. You can disable prices later (one at a time, manually), but they’ll remain in your price history.
Why This Matters
This isn’t about charity. It’s about market density. A $49 template might convert 2% of US visitors. The same template at $18 in Argentina might convert 18% of Argentine visitors. You get more revenue, they get a fair price. The magic part is: it’s completely automatic and invisible to them.
For digital products with near-zero marginal cost—PDFs, courses, code snippets, templates—PPP pricing is economically sensible. It’s also quietly powerful: it means your reach extends beyond wealthy countries. It means a researcher in Lagos or a student in Manila isn’t priced out by currency accident.
Activists and NGOs have known this for decades (see: Oxfam, Médecins Sans Frontières, Amnesty—they all use tiered pricing). Now it’s available to indie developers for a 30-minute setup and zero ongoing cost.
The Limitations of This Price Point Parity Script (And Why They Matter)
- It’s a batch script, not a live service. You run it once per product. If Big Mac prices shift globally, you manually re-run it. The Economist updates quarterly.
- Prices accumulate in Stripe. Each run creates new prices. You can’t delete them, only disable them. This is Stripe’s API design, not a flaw in the script. Plan accordingly if you’re running this on multiple products.
- VPN detection is imperfect. Stripe uses IP-based geo-detection. A user on a UK VPN from Singapore might see the wrong price. This is rare enough that it’s not a material problem, but it exists.
- Requires a Stripe account. You need API access. It’s free, but you need the permissions.
None of these are showstoppers. They’re just… reality. Good tools don’t hide their constraints; they acknowledge them.
Next Steps
The repo is here: github.com/HomingHamster/StripeProductPPP. Clone it, read the README, run it locally or in your CI/CD if you want to keep prices in sync.
Remember: be fair. PPP pricing only works if it’s genuine. Don’t use it to squeeze wealthy markets—charge them what your work is worth. Use it to reach markets that are currently priced out. That’s the magic.
Similar posts on systems that work invisibly but ethically: check the recommendations below. That’s Stripe PPP wound up :).

