Stripe 가격을 방문자의 통화에 맞게 현지화하기, 25줄

발행: (2026년 5월 5일 AM 04:20 GMT+9)
11 분 소요
원문: Dev.to

Source: Dev.to


방문자의 통화에 맞게 Stripe 가격을 현지화하기 (25줄 코드)

Stripe는 기본적으로 USD와 같은 단일 통화로 가격을 설정합니다.
하지만 전 세계 사용자를 대상으로 하는 서비스라면, 사용자가 보는 가격을 그들의 현지 통화로 표시해 주는 것이 UX를 크게 향상시킵니다.

아래 예제에서는 25줄 이하의 JavaScript(또는 TypeScript) 코드만으로 방문자의 IP를 기반으로 통화를 감지하고, Stripe Checkout 세션을 해당 통화에 맞게 생성하는 방법을 보여줍니다.

주요 흐름

  1. 사용자의 IP 주소를 가져온다.
  2. IP → 국가 코드 변환 (예: geoip-lite 사용).
  3. 국가 코드를 통화 코드로 매핑한다.
  4. Stripe Checkout 세션을 해당 통화가격으로 생성한다.

구현 코드

// 1️⃣ 의존성 설치
// npm i stripe express geoip-lite dotenv

require('dotenv').config();
const express = require('express');
const Stripe = require('stripe');
const geoip = require('geoip-lite');

const app = express();
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);

// 2️⃣ 국가 → 통화 매핑 테이블 (필요에 따라 확장)
const countryToCurrency = {
  US: 'usd',
  CA: 'cad',
  GB: 'gbp',
  AU: 'aud',
  JP: 'jpy',
  KR: 'krw',
  // ... 기타 국가
};

// 3️⃣ 가격(센트) 정의 (통화별로 다르게 설정 가능)
const priceInCents = {
  usd: 500,   // $5.00
  cad: 650,   // C$6.50
  gbp: 400,   // £4.00
  aud: 700,   // A$7.00
  jpy: 550,   // ¥550
  krw: 6000,  // ₩6,000
};

// 4️⃣ 라우트: Checkout 세션 생성
app.post('/create-checkout-session', async (req, res) => {
  // 클라이언트 IP 추출 (프록시 환경에 따라 헤더 조정)
  const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.socket.remoteAddress;

  // IP → 국가 코드
  const geo = geoip.lookup(ip);
  const country = geo?.country || 'US';

  // 국가 → 통화 (디폴트는 USD)
  const currency = countryToCurrency[country] || 'usd';

  // 통화에 맞는 가격 가져오기
  const amount = priceInCents[currency] || priceInCents['usd'];

  // Stripe Checkout 세션 생성
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [{
      price_data: {
        currency,
        product_data: { name: 'Premium Subscription' },
        unit_amount: amount,
      },
      quantity: 1,
    }],
    mode: 'payment',
    success_url: `${process.env.BASE_URL}/success`,
    cancel_url: `${process.env.BASE_URL}/cancel`,
  });

  res.json({ id: session.id });
});

// 5️⃣ 서버 시작
const PORT = process.env.PORT || 4242;
app.listen(PORT, () => console.log(`🚀 Server running on port ${PORT}`));

코드 설명

라인역할
1‑2필요한 패키지를 불러오고 환경 변수를 로드합니다.
8‑15countryToCurrency 객체에 국가‑통화 매핑을 정의합니다. 필요에 따라 더 많은 국가를 추가하세요.
18‑26priceInCents 객체에 각 통화별 가격(센트/일본엔 등) 을 지정합니다.
31‑36요청 헤더에서 실제 클라이언트 IP를 추출합니다. (프록시 사용 시 x-forwarded-for 필요)
38‑40geoip-lite 로 IP를 조회해 국가 코드를 얻고, 매핑 테이블을 통해 통화를 결정합니다.
43‑45선택된 통화에 맞는 금액을 가져옵니다. 매핑이 없으면 기본값(USD) 사용.
48‑66Stripe Checkout 세션을 생성합니다. price_data 에서 동적으로 currencyunit_amount 를 설정합니다.
71‑73서버를 지정된 포트에서 실행합니다.

배포 시 고려사항

  • IP 정확도: geoip-lite 는 무료 데이터베이스를 사용하므로 정확도가 100%는 아닙니다. 더 정밀한 서비스가 필요하면 IP2Location 혹은 MaxMind GeoIP2 와 같은 유료 API 를 검토하세요.
  • 통화 변동: 환율 변동에 따라 가격을 자동 업데이트하려면 별도의 환율 API (예: Open Exchange Rates, CurrencyLayer) 를 연동해 priceInCents 를 동적으로 계산하도록 확장할 수 있습니다.
  • 법적 요구사항: 일부 국가에서는 현지 통화 표시가 법적으로 의무일 수 있습니다. 서비스가 제공되는 국가의 규정을 반드시 확인하세요.
  • 다중 가격: 제품마다 다른 가격을 제공하려면 priceInCents제품‑통화 2차원 구조로 바꾸고, line_items 를 동적으로 구성하면 됩니다.

마무리

이 간단한 25줄 코드를 프로젝트에 삽입하기만 하면, 방문자는 자신의 현지 통화로 가격을 확인하고 결제할 수 있습니다.
Stripe가 지원하는 모든 통화에 대해 동일한 로직을 적용할 수 있으니, 필요에 따라 매핑 테이블과 가격 정보를 확장해 보세요.

