Core API Reference Guide
The core API is framework-agnostic and can be used without Vue.
createConsentManager
Creates a consent manager instance.
import { createConsentManager } from "@structured-world/vue-privacy";
const manager = createConsentManager({
gaId: "G-XXXXXXXXXX",
geoDetection: "auto",
});See ConsentConfig for every option.
Methods
init(): Promise<void>
Initialize the consent manager: finds whether the visitor is in a consent jurisdiction, loads the stored choice, and shows the banner if the visitor has to be asked.
await manager.init();acceptAll(): Promise<void>
Accept all consent categories.
await manager.acceptAll();rejectAll(): Promise<void>
Reject every optional category (analytics, marketing and functional); only strictly necessary storage stays. The refusal is stored like a grant, for the consent cookie's lifetime (cookie.expiry, 365 days by default), and replaces an earlier grant; the banner does not ask again on every page.
await manager.rejectAll();The consent signals, the stored choice and the closed banner take effect at once, as for acceptAll() and savePreferences(). config is queued together with the first consent default, so events tracked at any later point follow it, even while gtag.js is still loading.
savePreferences(categories): Promise<void>
Save specific category preferences. Every choice is stored, a refusal included; a category not given is refused.
await manager.savePreferences({
analytics: true,
marketing: false,
functional: true,
});getConsent(): StoredConsent | null
Get the visitor's choice (a grant or a refusal), or null while the visitor has not chosen. A choice made on this page is returned even if the browser blocks the consent cookie; a choice saved later in another tab replaces it, and a reset in another tab makes the visitor undecided again. With consentMode: 'basic', a CCPA visitor or one outside consent jurisdictions who has not chosen gets the state the jurisdiction implies (analytics off, the other categories on), so the preference centre shows what is in effect; it is not stored and hasConsent() stays false.
const consent = manager.getConsent();
if (consent) {
console.log("Analytics:", consent.categories.analytics);
}hasConsent(): boolean
Check if the visitor has chosen: true after a grant and after a refusal, whenever getConsent() returns a choice. Use getConsent() to see which categories it allows.
if (manager.hasConsent()) {
// The visitor has chosen
}isConsentRequired(): boolean | null
Whether the visitor is in a consent jurisdiction (consentJurisdictions, EEA and UK by default), so the banner asks before anything is granted; null before detection ran. A failed lookup counts as true unless geoFailure: 'grant'.
if (manager.isConsentRequired()) {
// Show GDPR-specific content
}isCCPAUser(): boolean
Whether the visitor is in a CCPA-covered US state (California, Virginia, Colorado and others); always false unless ccpaEnabled is set.
getGeoResult(): GeoDetectionResult | null
The region lookup's result (countryCode, region, method, consentRequired), or null before it ran. When the stored choice's jurisdiction stands in for a lookup, it is { consentRequired, method: 'stored' }, without a country.
getRegion(): string | undefined
The detected region or US state, when the lookup reported one.
getGeoDetectionLog(): GeoDetectionLogEntry[]
Every detection method tried and its outcome, for debugging the lookup.
trackPageView(path, title?): void
Track a page view manually. Use this for SPA navigation with Vue Router or custom routing.
While the visitor has not chosen, the event is sent under the Consent Mode defaults (analytics denied), so Google receives it as a cookieless ping and stores no identifiers. Once the visitor's choice leaves analytics off, the manager sends nothing. With consentMode: 'basic' nothing is sent until the visitor allows analytics; the page view tracked last before that is then sent once, so the page the visitor consented on is counted. With sendPageView left on, the tag's own first page view covers it and nothing extra is sent.
manager.trackPageView("/docs/guide");
manager.trackPageView("/docs/api", "API Reference");TIP
The VitePress enhanceWithConsent adapter calls this automatically on every navigation. You only need this for custom SPA setups.
trackEvent(eventName, params?): void
Send a GA4 event. Before any choice it goes out under the Consent Mode defaults, as a cookieless ping; once the visitor's choice leaves analytics off it is dropped. With consentMode: 'basic' an event tracked before the visitor allows analytics is dropped too, and unlike the last page view it is not sent later.
manager.trackEvent("share", { method: "twitter", content_type: "article" });Typed helpers send the GA4 recommended events: trackPurchase, trackAddToCart, trackBeginCheckout, trackViewItem, trackViewItemList, trackSelectItem, trackAddShippingInfo, trackAddPaymentInfo, trackSignUp(method?), trackLogin(method?) and trackGenerateLead. See Ecommerce Tracking.
isInitialized(): boolean
Check if the consent manager has been initialized.
if (manager.isInitialized()) {
// Manager is ready
}resetConsent(): void
Forget the stored choice and show the banner again. The consent signals go back to denied until the user chooses. An open preference centre closes first, and its pending requestConsent() calls answer false.
manager.resetConsent();requestConsent(category, options?): Promise<boolean>
Ask again for an optional category a feature needs, at the moment it is needed, with options.reason shown above the categories. A category in effect (granted by the visitor, or by the jurisdiction) resolves true at once and shows nothing. Otherwise the preference centre opens with the category highlighted, never pre-ticked, and the promise resolves whether the category is granted after the visitor's choice; closing the dialog resolves false and keeps the stored refusal. A call while the dialog is open joins it, and each caller gets its own answer. A call before init() settled waits for it; after destroy() it resolves false. Rejects for a category outside usedCategories, which no choice can grant. See Asking again.
const allowed = await manager.requestConsent("functional", {
reason: "Sign-in needs functional cookies to keep you logged in.",
});getConsentRequest(): ConsentRequest | null
What the open preference centre is asked for: the requested categories and the sites' reasons, for a custom dialog to show; null when no request is pending.
hidePreferenceCenter(): void
Close the preference centre without a choice (a custom dialog's close button, Escape, a click outside). The stored choice stands, and each pending requestConsent() call is answered from it. With nothing open it does nothing, and onPreferenceCenterHide does not fire.
showPreferenceCenter(): void
Open the preference centre, e.g. from a "Cookie settings" link. Without a mounted dialog the request is held until one registers.
getLocale(): SupportedLocale
The locale the banner and the preference centre are shown in.
setLocale(tag): SupportedLocale
Switch the UI language, e.g. from the site's language switcher. A language tag resolves to its locale within locales (ro-MD to ro), else to fallbackLocale; the built-in dialogs re-render in it. Returns the locale now shown. See Languages.
manager.setLocale("ro-MD"); // 'ro'onLocaleChange(listener): () => void
Call listener(locale) on every language switch, for a custom dialog to re-render. Returns a function that unregisters it.
onConsentChange(listener): void
Call listener(categories) whenever the categories in effect change on this page. With consentMode: 'basic' (and gaId) a choice made in another tab of the site counts too, once this tab follows it; in the default advanced mode the listeners are not called for another tab's choice. Each listener gets its own copy; one that throws is logged and does not stop the others.
Dialog callbacks
A custom banner or preference centre registers with the manager, which then opens and closes it:
| Method | Called |
|---|---|
onShowBanner(callback) | when the banner should show; at once if it was requested before the callback registered |
onHideBanner(callback) | when the banner should close |
onShowPreferenceCenter(callback | null) | when the preference centre should open, or refresh for a joining request; null unregisters it, and an open dialog going away answers its requests |
onHidePreferenceCenter(callback | null) | when the preference centre should close |
getConfig(): ConsentConfig
The configuration in effect, with the banner text in the current locale.
destroy(): void
Remove the manager's listeners, the script blocker and router tracking, e.g. when the app unmounts. A requestConsent() call still waiting answers false.
Google Tag Functions
setConsentDefaults
Set initial consent state before loading gtag.js.
import { setConsentDefaults } from "@structured-world/vue-privacy";
setConsentDefaults({
analytics_storage: "denied",
ad_storage: "denied",
ad_user_data: "denied",
ad_personalization: "denied",
});updateConsent
Update consent signals after user choice.
import { updateConsent } from "@structured-world/vue-privacy";
updateConsent({
analytics_storage: "granted",
});trackPageView
Low-level function that always sends a page_view event to Google Analytics without checking consent state. Google Consent Mode controls whether data is stored. For consent-aware tracking that skips sending events when analytics is denied, use ConsentManager.trackPageView() or the useConsent() composable instead.
import { trackPageView } from "@structured-world/vue-privacy";
trackPageView("/new-page");
trackPageView("/new-page", "Custom Title");initGoogleAnalytics
Initialize Google Analytics with Consent Mode: consent default, js and config are queued, then gtag.js loads and processes them.
import { initGoogleAnalytics } from "@structured-world/vue-privacy";
// Args: gaId, defaults, sendPageView, waitForUpdate, options
await initGoogleAnalytics("G-XXXXXXXXXX", true, false);options takes the same block as ConsentConfig.googleAnalytics (GoogleAnalyticsOptions): its set fields go out before config, its config fields into the config call.
await initGoogleAnalytics("G-XXXXXXXXXX", true, true, 500, {
config: { allow_google_signals: false, cookie_expires: 7776000 },
});Or, instead of the call above, per-signal defaults, e.g. for a returning visitor who allowed analytics only. The choice is already final, so waitForUpdate is 0:
await initGoogleAnalytics(
"G-XXXXXXXXXX",
{
analytics_storage: "granted",
ad_storage: "denied",
ad_user_data: "denied",
ad_personalization: "denied",
},
false,
0
);defaults is true (deny every signal), false (grant every signal) or the signals themselves. Set sendPageView to false for SPA apps where you track navigation manually. waitForUpdate (default 500) is how long tags hold their first hits for a consent update; 0 omits wait_for_update. If gtag.js is already on the page, the defaults come too late to apply, so the same signals follow as an update.
Call it once per page. Every later change goes through updateConsent(): a second call issues another consent default, and Consent Mode applies defaults only before the tag loads, so once it has loaded that default changes nothing. js and config are queued once per measurement ID, so calling it again after a failed load retries the script without a second page view. ConsentManager does this for you.
Storage Functions
getStoredConsent
Read consent from cookie.
import { getStoredConsent } from "@structured-world/vue-privacy";
const consent = getStoredConsent({ cookie: { name: "my_consent" } });storeConsent
Write consent to cookie.
import { storeConsent } from "@structured-world/vue-privacy";
storeConsent({
categories: { analytics: true, marketing: false, functional: true },
});clearConsent
Delete consent cookie.
import { clearConsent } from "@structured-world/vue-privacy";
clearConsent();createKVStorage
Create a remote consent storage backed by a Cloudflare KV Worker (vue-privacy-worker compatible API).
import { createConsentManager, createKVStorage } from "@structured-world/vue-privacy";
// Basic usage
const manager = createConsentManager({
gaId: "G-XXXXXXXXXX",
storage: createKVStorage("/api/consent"),
});
// With rate limiting options
const storage = createKVStorage("/api/consent", {
maxRetries: 5,
onRateLimited: (retryAfter, attempt) => {
console.log(`Rate limited (attempt ${attempt}). Retry in ${retryAfter ?? "exponential"}s`);
},
});Options
| Option | Type | Default | Description |
|---|---|---|---|
maxRetries | number | 3 | Total fetch attempts on 429 (1 initial + N-1 retries) |
onRateLimited | function | - | Callback invoked on each 429 response |
Rate Limiting Behavior
When the server returns a 429 (Too Many Requests) response:
- Retry with exponential backoff: Delays between attempts are 1s, 2s, 4s, 8s... (2^0, 2^1, 2^2... seconds)
- Respect Retry-After header: If the server sends a
Retry-Afterheader, that delay is used instead - Graceful fallback: After max retries, returns
null(consent stored locally via cookie only)
The onRateLimited callback receives:
retryAfter- Delay from server's Retry-After header (in seconds), ornullif not providedattempt- Current attempt number (1-based)