SubSovereign Web-Komponente — Integrationsanleitung (Vue, Svelte, Angular, reines HTML)
Diese Anleitung behandelt sdk-web/ – das framework-unabhängige Browser-SDK. Es liefert einen reinen fetch-Datenclient sowie zwei Web Components, <subsovereign-paywall> und <subsovereign-withdrawal>, die auf jeder Website funktionieren – Vue, Svelte, Angular oder einer reinen HTML-Seite – ohne Build-Schritt und ohne Abhängigkeiten. (Nutzen Sie React? Verwenden Sie stattdessen die React-Anleitung.)
Vorbereitung
Ein laufender SubSovereign-Server, eine im Dashboard registrierte App (eine appId und ein SDK-Rollen-API-Key) sowie eine veröffentlichte Paywall.
Schritt 1 — Laden und Konfigurieren
<script type="module">
import { SubSovereign } from './sdk-web/src/index.js'; // importing registers the elements
SubSovereign.configure({
apiKey: 'YOUR_SDK_KEY',
appId: 'your-app-id',
baseUrl: 'https://subs.yourdomain.com/api/v1', // YOUR self-hosted server
userId: currentUser.id, // your own stable user id
locale: 'en',
});
</script>
Schritt 2 — Zugriff prüfen
const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) showPremiumContent();
else showPaywall();
Für eine einfache Sperre gibt es hasAccess(), optional für eine bestimmte Zugriffsebene. Es fällt im Fehlerfall sicher zu (fail-closed): Bei einem Netzwerkfehler wird false zurückgegeben, sodass ein kurzer Ausfall niemals versehentlich kostenpflichtige Inhalte freischaltet.
if (await SubSovereign.hasAccess('pro')) showPremiumContent();
checkEntitlements() wirft eine Ausnahme bei Fehlern, sodass der Nutzer auf dem zuletzt bekannten Zugriff bleibt; hasAccess() wirft nie eine Ausnahme. Wählen Sie die Methode, deren Fehlerverhalten Sie benötigen.
Schritt 3 — Paywall anzeigen und verkaufen
<subsovereign-paywall id="pw"></subsovereign-paywall>
<script type="module">
const pw = document.getElementById('pw');
pw.config = await SubSovereign.getPaywallConfig(); // platform defaults to 'web'
pw.addEventListener('select-product', (e) => {
startCheckout(e.detail.productId); // wire to your checkout
});
</script>
Die Größe ist Aufgabe Ihrer Seite. Die Standardbreite beträgt 420px; erweitern Sie sie mit der CSS-Custom-Property (Custom Properties durchdringen den Shadow DOM) und/oder skalieren Sie sie gleichmäßig:
subsovereign-paywall { --ss-paywall-max-width: 900px; transform: scale(1.4); }
Gewährung nach dem Kauf: Dieses SDK enthält keinen clientseitigen validate…-Aufruf. Schließen Sie den Checkout mit Ihrem Anbieter ab, gewähren Sie die Zugriffsberechtigung serverseitig – Ihr Backend ruft Ihren SubSovereign-Server auf oder nutzt die signierte Bring-Your-Own-Billing-Brücke (POST /entitlements/external) – und prüfen Sie anschließend erneut:
const again = await SubSovereign.checkEntitlements();
if (again.hasAccess) unlock();
Feature-Flags
Funktionen serverseitig ohne Deployment aktivieren. Fällt im Fehlerfall sicher zu (fail-closed): Bei einem Netzwerkfehler erhalten Sie {}, sodass alle Flags als deaktiviert gelten.
const flags = await SubSovereign.getFeatureFlags(); // { newPlayer: true, ... }
if (flags.newPlayer) showNewPlayer();
KI-Antwort-Engine-Zuordnung (GEO)
Wenn Sie die Acquisition/GEO-Funktionen nutzen, erfassen Sie, woher Besucher stammen – der KI-Referrer existiert nur auf der Landingpage, und die Nutzer-ID existiert erst nach der Anmeldung. Daher ist es ein zweistufiger Vorgang aus Zwischenspeichern und späterem Senden:
import { ssCaptureLanding } from '@subsovereign/web';
// On every page of your marketing site, ONCE THE VISITOR HAS ACCEPTED YOUR CONSENT BANNER:
onConsentAccepted(() => ssCaptureLanding());
// …later, the moment the user signs up / signs in, after SubSovereign.configure():
await SubSovereign.recordAttributionTouch();
Das SDK speichert nichts auf dem Gerät des Besuchers, bis Sie ssCaptureLanding() aufrufen. Das Importieren des Pakets schreibt nichts. Der Zwischenspeicher (Referrer + UTM-Tags) fällt unter die DSGVO als personenbezogene Daten und unter ePrivacy als Speicherung. Wann er erfasst wird, ist daher Ihre Einwilligungsentscheidung – rufen Sie die Funktion im Akzeptanz-Handler Ihres Banners auf. Ohne Erfassung meldet recordAttributionTouch() nur, was die Anmeldeseite selbst sehen kann – UTM-Tags in der URL und einen Referrer, sofern dieser nicht Ihre eigene Website ist. Ein KI- oder Suchmaschinen-Referrer von einer früheren Landingpage wird nicht zugeordnet. Das ist der Preis für die Nicht-Erfassung – und es ist die Entscheidung des Besuchers.
recordAttributionTouch() sendet die zwischengespeicherte erste Landingpage (sie überschreibt die aktuelle Seite), löscht den Zwischenspeicher erst nach erfolgreicher Übertragung, sodass ein späterer Login erneut versucht, und wirft nie eine Ausnahme. Wenn Ihre Landingpages configure() nicht aufrufen können (eine statische Marketingseite ohne Nutzer), führt ssFlushAttribution(userId, { apiUrl, apiKey }) denselben Sendevorgang mit expliziten Anmeldedaten aus – oder setzen Sie window.SS_API_URL und window.SS_API_KEY.
Die Ursprungs-URL Ihrer Website muss in der ALLOWED_ORIGINS des Servers enthalten sein, andernfalls meldet der Browser nichts (stille Ablehnung).
Datenschutz (DSGVO und CCPA)
await SubSovereign.recordConsent({ purpose: 'analytics', granted: true });
await SubSovereign.requestErasure(); // "forget me" — GDPR Art. 17
const myData = await SubSovereign.exportMyData(); // data export — GDPR Art. 20
await SubSovereign.setDoNotSell(true); // CCPA "Do Not Sell" / GPC signal
Die drei Datenschutz-Aufrufe werfen bei Fehlern eine Ausnahme (ApiError, mit .status). Wenn ein Nutzer ein gesetzliches Recht ausübt, muss ihm mitgeteilt werden, wenn es nicht durchging – fangen Sie den Fehler ab und teilen Sie dies mit; zeigen Sie niemals einen scheinbaren Erfolg an. Rechnungsdatensätze werden vom Server gemäß DSGVO Art. 17(3)(b) aufbewahrt und anonymisiert.
EU-Rücktrittsbutton (Compliance-Pass)
<subsovereign-withdrawal subscription-id="SUB_ID" appearance="auto"></subsovereign-withdrawal>
Prominenter beschrifteter Button → einmalige Bestätigung → idempotente Übermittlung → Bestätigung, gemäß Richtlinie (EU) 2023/2673. Für benutzerdefinierte Oberflächen: SubSovereign.withdraw(subscriptionId, opts) und SubSovereign.getWithdrawalConfig().
Aussehen – light, dark oder auto (Standard), und nur diese Optionen. Der Dialog zeichnet seine eigene Karte und seinen eigenen Text, sodass er auf jeder Host-Seite lesbar ist; auto folgt der Browser-Einstellung des Besuchers (prefers-color-scheme), und das Attribut kann jederzeit geändert werden – die Karte wird neu gezeichnet. Es gibt bewusst keine Möglichkeit, eine Farbe zu übergeben: Dies ist eine gesetzliche Mitteilung, und Formulierung sowie Farben sind fest vorgegeben, sodass sie für jeden Kunden jedes Mandanten gleich lesbar sind. Die Texte stammen von Ihrem Server in der Sprache des Kunden (locale in configure()); bei einem älteren Server fallen sie auf Englisch zurück, statt leer zu bleiben.
Das Element löst withdrawal-shown, withdrawal-submitted (Details: die Quittung) und withdrawal-error (Details: { reason, status? }) für Ihre Analysen aus. Wenn Sie subscription-id vergessen, sieht der Kunde den übersetzten Fehler und Sie erhalten einen Konsolenfehler sowie ein withdrawal-error-Ereignis. Wenn das Element seine Einstellungen nicht laden kann (falscher Key, falsche App-ID, Ihr Server lehnt den Ursprung dieser Seite ab), sieht der Kunde trotzdem den Button – auf Englisch – und Sie erhalten eine console.warn mit der wahrscheinlichsten Ursache sowie ein withdrawal-error-Ereignis mit reason: 'config-unavailable' und, falls vorhanden, dem HTTP-status (ein abgelehnter Ursprung oder eine falsche URL hat keinen). Hören Sie in jeder Umgebung auf dieses Ereignis: So erfahren Sie, dass deutsche Kunden englische Texte sehen. Beachten Sie, dass es beim Laden ausgelöst wird, noch bevor der Kunde handelt – zählen Sie es nicht als fehlgeschlagene Stornierung. Eine Fehlkonfiguration ist für den Entwickler nie unsichtbar und für den Kunden nie sichtbar.
Schnellreferenz
| Sie möchten… | Verwenden Sie |
|---|---|
| SDK einrichten | SubSovereign.configure(config) |
| Sehen, was der Nutzer freigeschaltet hat | await checkEntitlements() → { hasAccess, … } (wirft bei Fehlern eine Ausnahme) |
| Einfache Sperre (fail-closed) | await hasAccess('pro') → boolean |
| Paywall laden + anzeigen | pw.config = await getPaywallConfig() + Event select-product |
| Paywall-Größe anpassen | --ss-paywall-max-width · transform: scale(…) |
| Nach dem Kauf freigeben | serverseitig (Ihr Backend oder die BYO-Billing-Brücke), dann erneut prüfen |
| Feature-Flags (fail-closed) | await getFeatureFlags() → { [flag]: boolean } |
| GEO-Zuordnung | ssCaptureLanding() nach Einwilligung · recordAttributionTouch() nach Identifizierung |
| Einwilligung erfassen | await recordConsent({ purpose, granted }) |
| DSGVO / CCPA (wirft bei Fehlern eine Ausnahme) | requestErasure() · exportMyData() · setDoNotSell(bool) |
| EU-Rücktritt | <subsovereign-withdrawal subscription-id="…" appearance="light|dark|auto"> · withdraw() |
Nächste Schritte
- React-Apps: React-Anleitung. Datenebenen-Details: Web & React Native.
- Neue Konzepte? Lesen Sie Wie SubSovereign funktioniert.