Legal Consent
Publish Terms of Service and Privacy Policy versions from the dashboard, and require signed-in users to accept a material update inside your app. When enabled, a blocking gate appears the moment the version takes effect: the user must accept the new document — or sign out — before they can keep using the app. Manage documents under Dashboard → Legal (workspace-level, with a picker for the app the documents belong to).
Publish a version
- Open Legal, pick a document — Terms, Privacy or DPA (Cookies is marked Coming soon) — and click New version.
- Write the content, set the effective date, and choose how it's delivered:
- Notify users by email — announce + reminder emails (optional).
- Require in-app acceptance — the blocking gate. This is what drives the SDK.
- Publish. Signed-in users are gated from the effective date; users who joined before the version took effect are the audience — brand-new users are bound at sign-up and never re-prompted.
How the SDK gate works
Every SDK reads a server-computed blocking flag (enforcement is decided on the server, never the client clock). When a blocking document is outstanding, the SDK presents the hosted gate and, on the user's choice:
- Accept → records the acceptance, then re-checks for the next stacked document.
- Sign out → signs the user out (there is no “dismiss”).
Updates arrive in real time — the moment you publish, the gate appears in every running, signed-in app over a live connection. No polling, no restart.
Per-platform behaviour
| Platform | Presentation | What you wire |
|---|---|---|
| Swift | Hosted gate in a WKWebView; app content is held behind it until resolved. | Nothing while OneloAuthView is mounted; use .oneloConsentGate(auth:) on your post-login UI. |
| Electron | Hosted gate in a modal BrowserWindow — non-dismissible, blocks the app. | Call onelo.consent.setGateParent(mainWindow) so the gate is modal over your window. |
| JS / Web | Full-screen, non-dismissible SDK overlay (the browser blocks cross-origin iframing of the hosted page). | Nothing — on by default. Return to login on sign-out (see below). |
| React Native | Hosted gate in a non-dismissible modal WebView. | Mount <ConsentGateModal consent={onelo.consent} /> once, near your app root. |
| Flutter | Hosted gate in a WebView that wraps your widget tree. | Wrap your post-login tree in OneloConsentGate. |
| Android | Hosted gate in a dedicated Activity, auto-presented on resume. | Call onelo.consent.registerLauncher(activity, auth) { result -> … } in onCreate. |
result.declined (already signed out); on Web, Electron, React Native and Flutter, listen for the session going null.Web / Electron — return to login on sign-out
Use ONE SDK instance and subscribe to session changes on onelo.auth — the same instance the consent gate signs out. A separate auth instance would never receive the event.
import { Onelo } from '@onelo/js'
const onelo = new Onelo({ publishableKey: '...', apiUrl: '...' })
// The blocking gate auto-presents on sign-in and on publish. Nothing to wire.
// Just return to your login UI when the gate's "Sign out" clears the session:
onelo.auth.onAuthStateChange((session) => {
if (!session) showLoginScreen() // declined gate, revoke, or expiry
})import { Onelo } from '@onelo/electron'
const onelo = new Onelo({ publishableKey: '...', apiUrl: '...', protocol: 'onelo-my-app' }) // YOUR app's unique scheme — see /docs/security/app-identity
const auth = onelo.auth // same instance the gate signs out
app.whenReady().then(async () => {
const mainWindow = new BrowserWindow({ show: false })
onelo.consent.setGateParent(mainWindow) // required for a true modal hard block
auth.onSessionChange((userId) => {
if (!userId) { mainWindow.hide(); void auth.presentAuthWindow(null) }
})
// ...create + show your window after sign-in
})Custom UI (drive it yourself)
To build your own gate instead of the hosted one, disable auto-present and read the pending documents. This is the same API the built-in gate uses.
const onelo = new Onelo({ /* ... */ autoPresentConsentGate: false })
// React to a live publish:
onelo.consent.onConsentRequired(() => renderYourBanner())
// Read + record:
const pending = await onelo.consent.requiredConsents()
const blocker = pending.find(c => c.blocking) // block | notify | unknown
if (blocker) {
// show blocker.url (the full document), then on accept:
await onelo.consent.acceptConsent(blocker.versionId)
}Availability
| SDK | Consent gate |
|---|---|
| Swift (iOS / macOS) | Available |
| Electron | Available |
| JS / TS (Web) | Available |
| React Native | Available |
| Flutter | Available |
| Android | Available |