TL;DR: Expanding a SaaS product into global markets requires more than translation — it demands infrastructure changes (edge deployment for low latency), compliance adaptation (GDPR, PIPL, CCPA), payment localization (Alipay, SEPA, Stripe), and cultural UX adjustments. This guide breaks down the technical and business preparation needed for the three largest SaaS markets: the US, Europe, and China. Each section includes actionable code examples, configuration snippets, and deployment patterns you can implement immediately.
Why Globalization Must Be Built, Not Bolted On
The biggest mistake SaaS founders make with globalization is treating it as a phase-two feature. Retrofitting i18n, multi-currency pricing, and regional compliance onto a monolithic codebase typically costs 3-5x more than building it in from the start — and often requires a full rewrite of the database schema, routing layer, and deployment pipeline.
The three largest SaaS markets have fundamentally different requirements:
| Requirement | US Market | European Market | Chinese Market |
|---|---|---|---|
| Language | English | Multi (DE, FR, ES, etc.) | Chinese (Simplified) |
| Data regulation | CCPA/State laws | GDPR (strictest) | PIPL + CSL |
| Payment methods | Credit cards, Stripe | SEPA, PayPal, credit cards | Alipay, WeChat Pay, UnionPay |
| Infrastructure | AWS/US-East | GDPR-compliant hosting | ICP license, China-hosted |
| Authentication | Google, GitHub | EU-specific (eIDAS) | WeChat, Alipay, phone SMS |
| Pricing display | $ (tax excl.) | € (VAT incl.) | ¥ (tax incl.) |
| Content delivery | Global CDN | Edge (300ms latency target) | China CDN (ICP + DDoS shield) |
| Social login | Google, Apple, GitHub | Google, Apple, LinkedIn | WeChat, Alipay, phone OTP |
| Email deliverability | SendGrid, AWS SES | SendGrid (DPA signed) | QQ Mail, Alibaba Direct Mail |
Market 1: European Market Preparation
GDPR Compliance Checklist
GDPR applies to any SaaS processing data of EU residents — regardless of where your company is incorporated. Here is the technical implementation:
// src/lib/gdpr.ts
// GDPR-compliant data handling utilities
// 1. Explicit consent tracking
interface ConsentRecord {
userId: string
consentType: "analytics" | "marketing" | "functional" | "third_party"
granted: boolean
timestamp: number
ipAddress: string // Anonymized
}
export async function recordConsent(
userId: string,
consentType: ConsentRecord["consentType"],
granted: boolean
) {
await env.DB.prepare(
`INSERT INTO consent_records (user_id, consent_type, granted, timestamp, ip_address)
VALUES (?, ?, ?, unixepoch(), ?)`
).bind(
userId,
consentType,
granted ? 1 : 0,
anonymizeIp(getClientIp())
).run()
}
// 2. Data portability export
export const exportUserData = createServerFn({ method: "GET" }).handler(
async (_, { request }) => {
const userId = await getUserId(request)
const [profile, subscriptions, invoices, events] = await Promise.all([
env.DB.prepare("SELECT * FROM users WHERE id = ?").bind(userId).first(),
env.DB.prepare("SELECT * FROM subscriptions WHERE user_id = ?").bind(userId).all(),
env.DB.prepare("SELECT * FROM invoices WHERE user_id = ?").bind(userId).all(),
env.DB.prepare("SELECT * FROM analytics_events WHERE user_id = ?").bind(userId).all(),
])
return Response.json({
exportedAt: new Date().toISOString(),
data: { profile, subscriptions, invoices, events },
})
}
)
// 3. Right to erasure (GDPR Article 17)
export const deleteUserData = createServerFn({ method: "POST" }).handler(
async (_, { request }) => {
const userId = await getUserId(request)
// Anonymize personal data (keep transactional records for legal retention)
await env.DB.batch([
env.DB.prepare(`UPDATE users SET
email = 'deleted-' || id || '@redacted.com',
name = 'Deleted User',
avatar_url = NULL,
deleted_at = unixepoch()
WHERE id = ?`).bind(userId),
env.DB.prepare("DELETE FROM analytics_events WHERE user_id = ?").bind(userId),
env.DB.prepare("DELETE FROM session_tokens WHERE user_id = ?").bind(userId),
])
return { success: true }
}
)
EU Data Residency
GDPR requires that EU user data stays within the EU or in countries with adequate protection. With Cloudflare Workers, use data localization:
# wrangler.jsonc
{
"name": "tanstack-ship",
"compatibility_date": "2026-06-01",
"workers_dev": false,
"routes": [
{ "pattern": "tanstackship.com", "zone_id": "YOUR_ZONE_ID" },
{ "pattern": "eu.tanstackship.com", "zone_id": "YOUR_ZONE_ID", "custom_domain": true }
],
"d1_databases": [
{ "binding": "DB", "database_id": "GLOBAL_DB", "database_name": "tanstack-ship" },
{ "binding": "EU_DB", "database_id": "EU_DB", "database_name": "tanstack-ship-eu" }
]
}
// Route EU users to EU D1 instance
async function getDb(request: Request) {
const country = request.cf?.country
if (country && EU_COUNTRIES.has(country)) {
return env.EU_DB // GDPR-compliant D1 instance
}
return env.DB
}
EU Payment: SEPA Direct Debit
SEPA (Single Euro Payments Area) Direct Debit is the dominant recurring payment method for EU-based SaaS subscriptions. Stripe handles SEPA Direct Debit through its standard Payment Methods API, allowing you to collect payments in euros across 36 SEPA countries without needing separate contracts per country:
// With Stripe, SEPA is handled via Payment Methods
const paymentIntent = await stripe.paymentIntents.create({
amount: 2999, // €29.99
currency: "eur",
payment_method_types: ["sepa_debit", "card"],
customer: customerId,
})
Key EU-specific pricing considerations:
- Display prices including VAT (unlike the US)
- Register for VAT MOSS to handle cross-border EU sales
- Issue VAT-compliant invoices (required by law for B2B)
- SEPA transfers can take 1-3 business days — do not grant access until payment clears
Market 2: Chinese Market Preparation
Entering China is the most technically demanding market expansion. Here is what you need:
ICP License (Required for Any Hosted Service)
Any website or app hosted on servers in mainland China or using a Chinese CDN must have an ICP (Internet Content Provider) license. The process takes 4-8 weeks and requires:
- Registered Chinese company (WFOE or joint venture) or partnership with a Chinese ICP-licensed entity
- ICP filing submission through your cloud provider (Alibaba Cloud, Tencent Cloud, AWS China)
- Domain name already ICP-filed
Without an ICP license, your site will be blocked by the Great Firewall of China (GFW).
Infrastructure: Bypassing the Great Firewall
// src/lib/geo-routing.ts
// Route Chinese users to China-hosted instances
const CHINA_REGIONS = new Set(["CN", "HK", "MO"])
export async function getRegionalEndpoint(request: Request): Promise<string> {
const country = request.cf?.country
if (CHINA_REGIONS.has(country ?? "")) {
// Route to China-hosted instance via Cloudflare China Network
return "https://tanstack-ship.cn"
}
// Global instance
return "https://tanstackship.com"
}
Cloudflare China Network provides a GFW-compliant CDN layer without requiring your own Chinese servers. All major Chinese cloud providers also offer GPU/CPU instances:
- Alibaba Cloud (aliyun.com) — largest market share
- Tencent Cloud — second largest, WeChat integration
- AWS China (Beijing/Ningxia) — requires separate account
Chinese Payment Integration
Chinese users expect local payment methods — Alipay and WeChat Pay are non-negotiable for any SaaS targeting the China market. You can integrate these either through Stripe's global payment API for simplicity, or use the Alipay SDK directly for lower transaction fees:
// src/lib/payment/china.ts
// Alipay integration via Stripe or direct API
// Option 1: Stripe (simplest, higher fees)
const paymentIntent = await stripe.paymentIntents.create({
amount: 19900, // ¥199.00
currency: "cny",
payment_method_types: ["alipay", "card"],
payment_method_options: {
alipay: {},
},
})
// Option 2: Direct Alipay API (lower fees, more setup)
import AlipaySdk from "alipay-sdk"
const alipaySdk = new AlipaySdk({
appId: process.env.ALIPAY_APP_ID,
privateKey: process.env.ALIPAY_PRIVATE_KEY,
})
const result = await alipaySdk.exec("alipay.trade.create", {
bizContent: {
out_trade_no: orderId,
total_amount: "199.00",
subject: "TanStack Ship - Pro Plan",
product_code: "FAST_INSTANT_TRADE_PAY",
},
})
Chinese Social Login
WeChat OAuth is the primary social login mechanism for Chinese users, analogous to Google Sign-In in Western markets. The flow follows the standard authorization code grant pattern but uses WeChat's Open Platform endpoints:
// src/lib/auth/china.ts
// WeChat OAuth
// Step 1: Redirect user to WeChat authorization
export function getWeChatAuthUrl(redirectUri: string): string {
const params = new URLSearchParams({
appid: process.env.WECHAT_APP_ID,
redirect_uri: redirectUri,
response_type: "code",
scope: "snsapi_login",
state: crypto.randomUUID(),
})
return `https://open.weixin.qq.com/connect/qrconnect?${params}`
}
// Step 2: Exchange code for access token
export async function getWeChatToken(code: string) {
const response = await fetch(
`https://api.weixin.qq.com/sns/oauth2/access_token?` +
new URLSearchParams({
appid: process.env.WECHAT_APP_ID,
secret: process.env.WECHAT_APP_SECRET,
code,
grant_type: "authorization_code",
})
)
return response.json() as Promise<{
access_token: string
openid: string
unionid: string
}>
}
Chinese Content Delivery Considerations
- Censored keywords: Your content will be scanned. Common SaaS-blocked terms include sensitive political topics, VPN references, and cryptocurrency mentions
- WeChat ecosystem: WeChat Mini Programs, WeChat Pay, and WeChat Official Accounts are essential for B2C SaaS
- Email deliverability: QQ Mail and 163.com are the dominant email providers — ensure your SPF, DKIM, and DMARC are configured for Chinese domains
- Domain blocking: Some domains are blocked without clear reason. Register a
.cndomain as backup
Market 3: US Market Preparation
The US market is the most straightforward but still requires specific attention:
Tax Compliance: Sales Tax by State
US sales tax varies by state, and economic nexus laws require you to collect tax once you exceed certain revenue or transaction thresholds in each state. Here is a simplified tax calculation utility that maps state codes to their base rates:
// src/lib/tax/us-sales-tax.ts
// Simplified sales tax calculation (use a service like TaxJar for production)
const STATE_TAX_RATES: Record<string, number> = {
"CA": 0.0725, // California base rate
"NY": 0.04, // New York state (county/city adds more)
"TX": 0.0625, // Texas
"WA": 0.065, // Washington
// ... 45+ more states
}
export function calculateSalesTax(
amount: number,
state: string
): { taxRate: number; taxAmount: number; total: number } {
const taxRate = STATE_TAX_RATES[state.toUpperCase()] ?? 0
const taxAmount = Math.round(amount * taxRate * 100) / 100
return { taxRate, taxAmount, total: amount + taxAmount }
}
Key considerations:
- Economic nexus: If you sell >$100K or 200+ transactions in a state, you must collect sales tax
- Use a service like TaxJar, Stripe Tax, or Anrok for automated calculation
- Display prices excluding tax (unlike Europe)
US Privacy Compliance (CCPA)
The California Consumer Privacy Act (CCPA) requires SaaS businesses to provide a clear opt-out mechanism for the sale of personal information. Here is the implementation of a CCPA opt-out endpoint using TanStack Start server functions:
// src/lib/ccpa.ts
// CCPA opt-out mechanism
export async function handleCcpOptOut(userId: string) {
await env.DB.prepare(
`INSERT INTO privacy_opt_outs (user_id, regulation, opted_out_at)
VALUES (?, 'CCPA', unixepoch())`
).bind(userId).run()
}
// Do not sell my personal information endpoint
export const optOutOfSale = createServerFn({ method: "POST" }).handler(
async (_, { request }) => {
const userId = await getUserId(request)
await handleCcpOptOut(userId)
return { success: true }
}
)
Architectural Pattern: Regional Deployment with Edge Workers
For SaaS products targeting all three markets simultaneously, a Cloudflare Workers-based architecture provides the global reach you need. Our Cloudflare Workers Full-Stack SSR guide covers the fundamentals of deploying full-stack applications at the edge. Here is the regional deployment architecture:
┌─────────────────────────────────────────────────┐
│ Cloudflare │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ US Worker │ │ EU Worker │ │ CN Edge │ │
│ │ us-east │ │ eu-west │ │ (CF CN) │ │
│ └──────┬───────┘ └──────┬───────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ ┌────▼─────┐ │
│ │ US D1 DB │ │ EU D1 DB │ │ CN D1 DB │ │
│ │ (Virginia) │ │ (Frankfurt) │ │ (Beijing) │ │
│ └──────────────┘ └──────────────┘ └──────────┘ │
│ │ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ │
│ │ US R2 │ │ EU R2 │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
// src/middleware/geo-router.ts
// Edge middleware that routes to the correct regional deployment
export const geoRouter = createServerFn({ method: "GET" }).handler(
async (_, { request }) => {
const country = request.cf?.country ?? "US"
if (["CN", "HK", "MO"].includes(country)) {
return env.CN_DB
}
if (EU_COUNTRIES.has(country)) {
return env.EU_DB
}
return env.US_DB
}
)
Multi-Currency Pricing Database Schema
Supporting multiple currencies and tax regimes requires a well-designed pricing table. This schema supports region-specific pricing with different currencies, tax behaviors (inclusive vs. exclusive), and billing intervals:
CREATE TABLE price_tiers (
id TEXT PRIMARY KEY,
product_id TEXT NOT NULL REFERENCES products(id),
region TEXT NOT NULL CHECK (region IN ('US', 'EU', 'CN', 'ROW', 'GLOBAL')),
currency TEXT NOT NULL,
unit_amount INTEGER NOT NULL, -- In smallest currency unit (cents, fen, etc.)
interval TEXT NOT NULL CHECK (interval IN ('month', 'year')),
tax_behavior TEXT NOT NULL DEFAULT 'exclusive' CHECK (tax_behavior IN ('inclusive', 'exclusive')),
is_active INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
UNIQUE(product_id, region, interval)
);
CREATE INDEX idx_price_tiers_region ON price_tiers(region);
// src/lib/pricing/regional.ts
export async function getRegionalPrice(
productId: string,
region: "US" | "EU" | "CN" | "ROW",
interval: "month" | "year"
) {
const price = await env.DB.prepare(
`SELECT unit_amount, currency, tax_behavior
FROM price_tiers
WHERE product_id = ? AND region = ? AND interval = ? AND is_active = 1
ORDER BY created_at DESC
LIMIT 1`
)
.bind(productId, region, interval)
.first()
return price
}
Globalization Readiness Checklist
Before launching in a new market, verify each item:
- Content is fully translated (not just UI, but transactional emails, docs, error pages)
- Date/time/number formatting uses
Intl.*APIs (never hardcoded) - Currency symbols and formats match local expectations (€29,99 vs ¥199 vs $29.99)
- Regional payment methods are integrated and tested with sandbox credentials
- Tax calculation is automated per region (VAT, sales tax, consumption tax)
- Data residency requirements are met (GDPR EU, PIPL China, CCPA California)
- Privacy policy covers all applicable regulations (separate versions per region)
- CDN/edge routing directs users to the nearest regional deployment
- Email deliverability is configured for regional providers (QQ, 163, GMX, Gmail)
- Social login options include region-specific providers (WeChat, LINE, LinkedIn)
- Terms of Service are localized and legally reviewed per jurisdiction
- Customer support channels cover regional time zones (email, chat, phone)
- Pricing is localized to market expectations (not just currency conversion)
- ICP license is obtained for China (allow 4-8 weeks processing time)
- Cookie consent mechanism is GDPR-compliant (granular, documented)
Conclusion
Globalizing a SaaS product is a multi-dimensional challenge that touches every part of your stack — from database sharding and edge deployment to payment processing and legal compliance. The key takeaways:
- Build globalization into your architecture from day one — retrofitting regional routing, multi-currency pricing, and data residency onto a monolithic system is prohibitively expensive
- Each market has a dominant constraint: GDPR (data privacy) in Europe, ICP/GFW (infrastructure) in China, and sales tax nexus (tax complexity) in the US
- Payments are the hardest part — you need at least 3 payment providers (Stripe, Alipay/WeChat, SEPA) to cover all three markets
- Edge deployment is your friend — Cloudflare Workers' regional routing makes data residency compliance much simpler than traditional VPS-based architectures
- Test with real users in each market — localization bugs (wrong date formats, truncated text in Chinese characters, missing RTL support) only surface with native users. For a comprehensive walkthrough of building multilingual React applications, refer to our React Internationalization Complete Guide. To ensure search engines properly index your localized content, the hreflang Tags Ultimate Guide covers the essential implementation patterns for multilingual SPAs.
The companies that win at globalization are not the ones with the most features — they are the ones that make every user feel like the product was built for their market.