Parity Pricing (oft basierend auf Kaufkraftparität / PPP) ist eine der einfachsten Möglichkeiten, Ihr Produkt weltweit erschwinglich zu machen, ohne Ihren Listenpreis dauerhaft zu senken. Die Umsetzung ist ebenfalls unkompliziert, wenn Sie bereits Folgendes haben:
Hochwertige Starter-Kits mit integriertem Authentifizierungsfluss (Auth.js), Objekt-Uploads (AWS, Clouflare R2, Firebase Storage, Supabase Storage), integrierten Zahlungen (Stripe, LemonSqueezy), E-Mail-Verifizierungsablauf (Resend, Postmark, Sendgrid) und viel mehr . Kompatibel mit jeder Datenbank (Redis, Postgres, MongoDB, SQLite, Firestore).
Get all 3 kits Bundle ↗- Next.js Starter Kit
- SvelteKit Starter Kit
- Astro Starter Kit
One-time license · Lifetime updates
- Einen Zahlungsanbieter, der Rabattcodes unterstützt (Polar tut das)
- Eine Möglichkeit, das Land eines Besuchers serverseitig zu erkennen (Astro-API-Routen auf Vercel machen das einfach)
- Ein klares Set an Rabattstufen, die Sie anbieten möchten
Dieses Tutorial führt durch ein produktionsreifes Parity-System mit Polar + Astro:
- Land serverseitig erkennen
- Land → Stufe zuordnen (z. B. 75 % / 65 % / 55 % …)
- JSON-Antwort mit Angebot zurückgeben, die
percentOffund optional einen Polar-Rabattcode enthält - Ein kleines Banner auf der Marketing-Website rendern und/oder den Rabatt beim Checkout anwenden
Inhaltsverzeichnis
- Schritt 1: Parity-Stufen definieren (Land → Rabattstufe)
- Schritt 2: Land des Besuchers auf dem Server erkennen
- Schritt 3: Parity-Rabatte in Polar erstellen (manuell oder per API)
- Schritt 4: Entweder „Prozent Rabatt“ oder „Gutscheincode“ über eine Astro-Server-Route zurückgeben
- Schritt 5: Parity-Banner in Astro rendern (clientseitig)
- Schutzmaßnahmen gegen Missbrauch
Voraussetzungen
Sie benötigen:
- Node.js 20 oder höher
- Ein Polar-Konto mit mindestens einem Produkt
- Astro im Server-Modus (
output: 'server'), damit API-Routen zur Laufzeit ausgeführt werden - (Empfohlen) Vercel-Deployment, wenn Sie integrierte Request-Geolokalisierung über Header nutzen möchten
Architekturüberblick
1. Browser (marketing site) → GET /api/parity-offer?product=astro (optional product parameter) → Receives JSON: country, percentOff, eligible, optional coupon/discount code
2. Astro API route (server) → Resolves visitor country from request metadata (e.g. Vercel geolocation) → Looks up PPP tier for that country → Returns offer JSON for the UI + checkout flow
3. Polar (payments) → Discount codes exist per tier (or per product, depending on your strategy) → Checkout applies the code (either prefilled or user-entered)Die zentrale Designentscheidung lautet: Der Browser darf den Rabatt niemals selbst festlegen. Die Server-Route sollte das Angebot berechnen, weil der Server Zugriff auf vertrauenswürdige Request-Metadaten hat und Schutzmaßnahmen durchsetzen kann.
Schritt 1: Parity-Stufen definieren (Land → Rabattstufe)
Beginnen Sie damit, die Stufen festzulegen, die Sie anbieten möchten. Ein pragmatischer Ansatz ist, eine Handvoll Prozentstufen (10 %, 15 %, 25 %, 35 %, 45 %, 55 %, 65 %, 75 %) zu verwenden und Länder jeweils einer Stufe zuzuordnen.
In Ihrer eigenen Astro-Anwendung fügen Sie eine Datei src/lib/parity.ts hinzu, in der jede Stufe Folgendes enthält:
pppRange: rein informativ (nützlich für Docs/Admin-Oberflächen)percentOff: der zu kommunizierende RabattcouponCode: ein einzelner Code, den alle Länder in dieser Stufe teilencountries: die ISO-3166-1-alpha-2-Codes, die zu dieser Stufe gehören
Ihre Kerntypen können so aussehen:
export type ParityTierMeta = { pppRange: string percentOff: number couponCode: string}
export type ParityOffer = { country: string countryName: string product: string percentOff: number eligible: boolean couponCode?: string pppRange?: string}Erstellen Sie anschließend einmal beim Modul-Init eine schnelle Lookup-Map:
function buildCountryParityMap(): Record<string, { percentOff: number; couponCode: string; pppRange: string }> { const map: Record<string, { percentOff: number; couponCode: string; pppRange: string }> = {} for (const tier of PARITY_TIERS) { for (const cc of tier.countries) { map[cc] = { percentOff: tier.percentOff, couponCode: tier.couponCode, pppRange: tier.pppRange } } } return map}Stellen Sie schließlich einen kleinen Helper bereit, der ein einzelnes Angebot zurückgibt:
export function getParityOffer({ country, product }: { country: string; product: string }): ParityOffer { const upper = country.toUpperCase() const rule = COUNTRY_PARITY[upper] const percentOff = rule?.percentOff ?? 0
return { country: upper, countryName: new Intl.DisplayNames(['en'], { type: 'region' }).of(upper) ?? upper, product, percentOff, eligible: percentOff > 0, ...(rule?.couponCode ? { couponCode: rule.couponCode } : {}), ...(rule?.pppRange ? { pppRange: rule.pppRange } : {}), }}Auswahl einer Mapping-Quelle
Sie haben mehrere Optionen:
- Hardcodierte Stufen (wie in diesem Beispiel): am einfachsten, keine externen Abhängigkeiten, leicht nachvollziehbar.
- Datenbankgestützte Stufen: sinnvoll, wenn Sie eine Admin-Oberfläche brauchen oder Zuordnungen ohne Redeploy aktualisieren möchten.
- Dynamische PPP-Indizes: möglich, aber selten die Komplexität wert, es sei denn, Ihr Geschäft hängt davon ab.
Starten Sie mit hardcodierten Stufen — Sie können später jederzeit weiterentwickeln.
Schritt 2: Land des Besuchers auf dem Server erkennen
Sie benötigen einen Ländercode für Parity Pricing. Auf Vercel können Sie ihn aus Geolokalisierungs-Metadaten des Requests ableiten.
Die API-Route in diesem Repository nutzt geolocation() aus @vercel/functions innerhalb einer Astro-APIRoute:
import { geolocation } from '@vercel/functions'import type { APIRoute } from 'astro'import { getParityOffer } from '../../lib/parity'
export const GET: APIRoute = async ({ request, url }) => { const product = url.searchParams.get('product') || 'default' const geo = geolocation(request) const country = geo.country || 'US' const offer = getParityOffer({ country, product }) return new Response(JSON.stringify(offer), { headers: { 'content-type': 'application/json' }, })}Wenn Sie woanders deployen (oder mehr Kontrolle wünschen), können Sie auch Provider-Header nutzen (z. B. x-vercel-ip-country) oder eine serverseitige IP-zu-Land-Abfrage. Entscheidend ist, dass dies serverseitig passiert und vom Browser nicht trivial gefälscht werden kann.
Schritt 3: Parity-Rabatte in Polar erstellen (manuell oder per API)
Ihre Parity-Stufen referenzieren Codes wie DRRBQY5P. Diese Codes müssen in Polar als Rabatte/Promotions existieren, damit der Checkout sie anwenden kann.
Sie können sie auf zwei Wegen erstellen:
- Dashboard (manuell): Pro Stufe einen Rabattcode anlegen (empfohlen zum Start). Halten Sie den Code kurz, stabil und wiederverwendbar.
- Polar API (automatisiert): Rabatte programmatisch erstellen (und aktualisieren) über https://polar.sh/docs/api-reference/discounts/create, sodass Ihre Stufen-Tabelle die Source of Truth ist.
Strategie: ein Code pro Stufe vs. ein Code pro Land
- Ein Code pro Stufe: am einfachsten zu verwalten, das nutzen die meisten Teams.
- Ein Code pro Land: feine Kontrolle, aber hoher operativer Aufwand.
In den meisten Parity-Systemen ist stufenbasiert der Sweet Spot.
Rabatterstellung automatisieren (Überblick)
Polar stellt APIs zur Verwaltung von Commerce-Entitäten bereit. Die genauen Endpoint-Namen können sich ändern, die Architektur bleibt gleich:
- Halten Sie eine Stufen-Definitionsliste im Code (
PARITY_TIERS) - Fügen Sie eine interne Admin-Route oder ein Einmal-Skript hinzu, das:
- Bestehende Rabatte aus Polar auflistet
- Fehlende Rabatte pro Stufe erstellt
- Sicherstellt, dass
percentOffjeder Stufe Ihren Erwartungen entspricht
- Speichern Sie die resultierenden Rabatt-IDs/Codes zurück in Ihrer Stufen-Map (oder halten Sie Codes stabil, sodass kein Zurückschreiben nötig ist)
Wenn die Website einen Rabattcode zurückgeben soll, muss der Code nur in Polar existieren. Wenn die Website einen Rabattprozentsatz zurückgeben soll, können Sie ihn in der UI anzeigen, auch wenn der Code manuell beim Checkout eingegeben wird.
Schritt 4: Entweder „Prozent Rabatt“ oder „Gutscheincode“ über eine Astro-Server-Route zurückgeben
Ihre API-Antwort sollte beide Anwendungsfälle abdecken:
- Marketing-UI: „(X) % Rabatt für Kunden in (Country)“ anzeigen + optional „Code ABCD verwenden“
- Checkout: Code automatisch anwenden (wenn Ihr Checkout Prefill unterstützt) oder zumindest prominent anzeigen
Dieses Repository gibt sowohl percentOff als auch (bei Berechtigung) couponCode von /api/parity-offer zurück.
Eine kleine, aber wichtige Verbesserung für Production ist Caching:
- Geolokalisierungsbasierte Angebote brauchen keine millisekundengenaue Aktualität.
- JSON kurz am Edge cachen (z. B. 1 h–24 h), um Serverarbeit zu reduzieren.
Zum Beispiel:
return new Response(JSON.stringify(offer), { headers: { 'content-type': 'application/json', // Cache on the CDN; always revalidate on the server when not cached. 'cache-control': 'max-age=0, s-maxage=86400', },})Schritt 5: Parity-Banner in Astro rendern (clientseitig)
Sobald Sie /api/parity-offer haben, können Sie ein kleines Banner hinzufügen, das den regionalen Rabatt anzeigt.
Eine Komponente wie src/components/ParityBanner.astro kann ein minimales Client-Skript nutzen:
- Ruft
/api/parity-offerab - Prüft
eligibleundpercentOff - Baut einen kurzen Satz und hängt optional den Code an, falls vorhanden
<div id="parity-banner" class="hidden w-full border-b py-2.5 text-center" role="status" aria-live="polite"> <div class="mx-auto flex max-w-7xl flex-wrap items-center justify-center gap-x-2 gap-y-1 px-4 text-sm leading-snug"> <span id="parity-flag" class="shrink-0 text-lg leading-none" aria-hidden="true"></span> <p id="parity-text" class="font-sans"></p> </div></div>
<script> function countryCodeToFlagEmoji(code) { const upper = String(code).toUpperCase() if (upper.length !== 2 || !/^[A-Z]{2}$/.test(upper)) return '' return String.fromCodePoint(...[...upper].map((c) => 127397 + c.charCodeAt(0))) }
const banner = document.getElementById('parity-banner') const flagEl = document.getElementById('parity-flag') const textEl = document.getElementById('parity-text') if (!banner || !flagEl || !textEl) { /* skip */ } else { fetch('/api/parity-offer') .then((r) => r.json()) .then((data) => { if (!data || !data.eligible || !data.percentOff || data.percentOff <= 0) return flagEl.textContent = countryCodeToFlagEmoji(data.country ?? '')
const pct = data.percentOff const place = data.countryName || data.country || '' const parts = [] parts.push(`<strong class="font-bold">${pct}%</strong>`) parts.push(` discount for customers in `) parts.push(`<strong class="font-bold">${place}</strong>!`) if (data.couponCode) { parts.push(` Use code `) parts.push(`<strong class="font-bold">${data.couponCode}</strong>`) } textEl.innerHTML = parts.join('') banner.classList.remove('hidden') }) .catch(() => {}) }</script>Schutzmaßnahmen gegen Missbrauch
Parity Pricing ist ein Rabattsystem — Sie brauchen daher grundlegende Schutzmaßnahmen:
- Nur-Server-Entscheidung: Stufe niemals im Browser berechnen.
- Begrenzen und validieren: Nur Codes zurückgeben, die in Ihrer Stufen-Tabelle existieren.
- Produkt-Scoping: Wenn manche Produkte keine Parity-Rabatte haben sollen, für diese
eligible: falsezurückgeben.
Wenn Sie stärkere Durchsetzung brauchen (z. B. um das Teilen eines High-Tier-Codes zu verhindern), erwägen Sie kurzlebige, benutzerspezifische Rabattmechanismen statt geteilter Codes. Das ist komplexer, aber der nächste Schritt, wenn Parity ein wesentlicher Umsatzhebel wird.
Abschluss
Parity Pricing braucht beim Start Ihres SaaS keinen großen Implementierungsaufwand. Mit Astro, Vercel und Polar können Sie es so umsetzen:
- Eine deterministische Stufen-Map (Land → Prozent + Code)
- Eine einzelne API-Route, die das Land serverseitig auflöst und ein Angebots-JSON zurückgibt
- Eine kleine UI-Oberfläche, die den Rabatt klar kommuniziert
Von dort aus können Sie die Rabatterstellung per Polar API automatisieren, produktspezifische Berechtigungsregeln hinzufügen und die Durchsetzung verschärfen, wenn Ihr Volumen wächst.