Version 2025-07 is the last API version to support React-based UI components. Later versions use Polaris web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the upgrade guide to upgrade your extension and avoid being blocked from updating your extension after October 1st 2026.
Customer Privacy API
The API for interacting with a customer's privacy consent. It is similar to the Customer Privacy API in storefront.
Anchor to StandardApiStandard Api
The base API object provided to purchase extension targets.
- Anchor to applyTrackingConsentChangeapply
Tracking Consent Changeapply Tracking Consent Change ApplyTrackingConsentChangeTypeApplyTrackingConsentChangeTyperequiredrequired Allows setting and updating customer privacy consent settings and tracking consent metafields.
NoteRequires the
capability to be set totrue.Note:Requires the
capability to be set totrue.Note: Requires the <a href="/docs/api/checkout-ui-extensions/unstable/configuration#collect-buyer-consent"><code><span class="PreventFireFoxApplyingGapToWBR">customer<wbr/>_privacy</span></code> capability</a> to be set to <code>true</code>.
Requires access to protected customer data.
- Anchor to customerPrivacycustomer
Privacycustomer Privacy StatefulRemoteSubscribable<CustomerPrivacy>StatefulRemoteSubscribable<CustomerPrivacy>requiredrequired Customer privacy consent settings and a flag denoting if consent has previously been collected.
ApplyTrackingConsentChangeType
- visitorConsent
VisitorConsentChange
Promise<TrackingConsentChangeResult>VisitorConsentChange
- analytics
Visitor consents to recording data to understand how customers interact with the site.
boolean - marketing
Visitor consents to ads and marketing communications based on customer interests.
boolean - metafields
Tracking consent metafield data to be saved. If the value is `null`, the metafield will be deleted.
TrackingConsentMetafieldChange[] - preferences
Visitor consent to remembering customer preferences, such as country or language, to personalize visits to the website.
boolean - saleOfData
Opts the visitor out of data sharing / sales.
boolean - type
'changeVisitorConsent'
TrackingConsentMetafieldChange
- key
The name of the metafield. It must be between 3 and 30 characters in length (inclusive).
string - value
The information to be stored as metadata. If the value is `null`, the metafield will be deleted.
string | null
TrackingConsentChangeResult
TrackingConsentChangeResultSuccess | TrackingConsentChangeResultErrorTrackingConsentChangeResultSuccess
The returned result of a successful tracking consent preference update.
- type
The type of the `TrackingConsentChangeResultSuccess` API.
'success'
TrackingConsentChangeResultError
The returned result of an unsuccessful tracking consent preference update with a message detailing the type of error that occurred.
- message
A message that explains the error. This message is useful for debugging. It is **not** localized, and therefore should not be presented directly to the buyer.
string - type
The type of the `TrackingConsentChangeResultError` API.
'error'
CustomerPrivacy
- allowedProcessing
An object containing flags for each consent property denoting whether they can be processed based on visitor consent, merchant configuration, and user location.
AllowedProcessing - metafields
Stored tracking consent metafield data.
TrackingConsentMetafield[] - region
Details about the visitor's current location for use in evaluating if more granular consent controls should render.
CustomerPrivacyRegion - saleOfDataRegion
Whether the visitor is in a region requiring data sale opt-outs.
boolean - shouldShowBanner
Whether a consent banner should be displayed by default when the page loads. Use this as the initial open/expanded state of the consent banner. This is determined by the visitor's current privacy consent, the shop's [region visibility configuration](https://help.shopify.com/en/manual/privacy-and-security/privacy/customer-privacy-settings/privacy-settings#add-a-cookie-banner) settings, and the region in which the visitor is located.
boolean - visitorConsent
An object containing the customer's current privacy consent settings. *
VisitorConsent
AllowedProcessing
- analytics
Can collect customer analytics about how the shop was used and interactions made on the shop.
boolean - marketing
Can collect customer preference for marketing, attribution and targeted advertising from the merchant.
boolean - preferences
Can collect customer preferences such as language, currency, size, and more.
boolean - saleOfData
Can collect customer preference for sharing data with third parties, usually for behavioral advertising.
boolean
TrackingConsentMetafield
- key
The name of the metafield. It must be between 3 and 30 characters in length (inclusive).
string - value
The information to be stored as metadata.
string
CustomerPrivacyRegion
- countryCode
The [ISO 3166 Alpha-2 format](https://www.iso.org/iso-3166-country-codes.html) for the buyer's country. {% include /apps/checkout/privacy-icon.md %} Requires level 1 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).
CountryCode - provinceCode
The buyer's province code, such as state, province, prefecture, or region. Province codes can be found by clicking on the `Subdivisions assigned codes` column for countries listed [here](https://en.wikipedia.org/wiki/ISO_3166-2). {% include /apps/checkout/privacy-icon.md %} Requires level 1 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).
string
CountryCode
'AC' | 'AD' | 'AE' | 'AF' | 'AG' | 'AI' | 'AL' | 'AM' | 'AN' | 'AO' | 'AR' | 'AT' | 'AU' | 'AW' | 'AX' | 'AZ' | 'BA' | 'BB' | 'BD' | 'BE' | 'BF' | 'BG' | 'BH' | 'BI' | 'BJ' | 'BL' | 'BM' | 'BN' | 'BO' | 'BQ' | 'BR' | 'BS' | 'BT' | 'BV' | 'BW' | 'BY' | 'BZ' | 'CA' | 'CC' | 'CD' | 'CF' | 'CG' | 'CH' | 'CI' | 'CK' | 'CL' | 'CM' | 'CN' | 'CO' | 'CR' | 'CU' | 'CV' | 'CW' | 'CX' | 'CY' | 'CZ' | 'DE' | 'DJ' | 'DK' | 'DM' | 'DO' | 'DZ' | 'EC' | 'EE' | 'EG' | 'EH' | 'ER' | 'ES' | 'ET' | 'FI' | 'FJ' | 'FK' | 'FO' | 'FR' | 'GA' | 'GB' | 'GD' | 'GE' | 'GF' | 'GG' | 'GH' | 'GI' | 'GL' | 'GM' | 'GN' | 'GP' | 'GQ' | 'GR' | 'GS' | 'GT' | 'GW' | 'GY' | 'HK' | 'HM' | 'HN' | 'HR' | 'HT' | 'HU' | 'ID' | 'IE' | 'IL' | 'IM' | 'IN' | 'IO' | 'IQ' | 'IR' | 'IS' | 'IT' | 'JE' | 'JM' | 'JO' | 'JP' | 'KE' | 'KG' | 'KH' | 'KI' | 'KM' | 'KN' | 'KP' | 'KR' | 'KW' | 'KY' | 'KZ' | 'LA' | 'LB' | 'LC' | 'LI' | 'LK' | 'LR' | 'LS' | 'LT' | 'LU' | 'LV' | 'LY' | 'MA' | 'MC' | 'MD' | 'ME' | 'MF' | 'MG' | 'MK' | 'ML' | 'MM' | 'MN' | 'MO' | 'MQ' | 'MR' | 'MS' | 'MT' | 'MU' | 'MV' | 'MW' | 'MX' | 'MY' | 'MZ' | 'NA' | 'NC' | 'NE' | 'NF' | 'NG' | 'NI' | 'NL' | 'NO' | 'NP' | 'NR' | 'NU' | 'NZ' | 'OM' | 'PA' | 'PE' | 'PF' | 'PG' | 'PH' | 'PK' | 'PL' | 'PM' | 'PN' | 'PS' | 'PT' | 'PY' | 'QA' | 'RE' | 'RO' | 'RS' | 'RU' | 'RW' | 'SA' | 'SB' | 'SC' | 'SD' | 'SE' | 'SG' | 'SH' | 'SI' | 'SJ' | 'SK' | 'SL' | 'SM' | 'SN' | 'SO' | 'SR' | 'SS' | 'ST' | 'SV' | 'SX' | 'SY' | 'SZ' | 'TA' | 'TC' | 'TD' | 'TF' | 'TG' | 'TH' | 'TJ' | 'TK' | 'TL' | 'TM' | 'TN' | 'TO' | 'TR' | 'TT' | 'TV' | 'TW' | 'TZ' | 'UA' | 'UG' | 'UM' | 'US' | 'UY' | 'UZ' | 'VA' | 'VC' | 'VE' | 'VG' | 'VN' | 'VU' | 'WF' | 'WS' | 'XK' | 'YE' | 'YT' | 'ZA' | 'ZM' | 'ZW' | 'ZZ'VisitorConsent
- analytics
Visitor consents to recording data to understand how customers interact with the site.
boolean - marketing
Visitor consents to ads and marketing communications based on customer interests.
boolean - preferences
Visitor consent to remembering customer preferences, such as country or language, to personalize visits to the website.
boolean - saleOfData
Opts the visitor out of data sharing / sales.
boolean
Anchor to useCustomerPrivacyuse Customer Privacy()
Returns the current customer privacy settings and metadata and re-renders your component if the customer privacy settings change.
Examples
Read Customer Privacy
React
import {useState} from 'react'; import { reactExtension, useCustomerPrivacy, } from '@shopify/ui-extensions-react/checkout'; // 1. Choose an extension target export default reactExtension( 'purchase.checkout.block.render', () => <Extension />, ); function Extension() { // 2. Subscribe to customer privacy consent values const { visitorConsent: { analytics, marketing, preferences, saleOfData, }, } = useCustomerPrivacy(); // 3. Use consent values console.log('analytics', analytics); console.log('marketing', marketing); console.log('preferences', preferences); console.log('saleOfData', saleOfData); }JavaScript
import { extension, Text, } from '@shopify/ui-extensions/checkout'; // 1. Choose an extension target export default extension( 'purchase.checkout.block.render', (root, {customerPrivacy}) => { const { visitorConsent: { analytics, marketing, preferences, saleOfData, }, } = customerPrivacy.current; // 2. Use consent values console.log('initialValues'); console.log('analytics', analytics); console.log('marketing', marketing); console.log('preferences', preferences); console.log('saleOfData', saleOfData); // 3. Update component state when customerPrivacy changes customerPrivacy.subscribe((value) => { if (!value) { return; } const { visitorConsent: { analytics, marketing, preferences, saleOfData, }, } = value; console.log('updatedValues'); console.log('analytics', analytics); console.log('marketing', marketing); console.log('preferences', preferences); console.log('saleOfData', saleOfData); }); }, );Use a Sheet to manage customer privacy consent
Description
You can apply changes to customer consent by using the `applyTrackingConsentChanges` API. Note: Requires the [`customer_privacy` capability](/docs/apps/build/checkout/capabilities#collect-buyer-consent) to be set to `true`.
React
import {useState} from 'react'; import { reactExtension, BlockStack, Button, Checkbox, Form, Grid, Link, Modal, Sheet, TextBlock, useApi, useCustomerPrivacy, } from '@shopify/ui-extensions-react/checkout'; import type {VisitorConsent} from '@shopify/ui-extensions/checkout'; export default reactExtension( 'purchase.checkout.footer.render-after', () => <Extension />, ); function Extension() { const {applyTrackingConsentChange, ui} = useApi(); const { shouldShowBanner, visitorConsent: { analytics, marketing, preferences, saleOfData, }, } = useCustomerPrivacy(); const [ consentFormValues, setConsentFormValues, ] = useState({ analytics, marketing, preferences, saleOfData, }); const sheetId = 'sheet-consent'; const modalId = 'modal-consent'; const getCheckboxOnChangeHandler = ( key: string, ) => { return function (checked: boolean) { setConsentFormValues({ ...consentFormValues, [key]: checked, }); }; }; const handleConsentChange = async ( visitorConsent?: VisitorConsent, ) => { try { const result = await applyTrackingConsentChange({ ...(visitorConsent ? visitorConsent : consentFormValues), type: 'changeVisitorConsent', }); // Check if operation was successful if (result.type === 'success') { ui.overlay.close(modalId); ui.overlay.close(sheetId); } else { // Handle failure case here } } catch (error) { // Handle error case here } }; const consentFormMarkup = ( <Form onSubmit={() => handleConsentChange()}> <BlockStack> <Grid spacing="base"> <Checkbox id="marketing" checked={consentFormValues.marketing} onChange={getCheckboxOnChangeHandler( 'marketing', )} > Marketing </Checkbox> <Checkbox id="analytics" checked={consentFormValues.analytics} onChange={getCheckboxOnChangeHandler( 'analytics', )} > Analytics </Checkbox> <Checkbox id="preferences" checked={ consentFormValues.preferences } onChange={getCheckboxOnChangeHandler( 'preferences', )} > Preferences </Checkbox> <Checkbox id="saleOfData" checked={consentFormValues.saleOfData} onChange={getCheckboxOnChangeHandler( 'saleOfData', )} > Sale of data </Checkbox> </Grid> <Button accessibilityRole="submit"> Save </Button> </BlockStack> </Form> ); return ( <Sheet id={sheetId} accessibilityLabel="A sheet that collects privacy consent preferences" defaultOpen={shouldShowBanner} primaryAction={ <> <Button kind="secondary" onPress={() => handleConsentChange({ analytics: false, marketing: false, preferences: false, saleOfData: false, }) } > I decline </Button> <Button kind="secondary" onPress={() => handleConsentChange({ analytics: true, marketing: true, preferences: true, saleOfData: true, }) } > I agree </Button> </> } secondaryAction={ <Button kind="plain" overlay={ <Modal id={modalId} padding> {consentFormMarkup} </Modal> } > Settings </Button> } > <TextBlock> This website uses cookies to ensure you get the best experience on our website.{' '} <Link>Privacy Policy</Link> </TextBlock> </Sheet> ); }JavaScript
import { BlockStack, Button, Checkbox, extension, Form, Grid, Link, Modal, Sheet, TextBlock, } from '@shopify/ui-extensions/checkout'; import type {VisitorConsent} from '@shopify/ui-extensions/checkout'; // 1. Choose an extension target export default extension( 'purchase.checkout.footer.render-after', ( root, { applyTrackingConsentChange, customerPrivacy, ui, }, ) => { const sheetId = 'sheet-consent'; const modalId = 'modal-consent'; let showBanner = customerPrivacy.current.shouldShowBanner; const formValues: VisitorConsent = { analytics: undefined, marketing: undefined, preferences: undefined, saleOfData: undefined, }; // 2. Subscribe to customer privacy consent values and update component state when customerPrivacy changes customerPrivacy.subscribe((value) => { if (!value) { return; } showBanner = value.shouldShowBanner; const { visitorConsent: { analytics, marketing, preferences, saleOfData, }, } = value; formValues.analytics = value.visitorConsent.analytics; formValues.marketing = value.visitorConsent.marketing; formValues.preferences = value.visitorConsent.preferences; formValues.saleOfData = value.visitorConsent.saleOfData; analyticsCheckbox.updateProps({ checked: analytics, }); marketingCheckbox.updateProps({ checked: marketing, }); preferencesCheckbox.updateProps({ checked: preferences, }); saleOfDataCheckbox.updateProps({ checked: saleOfData, }); }); // 3. Set up event handlers const handleConsentChange = async ( visitorConsent?: VisitorConsent, ) => { const result = await applyTrackingConsentChange({ ...(visitorConsent ? visitorConsent : formValues), type: 'changeVisitorConsent', }); // Check if operation was successful if (result.type === 'success') { ui.overlay.close(modalId); ui.overlay.close(sheetId); } else { // Handle failure case here } }; // 4. Create consent preferences form const analyticsCheckbox = root.createComponent( Checkbox, { checked: formValues.analytics, onChange: (checked: boolean) => { formValues.analytics = checked; }, }, 'Analytics', ); const marketingCheckbox = root.createComponent( Checkbox, { checked: formValues.marketing, onChange: (checked: boolean) => { formValues.marketing = checked; }, }, 'Marketing', ); const preferencesCheckbox = root.createComponent( Checkbox, { checked: formValues.preferences, onChange: (checked: boolean) => { formValues.preferences = checked; }, }, 'Preferences', ); const saleOfDataCheckbox = root.createComponent( Checkbox, { checked: formValues.saleOfData, onChange: (checked: boolean) => { formValues.saleOfData = checked; }, }, 'Sale of data', ); const consentFormSubmitButton = root.createComponent( Button, {accessibilityRole: 'submit'}, 'Save', ); const consentForm = root.createComponent( Form, { onSubmit: () => handleConsentChange(), }, ); const consentFormBlockStack = root.createComponent(BlockStack); const consentFormGrid = root.createComponent( Grid, { spacing: 'base', }, ); consentFormGrid.appendChild( analyticsCheckbox, ); consentFormGrid.appendChild( marketingCheckbox, ); consentFormGrid.appendChild( preferencesCheckbox, ); consentFormGrid.appendChild( saleOfDataCheckbox, ); consentFormGrid.appendChild( consentFormSubmitButton, ); consentFormBlockStack.appendChild( consentFormGrid, ); consentFormBlockStack.appendChild( consentFormSubmitButton, ); consentForm.appendChild( consentFormBlockStack, ); // 5. Create modal to display consent form const modalFragment = root.createFragment(); const modal = root.createComponent( Modal, { id: modalId, padding: true, }, [consentForm], ); modalFragment.appendChild(modal); const declineButton = root.createComponent( Button, { kind: 'secondary', onPress: () => handleConsentChange({ analytics: false, marketing: false, preferences: false, saleOfData: false, }), }, 'I decline', ); const acceptButton = root.createComponent( Button, { kind: 'secondary', onPress: () => handleConsentChange({ analytics: true, marketing: true, preferences: true, saleOfData: true, }), }, 'I agree', ); const settingsButton = root.createComponent( Button, { kind: 'plain', overlay: modalFragment, }, 'Settings', ); const primaryActionFragment = root.createFragment(); primaryActionFragment.appendChild( declineButton, ); primaryActionFragment.appendChild( acceptButton, ); const secondaryActionFragment = root.createFragment(); secondaryActionFragment.appendChild( settingsButton, ); // 6. Create sheet to display privacy consent banner const sheet = root.createComponent( Sheet, { id: sheetId, defaultOpen: showBanner, accessibilityLabel: 'A sheet that collects privacy consent preferences', primaryAction: primaryActionFragment, secondaryAction: secondaryActionFragment, }, [ root.createComponent( TextBlock, undefined, [ 'This website uses cookies to ensure you get the best experience on our website test.', ' ', root.createComponent( Link, undefined, 'Privacy Policy', ), ], ), ], ); root.appendChild(sheet); }, );