SubSovereign für React (Web) — Integrationsanleitung
Dieser Leitfaden behandelt @subsovereign/react (sdk-react/) — die Paywall-UI-Schicht für React-Web-Apps. Er rendert die Paywall, die Sie im SubSovereign-Dashboard entwerfen, als echte React-Komponenten, und zwar mit demselben Renderer, den auch die Dashboard-Vorschau nutzt. Was Sie im Dashboard freigeben, ist also genau das, was ausgeliefert wird.
Dieses SDK zeichnet die Paywall; es kümmert sich nicht um Abrechnung oder Berechtigungen. Kombinieren Sie es mit dem Web/JS-Daten-SDK (@subsovereign/js-sdk) für checkEntitlements() und Kaufvalidierung — die beiden sind aufeinander abgestimmt.
Vorbereitung
Sie benötigen einen laufenden SubSovereign-Server, eine im Dashboard registrierte App (mit einer appId und einem SDK-Rollen-API-Key) sowie eine veröffentlichte Paywall (Dashboard → Paywall → Veröffentlichen).
Schritt 1 — Installation
Das Paket liegt in sdk-react/ und ist noch nicht auf npm verfügbar — fügen Sie es als Pfad- oder Git-Abhängigkeit hinzu (oder kopieren Sie den Ordner in Ihr Projekt):
npm install ./sdk-react # path dependency while it's pre-npm
import { Paywall, usePaywallConfig } from '@subsovereign/react';
Schritt 2 — Veröffentlichte Paywall laden
usePaywallConfig holt die Konfiguration für diese App/Benutzerin. Die A/B-Variante wird serverseitig über userId ausgewählt, sodass dieselbe Benutzerin immer dieselbe Paywall sieht.
const { config, loading, error } = usePaywallConfig({
apiUrl: 'https://subs.yourdomain.com/api/v1', // YOUR self-hosted server
appId: 'your-app-id',
userId: currentUser.id, // your own stable user id
apiKey: 'YOUR_SDK_KEY',
locale: 'en', // optional, default 'en'
platform: 'web', // optional, default 'web'
});
Übergeben Sie stattdessen null, um das Laden zu überspringen (z. B. während die Benutzerin nicht angemeldet ist).
Schritt 3 — Rendern
<Paywall
config={config}
loading={loading}
loadingState={<Spinner />} // optional
emptyState={<FallbackPaywall />} // optional — shown when no config is published
onSelectProduct={(productId) => startCheckout(productId)}
/>
onSelectProduct wird ausgelöst, wenn die Benutzerin ein Produkt auswählt — leiten Sie es an Ihren Checkout (Stripe im Web) weiter. Nach einem erfolgreichen Checkout validieren Sie mit dem Daten-SDK und prüfen die Berechtigungen erneut:
await SubSovereign.validateStripeSubscription({ subscriptionId, productId, accessLevelId: 'pro' });
const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) unlockProFeatures();
Falls Sie bereits eine Konfiguration haben (über das Daten-SDK abgerufen), überspringen Sie den Hook und übergeben Sie sie direkt. Für volle Kontrolle gibt es den Raw-Renderer: <PaywallRenderer config={config} onSelectProduct={…} />.
EU-Rücktritts-Button (Compliance Passport)
Verkaufen Sie Abonnements an EU-Verbraucherinnen online, verlangt die Richtlinie (EU) 2023/2673 einen klar gekennzeichneten Rücktritt. Das SDK liefert ihn fertig mit:
import { WithdrawalButton, useWithdrawalConfig } from '@subsovereign/react';
function CancelSubscription({ user, sub }: { user: { id: string; locale: string }; sub: { id: string } }) {
// Fetches the withdrawal settings AND the notice's wording in the customer's language.
const { config, strings, error } = useWithdrawalConfig({
apiUrl: 'https://subs.yourdomain.com/api/v1',
appId: 'your-app-id',
apiKey: 'YOUR_SDK_KEY',
locale: user.locale, // the CUSTOMER's language, not your console's
});
// Log it: a silent failure here is how a tenant ships English to German customers and never finds
// out. The customer is never shown this — they get the button, in English.
if (error) console.warn('SubSovereign: withdrawal settings unavailable', error);
if (config && config.enabled === false) return null; // the tenant turned it off
return (
<WithdrawalButton
apiUrl="https://subs.yourdomain.com/api/v1"
appId="your-app-id"
apiKey="YOUR_SDK_KEY"
userId={user.id}
subscriptionId={sub.id}
strings={strings} // ← without this the dialog is ENGLISH for every customer
locale={user.locale} // ← and without this the DATE is formatted for the device
labelKey={config?.labelKey} // ← the label the tenant chose in the console
appearance="auto"
/>
);
}
Sie können die Formulierung nicht ändern. Die Konsole bietet zwei Beschriftungen für die Rücktrittsfunktion an — „Hier vom Vertrag zurücktreten“ und „Hier kündigen“ — und labelKey übernimmt diejenige, die der Mandant gewählt hat; die Worte selbst stammen vom Server in der Sprache der Kundin. Es gibt keine Möglichkeit, eigenen Text zu übergeben. Eine label-Prop zur freien Texteingabe wird ignoriert und löst eine Konsolenwarnung aus: Ein gesetzlich vorgeschriebener Hinweis, der umformuliert werden kann, wäre auch einer, der in Marketing umgedeutet werden könnte — aus demselben Grund, warum Sie auch keine Farbe übergeben können.
🚩 Übergeben Sie auch locale. Es formatiert den Zeitstempel auf der Bestätigung. Ohne diese Angabe wird das Datum für das Gerät formatiert, sodass eine deutsche Kundin auf einem amerikanischen Browser 9/3/2026 angezeigt bekommt — was sie als 9. März liest, nicht als 3. September. Es handelt sich um das Datum einer rechtlichen Handlung, und die Mehrdeutigkeit wirkt in beide Richtungen.
🚩 Übergeben Sie strings, sonst erscheint der gesetzliche Hinweis für alle auf Englisch. Die Worte werden von Ihrem SubSovereign-Server in der gewünschten Sprache ausgeliefert — absichtlich nicht von Ihnen, damit ein rechtlicher Hinweis nicht in Marketing umgedeutet werden kann. Der Button rendert, was er erhält. Er holt sie nicht selbst, weil derselbe Komponentenvertrag auch für Roku gilt, wo eine UI-Komponente keine Netzwerkanfragen stellen kann. useWithdrawalConfig ist die eine Zeile, die die beiden verbindet.
Falls das Laden fehlschlägt, erscheint der Button trotzdem — auf Englisch, nicht gar nicht. Ihr Verstoß wäre es, der Verbraucherin keine auffindbare Rücktrittsfunktion anzubieten; die falsche Sprache ist es nicht. Der Hook gibt error zurück, damit Sie das protokollieren können; zeigen Sie es der Kundin niemals an.
Aussehen — light, dark oder auto (Standard), und sonst nichts. Der Dialog malt seine eigene Karte und seinen eigenen Text, sodass er auf jeder Seite – hell oder dunkel – lesbar ist; auto folgt der Browsereinstellung der Besucherin, und wo keine Präferenz erkannt wird, wird dunkel gewählt. Absichtlich gibt es keine Möglichkeit, eine Farbe zu übergeben: Es handelt sich um einen gesetzlich vorgeschriebenen Hinweis, und sowohl seine Formulierung als auch seine Farben sind festgelegt, damit er für jede Kundin jedes Mandanten gleich lesbar ist. Wenn Sie die Regel an anderer Stelle in Ihrer UI nachbilden möchten, ist resolveAppearance(appearance, scheme) exportiert (scheme ist 'light' | 'dark' | null).
Der Button zeigt den prominent beschrifteten Button, bestätigt einmal, sendet idempotent (ein Netzwerk-Retry kann niemals zwei Rücktritte erzeugen) und zeigt die Bestätigung an. Der Button selbst führt außer dem Senden keine Netzwerkanfragen durch, sodass Sie selbst anhand von config.enabled und config.jurisdictions entscheiden müssen, wie oben beschrieben. Niedrigere Ebenen (fetchWithdrawalConfig, useWithdrawal, submitWithdrawal) sind für benutzerdefinierte UIs exportiert.
Schnellreferenz
| Sie möchten… | Verwenden Sie |
|---|---|
| Veröffentlichte Paywall laden | usePaywallConfig(params) → { config, loading, error } |
| Sie rendern | <Paywall config onSelectProduct … /> |
| Volle Kontrolle über das Rendern | <PaywallRenderer config onSelectProduct /> |
| EU-Rücktritt in der Sprache der Kundin | useWithdrawalConfig({…, locale}) → übergeben Sie strings, locale und labelKey an <WithdrawalButton> |
| Berechtigungen / Validierung | das Web & React-Native-Leitfaden |
Nächste Schritte
- Datenebene (Berechtigungen, Käufe, DSGVO): Web & React-Native-Leitfaden.
- Framework-agnostische Seiten (Vue/Svelte/Plain HTML): Web-Komponenten-Leitfaden.
- Neue Konzepte? Lesen Sie Wie SubSovereign funktioniert.