Skip to content

Commit

Permalink
Auto cookie domain detect and update analytics error message (#2256)
Browse files Browse the repository at this point in the history
Co-authored-by: Bret Little <[email protected]>
  • Loading branch information
wizardlyhel and blittle authored Jun 18, 2024
1 parent c3baf78 commit 6cd5554
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 48 deletions.
5 changes: 5 additions & 0 deletions .changeset/stupid-falcons-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Auto cookie domain detection for customer privacy api and better error message for missing analytics fields
2 changes: 1 addition & 1 deletion packages/hydrogen/src/analytics-manager/CartAnalytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {flattenConnection} from '@shopify/hydrogen-react';
function logMissingField(fieldName: string) {
// eslint-disable-next-line no-console
console.error(
`[h2:error:CartAnalytics] Can't set up cart analytics events because the \`cart.${fieldName}\` value is missing from your GraphQL cart query. In standard Hydrogen projects, the cart query is contained in \`app/lib/fragments.js\`. Make sure it includes \`cart.${fieldName}\`. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L59.`,
`[h2:error:CartAnalytics] Can't set up cart analytics events because the \`cart.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartApiQuery on Cart\` is defined and make sure \`${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L59.`,
);
}

Expand Down
66 changes: 30 additions & 36 deletions packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,7 @@ function productViewHandler(payload: ProductViewPayload) {
if (
eventPayload &&
validateProducts({
eventName: PRODUCT_VIEWED,
productField: 'products',
variantField: 'product.<displayed_variant>',
fromSource: 'product_viewed products array',
type: 'product',
products: payload.products,
})
) {
Expand Down Expand Up @@ -318,10 +315,7 @@ function sendCartAnalytics({
};
if (
validateProducts({
eventName: ADD_TO_CART,
productField: 'merchandise.product',
variantField: 'merchandise',
fromSource: 'cart query',
type: 'cart',
products: [product],
})
) {
Expand All @@ -335,17 +329,27 @@ function sendCartAnalytics({
}
}

const PRODUCT_VIEWED = 'Product viewed';
const ADD_TO_CART = 'Add to cart';
function missingErrorMessage(
eventName: string,
missingFieldName: string,
fromSource: string,
type: 'cart' | 'product',
fieldName: string,
isVariantField: boolean,
viewKeyName?: string,
) {
// eslint-disable-next-line no-console
console.error(
`[h2:error:ShopifyAnalytics] ${eventName}: ${missingFieldName} is required from the ${fromSource}.`,
);
if (type === 'cart') {
const name = `${
isVariantField ? 'merchandise' : 'merchandise.product'
}.${fieldName}`;
// eslint-disable-next-line no-console
console.error(
`[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${name}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${name}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`,
);
} else {
const name = `${viewKeyName || fieldName}`;
// eslint-disable-next-line no-console
console.error(
`[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${name}\` is missing from your \`<Analytics.ProductView>\`. Make sure \`${name}\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`,
);
}
}

// Product expected field and types:
Expand All @@ -360,50 +364,40 @@ function missingErrorMessage(
// category: string, optional
// quantity: float
function validateProducts({
eventName,
productField,
variantField,
type,
products,
fromSource,
}: {
eventName: string;
productField: string;
variantField: string;
fromSource: string;
type: 'cart' | 'product';
products: Array<Record<string, unknown>>;
}) {
if (!products || products.length === 0) {
missingErrorMessage(eventName, `${productField}`, fromSource);
missingErrorMessage(type, '', false, 'data.products');
return false;
}

products.forEach((product) => {
if (!product.id) {
missingErrorMessage(eventName, `${productField}.id`, fromSource);
missingErrorMessage(type, 'id', false);
return false;
}
if (!product.title) {
missingErrorMessage(eventName, `${productField}.title`, fromSource);
missingErrorMessage(type, 'title', false);
return false;
}
if (!product.price) {
missingErrorMessage(
eventName,
`${variantField}.price.amount`,
fromSource,
);
missingErrorMessage(type, 'price.amount', true, 'price');
return false;
}
if (!product.vendor) {
missingErrorMessage(eventName, `${productField}.vendor`, fromSource);
missingErrorMessage(type, 'vendor', false);
return false;
}
if (!product.variantId) {
missingErrorMessage(eventName, `${variantField}.id`, fromSource);
missingErrorMessage(type, 'id', true, 'variantId');
return false;
}
if (!product.variantTitle) {
missingErrorMessage(eventName, `${variantField}.title`, fromSource);
missingErrorMessage(type, 'title', true, 'variantTitle');
return false;
}
});
Expand Down
41 changes: 30 additions & 11 deletions packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,26 +143,46 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) {
if (scriptStatus !== 'done' || loadedEvent.current) return;
loadedEvent.current = true;

if (!consentConfig.checkoutDomain) logMissingConfig('checkoutDomain');
if (!consentConfig.storefrontAccessToken)
logMissingConfig('storefrontAccessToken');
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 (
consentConfig.storefrontAccessToken.startsWith('shpat_') ||
consentConfig.storefrontAccessToken.length !== 32
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`,
);
}

if (withPrivacyBanner && window?.privacyBanner) {
window?.privacyBanner?.loadBanner({
checkoutRootDomain: consentConfig.checkoutDomain,
storefrontAccessToken: consentConfig.storefrontAccessToken,
const config: CustomerPrivacyConsentConfig = {
checkoutRootDomain: checkoutDomain,
storefrontAccessToken,
};

if (checkoutDomain) {
let storefrontRootDomain = window.document.location.host;
const checkoutDomainParts = checkoutDomain.split('.').reverse();
const currentDomainParts = storefrontRootDomain.split('.').reverse();
const sameDomainParts: Array<string> = [];
checkoutDomainParts.forEach((part, index) => {
if (part === currentDomainParts[index]) {
sameDomainParts.push(part);
}
});

storefrontRootDomain = sameDomainParts.reverse().join('.');

if (storefrontRootDomain) {
config.storefrontRootDomain = storefrontRootDomain;
}
}

if (withPrivacyBanner && window?.privacyBanner) {
window.privacyBanner?.loadBanner(config);
}

if (!window.Shopify?.customerPrivacy) return;
Expand All @@ -179,8 +199,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) {
{
...consent,
headlessStorefront: true,
checkoutRootDomain: consentConfig.checkoutDomain,
storefrontAccessToken: consentConfig.storefrontAccessToken,
...config,
},
callback,
);
Expand Down

0 comments on commit 6cd5554

Please sign in to comment.