Add Global Privacy Control (GPC) support (#4023)

This commit is contained in:
Nolann B.
2026-02-18 21:32:56 +01:00
committed by GitHub
parent f517035e38
commit 2e495cb28a
6 changed files with 57 additions and 3 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"gitbook": patch
"@gitbook/browser-types": patch
---
Add Global Privacy Control (GPC) support
+6
View File
@@ -90,6 +90,12 @@ export type GitBookGlobal = {
* and `undefined` when the tracking preference is unknown or not yet determined.
*/
isCookiesTrackingDisabled: () => boolean | undefined;
/**
* Indicates whether global privacy control is enabled for the current user.
* Returns `true` when global privacy control is enabled, `false` when it is disabled.
*/
isGlobalPrivacyControlEnabled: () => boolean;
};
declare global {
@@ -8,7 +8,11 @@ import { tcls } from '@/lib/tailwind';
import { useCustomCookieBanner, useIntegrationsLoaded } from '@/components/Integrations';
import { isAIUserAgent } from '@/lib/browser';
import { isCookiesTrackingDisabled, setCookiesTracking } from '../Insights';
import {
isCookiesTrackingDisabled,
isGlobalPrivacyControlEnabled,
setCookiesTracking,
} from '../Insights';
/**
* Toast to accept or reject the use of cookies.
@@ -20,8 +24,15 @@ export function CookiesToast(props: { privacyPolicy?: string }) {
const integrationsLoaded = useIntegrationsLoaded();
const { hasCustomCookieBanner } = useCustomCookieBanner();
const isAI = isAIUserAgent();
const hasGlobalPrivacyControl = isGlobalPrivacyControlEnabled();
React.useEffect(() => {
// If global privacy control is enabled, reject cookies
if (hasGlobalPrivacyControl && !isCookiesTrackingDisabled()) {
setCookiesTracking(false);
return;
}
// Always wait for integrations to load, and if a custom banner is registered, hide the built-in banner
if (!integrationsLoaded || hasCustomCookieBanner || isAI) {
setShow(false);
@@ -29,7 +40,7 @@ export function CookiesToast(props: { privacyPolicy?: string }) {
}
setShow(isCookiesTrackingDisabled() === undefined);
}, [hasCustomCookieBanner, integrationsLoaded, isAI]);
}, [hasCustomCookieBanner, integrationsLoaded, isAI, hasGlobalPrivacyControl]);
if (!show) {
return null;
@@ -31,3 +31,22 @@ export function isCookiesTrackingDisabled() {
return undefined;
}
let cachedIsGlobalPrivacyControlEnabled: boolean | undefined;
/**
* Get the global privacy control settings of the user.
* Return `true` if global privacy control is enabled
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/globalPrivacyControl
*/
export function isGlobalPrivacyControlEnabled(): boolean {
if (cachedIsGlobalPrivacyControlEnabled !== undefined) {
return cachedIsGlobalPrivacyControlEnabled;
}
if (typeof navigator === 'undefined' || !('globalPrivacyControl' in navigator)) {
cachedIsGlobalPrivacyControlEnabled = false;
return false;
}
cachedIsGlobalPrivacyControlEnabled = Boolean(navigator.globalPrivacyControl);
return cachedIsGlobalPrivacyControlEnabled;
}
@@ -1,6 +1,10 @@
'use client';
import { isCookiesTrackingDisabled, setCookiesTracking } from '@/components/Insights';
import {
isCookiesTrackingDisabled,
isGlobalPrivacyControlEnabled,
setCookiesTracking,
} from '@/components/Insights';
import { isAIUserAgent } from '@/lib/browser';
import type {
GitBookGlobal,
@@ -109,6 +113,7 @@ if (typeof window !== 'undefined') {
});
},
isCookiesTrackingDisabled: isCookiesTrackingDisabled,
isGlobalPrivacyControlEnabled: isGlobalPrivacyControlEnabled,
};
window.GitBook = gitbookGlobal;
}
+7
View File
@@ -0,0 +1,7 @@
declare global {
interface Navigator {
globalPrivacyControl: boolean | undefined;
}
}
export {};