Tip: 로컬 개발 환경에서는 localhost 로 접속하면 IP가 ::1 로 나오기 때문에 geoip.lookupnull 을 반환합니다. 테스트용으로 req.ip = '8.8.8.8' 과 같이 강제 지정해 두면 편리합니다.

개요

Stripe의 Price 객체는 단일 통화에 연결됩니다 (예: $79 USD).
전환율 최적화를 위해 방문자의 현지 통화(ARS, BRL, EUR, …)로 가격을 표시하면서도 백엔드에서는 정규 USD 금액을 청구할 수 있습니다.

작동 방식

  1. 정규 가격을 USD로 저장 – Stripe Price를 절대 수정하지 마세요.
  2. 서버에서 방문자의 국가를 감지합니다 (IP‑기반).
  3. 국가를 해당 현지 통화에 매핑합니다.
  4. FX API에서 실시간 USD → 현지 통화 환율을 가져옵니다.
  5. 현지화된 금액(예: “≈ AR$ 7 900”)을 USD 가격 옆에 표시합니다.
  6. 사용자가 Buy를 클릭하면 Stripe가 USD로 결제를 처리합니다; 변환은 표시 전용입니다.

이 접근 방식은 방문자에게 익숙한 숫자를 제공하면서 Stripe 회계를 단순하고 차지백에 안전하게 유지합니다.

구현

헬퍼: localizedPrice

// lib/localized-price.ts
import { headers } from 'next/headers';

interface LocalizedPrice {
  usd: number;
  display: string;
  currency: string;
  rate: number;
}

const APOGEO = 'https://api.apogeoapi.com/v1';

export async function localizedPrice(usdAmount: number): Promise {
  const ip =
    headers().get('x-forwarded-for')?.split(',')[0] ??
    headers().get('x-real-ip') ??
    '';

  if (!ip) return fallback(usdAmount, 'USD', 1);

  // 1️⃣ Detect visitor country
  const ipRes = await fetch(`${APOGEO}/ip/${ip}`, {
    headers: { 'X-API-Key': process.env.APOGEOAPI_KEY! },
    next: { revalidate: 3600 }, // 1 h
  });
  if (!ipRes.ok) return fallback(usdAmount, 'USD', 1);
  const { country } = await ipRes.json();
  const currency: string = country.currency;
  if (currency === 'USD') return fallback(usdAmount, 'USD', 1);

  // 2️⃣ Fetch live FX rate
  const fxRes = await fetch(`${APOGEO}/exchange-rates/${currency}`, {
    headers: { 'X-API-Key': process.env.APOGEOAPI_KEY! },
    next: { revalidate: 14400 }, // 4 h
  });
  if (!fxRes.ok) return fallback(usdAmount, 'USD', 1);
  const { usdRate }: { usdRate: number } = await fxRes.json();

  const localAmount = Math.round(usdAmount * usdRate);
  const display = new Intl.NumberFormat(undefined, {
    style: 'currency',
    currency,
    maximumFractionDigits: 0,
  }).format(localAmount);

  return { usd: usdAmount, display, currency, rate: usdRate };
}

function fallback(usdAmount: number, currency: string, rate: number): LocalizedPrice {
  return {
    usd: usdAmount,
    display: `$${usdAmount} ${currency}`,
    currency,
    rate,
  };
}

컴포넌트에서 헬퍼 사용

// components/PricingCard.tsx
import { localizedPrice } from '@/lib/localized-price';

export default async function PricingCard() {
  const price = await localizedPrice(79); // Stripe price in USD

  return (
    <>
      <h2>Professional Plan</h2>

      <p>$79 USD</p>

      {price.currency !== 'USD' && (
        <p>≈ {price.display} at today&apos;s rate</p>
      )}

      <button>Buy now</button>
    </>
  );
}

실용적인 팁

  • 통화별로 Stripe Price 객체를 절대 변경하지 마세요; 단일 USD 가격을 유지하고 표시 전용 로컬라이제이션을 사용하세요.
  • 적절히 반올림하세요 – 예를 들어 ARS는 유용한 센트가 없으므로 maximumFractionDigits: 0으로 소수점을 제거합니다.
  • 우아한 대체 처리 – FX API를 사용할 수 없을 경우 “$undefined” 대신 USD 금액을 표시하세요.
  • 환율을 4시간 동안 캐시 (API 갱신 주기에 맞춰)하여 과도한 요청을 방지하세요.
  • Adaptive Pricing (Stripe가 제공하는 통화별 가격)은 Stripe가 보유하고 방문자의 원래 표시 가격을 숨기는 약 2 %의 FX 스프레드를 발생시킵니다. 표시 전용 방법은 무료이며 투명하고 더 간단합니다.

선택 사항: 통화 스위처

사용자가 자동 감지를 무시하도록 하려면:

  1. 선택한 통화를 쿠키에 저장합니다.
  2. localizedPrice에 해당 값을 전달합니다 (선택적 overrideCurrency 매개변수를 추가).
  3. 같은 헬퍼가 적절한 표시 금액을 반환합니다.

비용 및 제한

  • ApogeoAPI 무료 티어: 월 1 000 요청.
  • 4시간 캐시를 사용하면 월 약 5 000 페이지 뷰를 커버합니다.
  • 여기서 키를 받으세요.

원본 게시물

Stripe Localized Pricing with FX – ApogeoAPI Blog

0 조회
Back to Blog

관련 글

더 보기 »