Every Fingerly SDK takes a consent state. Until it is granted, the SDK reads nothing from the device, sends nothing, and identify() rejects with a ConsentError. The SDKs do not talk to consent tools themselves: your code passes the tool's answer on with setConsent(). This page shows that code for common tools.
The pattern
import { load } from '@fingerly/web-js'
// Nothing is read or sent until setConsent('granted').
export const fingerly = await load({ apiKey: 'fly_pk_us_production_…', consent: 'pending' })
- Load with
pendingbefore your consent tool has answered. - Call
setConsent('granted')when the visitor accepts the category you put Fingerly in, andsetConsent('denied')when they refuse or withdraw it.pendinganddeniedbehave the same. - Apply the tool's answer on page load too: a returning visitor's choice is already stored.
- Withdrawing consent stops an identification that is already running before anything more is sent.
OneTrust
OneTrust lists the categories a visitor has accepted in OnetrustActiveGroups, and calls OptanonWrapper() when its banner loads and every time consent changes. Use the ID of the category you assigned Fingerly to, such as C0003 for Functional cookies in OneTrust's default categories.
import { fingerly } from './fingerly'
// What OneTrust puts on the page, for TypeScript.
declare global {
interface Window {
OnetrustActiveGroups?: string
OptanonWrapper?: () => void
OneTrust?: unknown
}
}
const CATEGORY = 'C0003' // the OneTrust category you assigned Fingerly to
function applyOneTrust() {
const accepted = (window.OnetrustActiveGroups ?? '').split(',').includes(CATEGORY)
fingerly.setConsent(accepted ? 'granted' : 'denied')
}
// Keep any OptanonWrapper already on the page.
const previous = window.OptanonWrapper
window.OptanonWrapper = () => {
previous?.()
applyOneTrust()
}
if (window.OneTrust) applyOneTrust() // the banner loaded before this code
Cookiebot
Cookiebot exposes the visitor's answer per category on Cookiebot.consent, and fires CookiebotOnConsentReady on the window once consent is known, including after every change.
import { fingerly } from './fingerly'
// What Cookiebot puts on the page, for TypeScript.
declare global {
interface Window {
Cookiebot?: { hasResponse?: boolean; consent?: Record<string, boolean> }
}
}
const CATEGORY = 'preferences' // necessary, preferences, statistics or marketing
function applyCookiebot() {
const accepted = Boolean(window.Cookiebot?.consent?.[CATEGORY])
fingerly.setConsent(accepted ? 'granted' : 'denied')
}
window.addEventListener('CookiebotOnConsentReady', applyCookiebot)
if (window.Cookiebot?.hasResponse) applyCookiebot() // answered before this code ran
Google Consent Mode
Consent Mode passes consent to Google's tags; it gives other scripts no supported way to read it. Set Fingerly's state in the same place you call gtag('consent', 'update'). The closest Consent Mode type is security_storage, which Google describes as covering fraud prevention.
import { fingerly } from './fingerly'
export function saveConsent(choices: { security: boolean; analytics: boolean; ads: boolean }) {
const state = (allowed: boolean) => (allowed ? 'granted' : 'denied')
gtag('consent', 'update', {
security_storage: state(choices.security),
analytics_storage: state(choices.analytics),
ad_storage: state(choices.ads),
ad_user_data: state(choices.ads),
ad_personalization: state(choices.ads),
})
fingerly.setConsent(state(choices.security))
}
Your own banner
import { fingerly } from './fingerly'
const saved = localStorage.getItem('consent.fraud-prevention')
if (saved) fingerly.setConsent(saved === 'yes' ? 'granted' : 'denied')
acceptButton.addEventListener('click', () => {
localStorage.setItem('consent.fraud-prevention', 'yes')
fingerly.setConsent('granted')
})
Frameworks
The framework SDKs take the same consent option, and wait for it: identification set to run on mount starts once consent becomes granted.
| SDK | Starting state | Change it with |
|---|---|---|
| React, Next.js | <FingerlyProvider consent="pending"> | The consent prop, or useFingerly().setConsent() |
| Vue | createFingerly({ apiKey, consent: 'pending' }) | useFingerly().setConsent() |
| Nuxt | fingerly: { consent: 'pending' } in nuxt.config | useFingerly().setConsent() |
| Svelte | setupFingerly({ apiKey, consent: 'pending' }) | useFingerly().setConsent() |
| Angular | provideFingerly({ apiKey, consent: 'pending' }) | injectFingerly().setConsent() |
import { useEffect } from 'react'
import { useFingerly } from '@fingerly/react'
// Window.OnetrustActiveGroups, OptanonWrapper and OneTrust are declared
// as in onetrust.ts.
export function OneTrustBridge() {
const fingerly = useFingerly()
useEffect(() => {
const apply = () => {
const accepted = (window.OnetrustActiveGroups ?? '').split(',').includes('C0003')
fingerly.setConsent(accepted ? 'granted' : 'denied')
}
const previous = window.OptanonWrapper
window.OptanonWrapper = () => {
previous?.()
apply()
}
if (window.OneTrust) apply()
}, [fingerly])
return null
}
Mobile apps
The iOS, Android, React Native, Flutter and Lynx SDKs take the same states. Load with pending, and call setConsent from your consent SDK's callback. In React Native, Flutter and Lynx the state is shared by the whole app, so pass it on every load. See the samples on privacy and consent.
Check that it works
- Before consent, the browser's Network panel shows no request to
/api/v1/identify, andidentify()rejects with aConsentErrorwhosecodeisconsent_required. - After accepting, the next identification succeeds without reloading the page.
- After withdrawing, identification stops again.