SubSovereign
All guides

SubSovereign Web Component — guida all’integrazione (Vue, Svelte, Angular, HTML puro)

Questa guida copre sdk-web/ — l’SDK browser agnostico rispetto al framework. Include un client dati basato su fetch e due Web Component, <subsovereign-paywall> e <subsovereign-withdrawal>, che funzionano su qualsiasi sito — Vue, Svelte, Angular o una semplice pagina HTML — senza passaggi di build e senza dipendenze. (Sviluppi in React? Usa la guida React invece.)

Prima di iniziare

È necessario un server SubSovereign attivo, un’app registrata nel dashboard (con un appId e una chiave API di ruolo SDK) e un paywall pubblicato.

Passo 1 — Caricamento e configurazione

<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>

Passo 2 — Verificare cosa può fare l’utente

const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) showPremiumContent();
else showPaywall();

Per un semplice controllo esiste hasAccess(), opzionalmente per un determinato livello di accesso. Il comportamento predefinito è chiuso: in caso di errore di rete restituisce false, quindi un problema temporaneo non potrà mai sbloccare contenuti a pagamento per errore.

if (await SubSovereign.hasAccess('pro')) showPremiumContent();

checkEntitlements() lancia un’eccezione in caso di errore, così puoi mantenere l’utente nell’accesso noto precedente; hasAccess() non lancia mai eccezioni. Scegli il metodo il cui comportamento in caso di errore si adatta meglio alle tue esigenze.

Passo 3 — Mostrare il paywall e vendere

<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>

La dimensione è compito della tua pagina. La larghezza predefinita è 420 px; puoi aumentarla con la proprietà CSS personalizzata (le proprietà personalizzate attraversano lo shadow DOM) e/o scalare uniformemente:

subsovereign-paywall { --ss-paywall-max-width: 900px; transform: scale(1.4); }

Concedere l’acquisto: questo SDK non include chiamate di validate… lato client. Completa il checkout con il tuo fornitore, poi concedi l’entitlement lato server — il tuo backend chiama il server SubSovereign o usa il bridge bring-your-own-billing firmato (POST /entitlements/external) — quindi verifica nuovamente:

const again = await SubSovereign.checkEntitlements();
if (again.hasAccess) unlock();

Feature flag

Distribuisci funzionalità dal server senza effettuare un deploy. Comportamento predefinito chiuso: in caso di errore di rete ottieni {}, quindi ogni flag viene interpretato come disattivato.

const flags = await SubSovereign.getFeatureFlags(); // { newPlayer: true, ... }
if (flags.newPlayer) showNewPlayer();

Attribuzione dell’AI answer-engine (GEO)

Se usi le funzionalità Acquisition/GEO, registra da dove provengono i visitatori — il referrer AI esiste solo sulla pagina di atterraggio, e l’ID utente esiste solo dopo la registrazione, quindi è necessario un processo in due fasi di memorizzazione e invio:

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();

L’SDK non memorizza nulla sul dispositivo del visitatore finché non chiami ssCaptureLanding(). L’importazione del pacchetto non scrive nulla. La memorizzazione temporanea (referrer + tag UTM) è un dato personale ai sensi del GDPR e una memorizzazione ai sensi dell’ePrivacy, quindi quando effettuarla è una tua decisione in merito al consenso: chiamala dal gestore dell’accettazione del banner. Senza la memorizzazione, recordAttributionTouch() riporterà solo ciò che la pagina di registrazione stessa può vedere — i tag UTM nell’URL e un referrer se non proviene dal tuo sito — quindi un referral da AI o da motore di ricerca avvenuto su una pagina di atterraggio precedente non verrà attribuito. Questo è il compromesso derivante dall’assenza di memorizzazione, ed è una scelta del visitatore.

recordAttributionTouch() invia il primo atterraggio memorizzato (sovrascrivendo la pagina corrente), svuota la memorizzazione solo dopo un invio riuscito, così un successivo login ritenta, e non lancia mai eccezioni. Se le tue pagine di atterraggio non possono chiamare configure() (ad esempio un sito di marketing statico senza utente), ssFlushAttribution(userId, { apiUrl, apiKey }) esegue lo stesso invio con credenziali esplicite — oppure imposta window.SS_API_URL e window.SS_API_KEY.

