A hook that loads the [Customer Privacy API](/docs/api/customer-privacy). You can also listen to a `document` event for `shopifyCustomerPrivacyApiLoaded`. It will be emitted when the Customer Privacy API is loaded.
import {useCustomerPrivacy} from '@shopify/hydrogen';
import {useEffect} from 'react';
export function MyComponent() {
const {customerPrivacy, privacyBanner = null} = useCustomerPrivacy({
storefrontAccessToken: '12345',
checkoutDomain: 'checkout.example.com',
onVisitorConsentCollected: (consent) => {
console.log('Visitor consent collected:', consent);
},
});
useEffect(() => {
if (customerPrivacy) {
// check if user has marketing consent
console.log(
'User marketing consent:',
customerPrivacy.analyticsProcessingAllowed(),
);
// or set tracking consent
customerPrivacy.setTrackingConsent(
{
marketing: true,
analytics: true,
preferences: true,
sale_of_data: true,
},
(data) => {
if (data?.error) {
console.error('Error setting tracking consent:', data.error);
return;
}
console.log('Tracking consent set');
},
);
}
if (privacyBanner) {
privacyBanner.loadBanner();
// or show banner with specific locale and country
// privacyBanner.loadBanner({locale: 'FR', country: 'CA'});
// or show consent preferences banner
// privacyBanner.showPreferences()
// or show consent preferences banner with specific locale and country
// privacyBanner.showPreferences({locale: 'FR', country: 'CA'});
}
}, [customerPrivacy, privacyBanner]);
}
import {
type VisitorConsentCollected,
useCustomerPrivacy,
} from '@shopify/hydrogen';
import {useEffect} from 'react';
export function MyComponent() {
const {customerPrivacy, privacyBanner = null} = useCustomerPrivacy({
storefrontAccessToken: '12345',
checkoutDomain: 'checkout.example.com',
onVisitorConsentCollected: (consent: VisitorConsentCollected) => {
console.log('Visitor consent collected:', consent);
},
});
useEffect(() => {
if (customerPrivacy) {
// check if user has marketing consent
console.log(
'User marketing consent:',
customerPrivacy.analyticsProcessingAllowed(),
);
// or set tracking consent
customerPrivacy.setTrackingConsent(
{
marketing: true,
analytics: true,
preferences: true,
sale_of_data: true,
},
(data) => {
if (data?.error) {
console.error('Error setting tracking consent:', data.error);
return;
}
console.log('Tracking consent set');
},
);
}
if (privacyBanner) {
privacyBanner.loadBanner();
// or show banner with specific locale and country
// privacyBanner.loadBanner({locale: 'FR', country: 'CA'});
// or show consent preferences banner
// privacyBanner.showPreferences()
// or show consent preferences banner with specific locale and country
// privacyBanner.showPreferences({locale: 'FR', country: 'CA'});
}
}, [customerPrivacy, privacyBanner]);
}
props: CustomerPrivacyApiProps
export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { const { withPrivacyBanner = false, onVisitorConsentCollected, onReady, ...consentConfig } = props; // Load the Shopify customer privacy API with or without the privacy banner // NOTE: We no longer use the status because we need `ready` to be not when the script is loaded // but instead when both `privacyBanner` (optional) and customerPrivacy are loaded in the window useLoadScript(withPrivacyBanner ? CONSENT_API_WITH_BANNER : CONSENT_API, { attributes: { id: 'customer-privacy-api', }, }); const {observing, setLoaded} = useApisLoaded({ withPrivacyBanner, onLoaded: onReady, }); const config = useMemo(() => { const {checkoutDomain, storefrontAccessToken} = consentConfig; if (!checkoutDomain) logMissingConfig('checkoutDomain'); if (!storefrontAccessToken) logMissingConfig('storefrontAccessToken'); // validate that the storefront access token is not a server API token if ( storefrontAccessToken.startsWith('shpat_') || storefrontAccessToken.length !== 32 ) { // eslint-disable-next-line no-console console.error( `[h2:error:useCustomerPrivacy] It looks like you passed a private access token, make sure to use the public token`, ); } const config: CustomerPrivacyConsentConfig = { checkoutRootDomain: checkoutDomain, storefrontAccessToken, storefrontRootDomain: parseStoreDomain(checkoutDomain), country: consentConfig.country, locale: consentConfig.locale, }; return config; }, [consentConfig, parseStoreDomain, logMissingConfig]); // settings event listeners for visitorConsentCollected useEffect(() => { const consentCollectedHandler = ( event: CustomEvent<VisitorConsentCollected>, ) => { if (onVisitorConsentCollected) { onVisitorConsentCollected(event.detail); } }; document.addEventListener( 'visitorConsentCollected', consentCollectedHandler, ); return () => { document.removeEventListener( 'visitorConsentCollected', consentCollectedHandler, ); }; }, [onVisitorConsentCollected]); // monitor when the `privacyBanner` is in the window and override it's methods with config // pre-applied versions useEffect(() => { if (!withPrivacyBanner || observing.current.privacyBanner) return; observing.current.privacyBanner = true; let customPrivacyBanner: PrivacyBanner | undefined = window.privacyBanner || undefined; const privacyBannerWatcher = { configurable: true, get() { return customPrivacyBanner; }, set(value: unknown) { if ( typeof value === 'object' && value !== null && 'showPreferences' in value && 'loadBanner' in value ) { const privacyBanner = value as PrivacyBanner; // auto load the banner if applicable privacyBanner.loadBanner(config); // overwrite the privacyBanner methods customPrivacyBanner = overridePrivacyBannerMethods({ privacyBanner, config, }); // set the loaded state for the privacyBanner setLoaded.privacyBanner(); emitCustomerPrivacyApiLoaded(); } }, }; Object.defineProperty(window, 'privacyBanner', privacyBannerWatcher); }, [ withPrivacyBanner, config, overridePrivacyBannerMethods, setLoaded.privacyBanner, ]); // monitor when the Shopify.customerPrivacy is added to the window and override the // setTracking consent method with the config pre-applied useEffect(() => { if (observing.current.customerPrivacy) return; observing.current.customerPrivacy = true; let customCustomerPrivacy: CustomerPrivacy | null = null; let customShopify: {customerPrivacy: CustomerPrivacy} | undefined | object = window.Shopify || undefined; // monitor for when window.Shopify = {} is first set Object.defineProperty(window, 'Shopify', { configurable: true, get() { return customShopify; }, set(value: unknown) { // monitor for when window.Shopify = {} is first set if ( typeof value === 'object' && value !== null && Object.keys(value).length === 0 ) { customShopify = value as object; // monitor for when window.Shopify.customerPrivacy is set Object.defineProperty(window.Shopify, 'customerPrivacy', { configurable: true, get() { return customCustomerPrivacy; }, set(value: unknown) { if ( typeof value === 'object' && value !== null && 'setTrackingConsent' in value ) { const customerPrivacy = value as CustomerPrivacy; // overwrite the tracking consent method customCustomerPrivacy = { ...customerPrivacy, setTrackingConsent: overrideCustomerPrivacySetTrackingConsent( {customerPrivacy, config}, ), }; customShopify = { ...customShopify, customerPrivacy: customCustomerPrivacy, }; setLoaded.customerPrivacy(); emitCustomerPrivacyApiLoaded(); } }, }); } }, }); }, [ config, overrideCustomerPrivacySetTrackingConsent, setLoaded.customerPrivacy, ]); // return the customerPrivacy and privacyBanner (optional) modified APIs const result = { customerPrivacy: getCustomerPrivacy(), } as { customerPrivacy: CustomerPrivacy | null; privacyBanner?: PrivacyBanner | null; }; if (withPrivacyBanner) { result.privacyBanner = getPrivacyBanner(); } return result; }
The production shop checkout domain url.
Country code for the shop.
Language code for the shop.
Callback to be call when customer privacy api is ready.
Callback to be called when visitor consent is collected.
The storefront access token for the shop.
Whether to load the Shopify privacy banner as configured in Shopify admin. Defaults to true.
A hook that loads the [Customer Privacy API](/docs/api/customer-privacy). You can also listen to a `document` event for `shopifyCustomerPrivacyApiLoaded`. It will be emitted when the Customer Privacy API is loaded.
import {getCustomerPrivacy} from '@shopify/hydrogen';
import {useEffect} from 'react';
export function MyComponent() {
useEffect(() => {
const customerPrivacy = getCustomerPrivacy();
if (customerPrivacy) {
console.log('Customer privacy:', customerPrivacy);
}
}, []);
}