SubSovereign Web Component — przewodnik integracji (Vue, Svelte, Angular, czysty HTML)
Ten przewodnik dotyczy sdk-web/ — frameworkowo-niezależnego SDK przeglądarkowego. Zawiera klienta danych oparty na fetch oraz dwa Web Componenty, <subsovereign-paywall> i <subsovereign-withdrawal>, które działają na każdej stronie — Vue, Svelte, Angular lub zwykłej stronie HTML — bez kroku kompilacji i bez zależności. (Używasz Reacta? Skorzystaj z przewodnika dla Reacta.)
Przed rozpoczęciem
Działający serwer SubSovereign, zarejestrowana aplikacja w panelu (zawierająca appId i klucz API w roli SDK), oraz opublikowana bramka płatności.
Krok 1 — Załadowanie i konfiguracja
<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>
Krok 2 — Sprawdzanie dostępu użytkownika
const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) showPremiumContent();
else showPaywall();
W przypadku prostego zabezpieczenia dostępna jest metoda hasAccess(), opcjonalnie dla konkretnego poziomu dostępu. Działa zamknięcie awaryjne: w przypadku błędu sieci zwraca false, więc chwilowa awaria nigdy nie odblokuje płatnej zawartości przez przypadek.
if (await SubSovereign.hasAccess('pro')) showPremiumContent();
Metoda checkEntitlements() zgłasza wyjątek w przypadku niepowodzenia, aby użytkownik mógł pozostać przy ostatnio znanym dostępie; hasAccess() nigdy nie zgłasza wyjątku. Wybierz tę, której zachowanie w przypadku awarii Ci odpowiada.
Krok 3 — Wyświetlanie bramy płatności i sprzedaż
<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>
Rozmiar bramy jest Twoim zadaniem. Domyślna szerokość wynosi 420px; możesz ją powiększyć za pomocą właściwości CSS (właściwości niestandardowe przenikają przez shadow DOM) i/lub skalować jednolicie:
subsovereign-paywall { --ss-paywall-max-width: 900px; transform: scale(1.4); }
Przyznawanie zakupu: ten SDK nie zawiera klientskiego wywołania validate…. Dopełnij płatności za pomocą swojego dostawcy, przyznaj dostęp po stronie serwera — Twój backend wywołuje Twój serwer SubSovereign lub podpisany mostek rozliczeń własnych (POST /entitlements/external) — a następnie ponownie sprawdź:
const again = await SubSovereign.checkEntitlements();
if (again.hasAccess) unlock();
Flagi funkcjonalne
Wdrażaj funkcje z poziomu serwera bez konieczności wdrażania. Działa zamknięcie awaryjne: w przypadku błędu sieci otrzymasz {}, więc każda flaga będzie traktowana jako wyłączona.
const flags = await SubSovereign.getFeatureFlags(); // { newPlayer: true, ... }
if (flags.newPlayer) showNewPlayer();
Atrybucja odpowiedzi AI (GEO)
Jeśli korzystasz z funkcji Acquisition/GEO, przechwyć źródło odwiedzających — odnośnik AI istnieje tylko na stronie docelowej, a identyfikator użytkownika pojawia się dopiero po rejestracji, dlatego jest to proces dwuetapowy: zapisanie i wysłanie:
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();
SDK nie zapisuje niczego na urządzeniu odwiedzającego do momentu wywołania ssCaptureLanding(). Importowanie pakietu niczego nie zapisuje. Zapisywane dane (odnośnik + tagi UTM) są danymi osobowymi zgodnie z RODO i przechowywaniem zgodnie z ePrivacy, dlatego kiedy je przechwycić, to decyzja o zgodzie, a nie nasza — wywołaj je z obsługi akceptacji Twojego banera. Bez przechwycenia recordAttributionTouch() raportuje jedynie to, co widzi strona rejestracji — tagi UTM z adresu URL i ewentualny odnośnik, jeśli nie pochodzi z Twojej witryny — dlatego AI lub wyszukiwarka, która odesłała użytkownika wcześniej, nie zostanie przypisana. To koszt braku przechwycenia i to wybór odwiedzającego.
recordAttributionTouch() wysyła pierwsze zapisane lądowanie (jest ważniejsze niż bieżąca strona), czyści zapis tylko po udanym wysłaniu, aby późniejsze logowanie mogło ponowić próbę, i nigdy nie zgłasza wyjątku. Jeśli strony docelowe nie mogą wywołać configure() (statyczna strona marketingowa bez użytkownika), ssFlushAttribution(userId, { apiUrl, apiKey }) wykonuje to samo wysłanie z jawnymi danymi uwierzytelniającymi — lub ustaw window.SS_API_URL i window.SS_API_KEY.
Pochodzenie Twojej witryny musi być na liście ALLOWED_ORIGINS serwera, w przeciwnym razie przeglądarka milcząco nic nie zgłosi.
Prywatność (RODO i 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
Trzy wywołania dotyczące prywatności zgłaszają wyjątek w przypadku niepowodzenia (ApiError, z .status). Użytkownik korzystający z przysługującego mu prawa musi zostać poinformowany, gdy operacja nie powiodła się — złap błąd i poinformuj o tym; nigdy nie pokazuj milczącego sukcesu. Rekordy rozliczeniowe są przechowywane przez serwer zgodnie z art. 17 ust. 3 lit. b RODO i anonimizowane.
Przycisk wycofania z UE (Paszport Zgodności)
<subsovereign-withdrawal subscription-id="SUB_ID" appearance="auto"></subsovereign-withdrawal>
Wyraźnie oznaczony przycisk → pojedyncze potwierdzenie → idempotentne wysłanie → potwierdzenie, zgodnie z Dyrektywą (UE) 2023/2673. W przypadku interfejsów niestandardowych: SubSovereign.withdraw(subscriptionId, opts) i SubSovereign.getWithdrawalConfig().
Wygląd — light, dark lub auto (domyślnie), i tylko te wartości. Dialog samodzielnie maluje swoją kartę i tekst, dzięki czemu jest czytelny na każdej stronie hosta; auto stosuje się do ustawień przeglądarki odwiedzającego (prefers-color-scheme), a atrybut można zmienić w dowolnym momencie — karta jest ponownie malowana. Celowo nie ma możliwości przekazania koloru: jest to obowiązkowe powiadomienie, a sformułowania i kolory są ustalone, aby były czytelne dla każdego klienta każdego najemcy. Słowa pochodzą z Twojego serwera w języku klienta (locale w configure()); przy starszym serwerze następuje zapasowe tłumaczenie na angielski zamiast pozostawienia pustego pola.
Element emituje zdarzenia withdrawal-shown, withdrawal-submitted (szczegóły: potwierdzenie) oraz withdrawal-error (szczegóły: { reason, status? }) dla Twojej analityki. Jeśli zapomnisz o subscription-id, klient zobaczy przetłumaczony komunikat o błędzie, a Ty otrzymasz błąd w konsoli i zdarzenie withdrawal-error. Jeśli element nie może załadować ustawień (zły klucz, zły appId, serwer odmawia dostępu do pochodzenia tej strony), klient nadal otrzyma przycisk — po angielsku — a Ty otrzymasz console.warn z prawdopodobną przyczyną oraz zdarzenie withdrawal-error z reason: 'config-unavailable' i, jeśli istnieje, kodem HTTP status (odmowa pochodzenia lub błędny adres URL nie posiadają statusu). Nasłuchuj tego zdarzenia we wszystkich środowiskach: to dzięki niemu dowiesz się, że klienci niemieckojęzyczni widzą angielski. Zauważ, że zdarzenie to wyzwalane jest podczas ładowania, przed jakąkolwiek interakcją użytkownika — nie traktuj go jako nieudanego anulowania. Błąd konfiguracji nigdy nie jest ukryty dla developera i nigdy nie jest widoczny dla klienta.
Szybki przegląd
| Chcesz… | Użyj |
|---|---|
| Skonfigurować SDK | SubSovereign.configure(config) |
| Zobaczyć, co użytkownik odblokował | await checkEntitlements() → { hasAccess, … } (zgłasza wyjątek w przypadku niepowodzenia) |
| Proste zabezpieczenie (zamknięcie awaryjne) | await hasAccess('pro') → boolean |
| Załadować + wyświetlić bramę płatności | pw.config = await getPaywallConfig() + zdarzenie select-product |
| Dopasować rozmiar bramy | --ss-paywall-max-width · transform: scale(…) |
| Przyznać dostęp po zakupie | po stronie serwera (Twój backend lub mostek rozliczeń własnych), a następnie ponownie sprawdź |
| Flagi funkcjonalne (zamknięcie awaryjne) | await getFeatureFlags() → { [flag]: boolean } |
| Atrybucja GEO | ssCaptureLanding() po zgodzie · recordAttributionTouch() po identyfikacji |
| Zarejestrować zgodę | await recordConsent({ purpose, granted }) |
| RODO / CCPA (zgłaszanie wyjątku w przypadku niepowodzenia) | requestErasure() · exportMyData() · setDoNotSell(bool) |
| Wycofanie z UE | <subsovereign-withdrawal subscription-id="…" appearance="light|dark|auto"> · withdraw() |
Następne kroki
- Aplikacje React: Przewodnik dla Reacta. Głębokie zanurzenie w warstwie danych: Web & React Native.
- Nowy w temacie? Przeczytaj Jak działa SubSovereign.