L’origine del tuo sito web deve essere inclusa tra gli ALLOWED_ORIGINS del server, altrimenti il browser non riporterà nulla in modo silenzioso.

Privacy (GDPR e 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

Le tre chiamate relative alla privacy lanciano eccezioni in caso di errore (ApiError, con .status). Se un utente esercita un diritto legale, deve essere informato se l’operazione non è andata a buon fine: gestisci l’errore e comunica l’esito negativo; non mostrare mai un successo silenzioso. I registri di fatturazione vengono conservati dal server ai sensi dell’art. 17(3)(b) del GDPR e anonimizzati.

Pulsante di recesso UE (Compliance Passport)

<subsovereign-withdrawal subscription-id="SUB_ID" appearance="auto"></subsovereign-withdrawal>

Pulsante etichettato in modo prominente → conferma singola → invio idempotente → riconoscimento, secondo la Direttiva (UE) 2023/2673. Per interfacce utente personalizzate: SubSovereign.withdraw(subscriptionId, opts) e SubSovereign.getWithdrawalConfig().

Aspetto — light, dark o auto (predefinito), e solo queste opzioni. Il dialogo disegna la propria scheda e il proprio testo, quindi è leggibile su qualsiasi pagina host; auto segue le preferenze del browser del visitatore (prefers-color-scheme), e l’attributo può essere modificato in qualsiasi momento — la scheda viene ridisegnata. Non esiste alcuna possibilità di passare un colore: si tratta di un avviso statutario, e il testo e i colori sono fissi affinché risulti identico per ogni cliente di ogni tenant. Le parole arrivano dal tuo server nella lingua del cliente (locale in configure()); con un server più vecchio, viene usato l’inglese come fallback invece di lasciare uno spazio vuoto.

L’elemento emette gli eventi withdrawal-shown, withdrawal-submitted (dettaglio: la ricevuta) e withdrawal-error (dettaglio: { reason, status? }) per le tue analisi. Se dimentichi subscription-id, il cliente visualizza l’errore tradotto e tu ricevi un errore in console e un evento withdrawal-error. Se l’elemento non riesce a caricare le impostazioni (chiave errata, app id errato, il server rifiuta l’origine di questa pagina), il cliente vede comunque il pulsante — in inglese — e tu ricevi un console.warn che indica la probabile causa più un evento withdrawal-error con reason: 'config-unavailable' e, se presente, lo stato HTTP (un’origine rifiutata o un URL errato non ne hanno uno). Ascolta questo evento in ogni ambiente: è così che scopri se i clienti tedeschi vedono l’inglese. Nota che viene attivato al caricamento, prima di qualsiasi azione del cliente — non considerarlo come un fallimento della cancellazione. Una configurazione errata non è mai silenziosa per lo sviluppatore e non è mai visibile al cliente.

Riferimento rapido

Vuoi… Usa
Configurare l’SDK SubSovereign.configure(config)
Vedere cosa ha sbloccato l’utente await checkEntitlements(){ hasAccess, … } (lancia eccezione in caso di errore)
Controllo semplice (chiuso in caso di errore) await hasAccess('pro')boolean
Caricare e visualizzare il paywall pw.config = await getPaywallConfig() + evento select-product
Dimensione del paywall --ss-paywall-max-width · transform: scale(…)
Concedere l’accesso dopo il checkout lato server (il tuo backend o il bridge BYO-billing), poi verifica nuovamente
Feature flag (chiuso in caso di errore) await getFeatureFlags(){ [flag]: boolean }
Attribuzione GEO ssCaptureLanding() dopo il consenso · recordAttributionTouch() una volta identificato
Registrare il consenso await recordConsent({ purpose, granted })
GDPR / CCPA (lancia eccezione in caso di errore) requestErasure() · exportMyData() · setDoNotSell(bool)
Recesso UE <subsovereign-withdrawal subscription-id="…" appearance="light|dark|auto"> · withdraw()

Passaggi successivi