window.analyzify.initGa4Gads = (ga4Obj, ga4Props, gadsProps) => { try { if (!ga4Obj || !ga4Props || !gadsProps) return; function gtag() { dataLayer.push(arguments); } const { primary: ga_primary, secondary: ga_secondary } = ga4Props; const { primary: gads_primary, secondary: gads_secondary } = gadsProps; // This flag ensures the initialization function only runs once. let pageEventsFired = false; const groups = []; const initializeAndTrackPage = () => { if (pageEventsFired) return; pageEventsFired = true; const formatTemplate = (template = 'other') => { const templateMap = { 'index': 'Homepage', 'default': template.charAt(0).toUpperCase() + template.slice(1) }; return templateMap[template] || templateMap.default; }; const result_template = formatTemplate(window.analyzify?.shopify_template); const market = window.analyzify?.market || null; const sh_info_obj = { content_group: result_template, ...window.analyzify.SSAP_vals(), page_currency: window.analyzify?.currency, implementation_type: "extension", cart_id: window.analyzify?.cart_id || null, send_page_view: false, ...window.analyzify.storeObj, market_id: market?.id?.toString() || null, market_handle: market?.handle?.toLowerCase() || null, market_language: market?.language?.toLowerCase() || null, market_country: market?.country?.toLowerCase() || null, shop_locale: window?.Shopify?.locale?.toLowerCase() || null, shop_country: window?.Shopify?.country?.toLowerCase() || null }; const groups = []; const configureGtag = (id, source, group, additionalParams = {}) => { try { const configObj = { ...sh_info_obj, analyzify_source: source, groups: group, ...additionalParams }; const customer = window.analyzify.shopify_customer; const idFormat = window.analyzify.user_id_format; const localStorageUserID = window.analyzify.getFromLocalStorage('azfy_sha256_user_id'); const localStorageEmail = window.analyzify.getFromLocalStorage('azfy_sha256_email_address'); if (idFormat === 'email') { if (customer?.sha256_email_address) configObj.user_id = customer.sha256_email_address; else if (localStorageEmail) configObj.user_id = localStorageEmail; } else { if (customer?.user_id) configObj.user_id = customer.user_id; else if (localStorageUserID) configObj.user_id = localStorageUserID; } gtag("config", id, configObj); groups.push(group); } catch (error) { console.error('Error processing configureGtag:', error); } }; if (ga4Props.primary.status) configureGtag(ga_primary.id, "analyzify_ga_primary", "analyzify_ga_primary"); if (ga4Props.secondary.id) configureGtag(ga_secondary.id, "analyzify_ga_secondary", "analyzify_ga_secondary"); if (gadsProps.primary.remarketing.status) configureGtag(gads_primary.id, "analyzify_ads_primary", "analyzify_ads_primary"); if (gadsProps.secondary.remarketing.status) configureGtag(gads_secondary.id, "analyzify_ads_secondary", "analyzify_ads_secondary"); if (window.analyzify.op_cart_data_collection && !window.analyzify.checksendcartdata_status) { window.analyzify_checksendcartdata(); } if (window.analyzify?.properties?.SERVERSIDE?.datalayer !== true) { gtag("event", "page_view", { send_to: groups, groups: groups, cart_id: window.analyzify?.cart_id || null, }); } analyzify.log('initializeAndTrackPage', 'an_ga4_gads', 'initializeAndTrackPage'); continueWith(); }; // The Consent Control Logic that calls the function above. if (window.analyzify.consent_active) { window.analyzify.consentManager.queueConsentAction((initialConsent) => { analyzify.log('consent -> queueConsentAction', 'an_ga4_gads', 'initializeAndTrackPage'); const defaultState = initialConsent || { ad_storage: 'denied', analytics_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', }; // gtag('consent', 'default', defaultState); initializeAndTrackPage(); }); window.analyzify.consentManager.onChange((newConsent) => { // gtag('consent', 'update', newConsent); analyzify.log('consent -> onChange', 'an_ga4_gads', 'initializeAndTrackPage'); initializeAndTrackPage(); }); } else { // gtag('consent', 'default', { // ad_storage: 'granted', // analytics_storage: 'granted', // ad_user_data: 'granted', // ad_personalization: 'granted', // }); initializeAndTrackPage(); } gtag("js", new Date()); function continueWith(){ const activeEvents = { ga4Primary: Object.keys(ga_primary.events).filter( (key) => ga_primary.events?.[key], ), ga4Secondary: Object.keys(ga_secondary.events).filter( (key) => ga_secondary.events?.[key], ), gadsRemPrimary: Object.keys(gads_primary.remarketing.events).filter( (key) => gads_primary.remarketing.events?.[key], ), gadsRemSecondary: Object.keys(gads_secondary.remarketing.events).filter( (key) => gads_secondary.remarketing.events?.[key], ), gadsConvPrimary: Object.keys(gads_primary.conversions).filter( (key) => gads_primary.conversions?.[key].status, ), gadsConvSecondary: Object.keys(gads_secondary.conversions).filter( (key) => gads_secondary.conversions?.[key].status, ), }; const sendMultipleDests = (eventObj) => { try { const gaItemMapper = (product, product_id_format) => { try { const variantInput = window.analyzify?.getCurrentVariant()?.id || window.analyzify.getFirstVariant(product)?.id; const variantDetails = window.analyzify.getVariantDetails(product?.variants, variantInput); const itemId = window.analyzify.getItemIds({ productObj: product, product_id_format: product_id_format, variantDetails: variantDetails, eventName: eventObj?.eventName, feedRegion: window.analyzify.feed_region }); const compareAtPrice = variantDetails?.compare_at_price || window.analyzify.formatPrice(product?.compare_at_price, true); const actualPrice = variantDetails?.price || window.analyzify.formatPrice(product?.price, true) || 0; const getDiscount = (compareAtPrice > 0 && compareAtPrice !== actualPrice) ? compareAtPrice - actualPrice : 0; const getCartDiscount = window.analyzify.formatPrice(product?.line_level_total_discount) || 0; const itemObj = { id: itemId?.selected?.toString() || itemId?.ids?.sku || itemId?.ids?.variant_id || null, item_id: itemId?.selected?.toString() || null, item_name: (product?.product_title || product?.title)?.trim() || null, item_brand: product?.vendor?.trim() || null, item_category: (product?.type || product?.product_type)?.trim() || null, item_sku: itemId?.ids?.sku?.toString() || null, item_handle: product?.handle || null, discount: window.analyzify.formatPrice(getDiscount || getCartDiscount, true), item_barcode: variantDetails?.barcode || null, quantity: Number(product?.quantity) || 1, item_variant: variantDetails?.title || product?.item_variant || product?.variant_title || null, item_variant_id: variantDetails?.id?.toString() || itemId.ids?.variant_id?.toString() || null, index: product.index || 0, item_list_id: eventObj?.eventParams?.item_list_id?.toString() || null, item_list_name: eventObj?.eventParams?.item_list_name?.trim() || null, price: variantDetails?.price || window.analyzify.formatPrice(product?.price, true), ...(ga4Props?.enhanced_params ? { tags: product?.tags?.join(',') || null, options: product?.options?.join(',') || product?.variant_options?.join(',') || null, variant_ids: product?.variants?.map((v) => { return v?.id?.toString() || null; }).join(',') || product?.variant_id?.toString() || null, } : {}), }; analyzify.log('sendMultipleDests: eventObj', 'an_ga4_gads', 'sendMultipleDests: eventObj'); analyzify.log(eventObj, 'an_ga4_gads', 'sendMultipleDests: eventObj'); analyzify.log('sendMultipleDests: itemObj', 'an_ga4_gads', 'sendMultipleDests: itemObj'); analyzify.log(itemObj, 'an_ga4_gads', 'sendMultipleDests: itemObj'); return itemObj; } catch (error) { console.error("Error processing item mapper:", error); } }; const gadsItemWrapper = (product, product_id_format, feedRegion) => { try { const variantInput = window.analyzify?.getCurrentVariant()?.id || window.analyzify.getFirstVariant(product)?.id; const variantDetails = window.analyzify.getVariantDetails(product?.variants, variantInput); const itemIds = window.analyzify.getItemIds({ productObj: product, product_id_format: product_id_format, variantDetails: variantDetails, eventName: eventObj?.eventName, feedRegion: feedRegion || window.analyzify?.feed_region || null }); return { id: itemIds?.selected || itemIds.ids?.sku || itemIds.ids?.variant_id || null, google_business_vertical: "retail", price: variantDetails?.price || product?.price || 0 }; } catch (error) { console.error("Error processing GAds item wrapper:", error); } }; analyzify.log('sendMultipleDests: gadsItemWrapper', 'an_ga4_gads', 'sendMultipleDests: gadsItemWrapper'); analyzify.log(gadsItemWrapper, 'an_ga4_gads', 'sendMultipleDests: gadsItemWrapper'); const { eventName, eventParams, items } = eventObj; analyzify.log('sendMultipleDests: eventObj', 'an_ga4_gads', 'sendMultipleDests: eventObj'); analyzify.log(eventObj, 'an_ga4_gads', 'sendMultipleDests: eventObj'); /* GA4 SCOPE */ const sendGA4Event = (ga4Props, eventName, activeEvents, sendTo) => { try { if (ga4Props?.status && ga4Props?.id) { if (eventName && activeEvents.includes(eventName)) { eventParams.items = items.map((product, index) => { return { ...gaItemMapper(product, ga4Props.product_id_format), index }; }); const { sha256_email_address, sha256_phone_number, sha256_first_name, sha256_last_name } = window.analyzify?.shopify_customer || {}; // Prepare user data object const userData = { sha256_phone_number: sha256_phone_number || null, sha256_email_address: sha256_email_address || null, address: [{ // Ensure address is an array sha256_first_name: sha256_first_name || null, sha256_last_name: sha256_last_name || null, }] }; const eventGa4Obj = { ...eventParams, send_to: ga4Props?.id, groups: sendTo, cart_id: window.analyzify?.cart_id || null, event_callback: () => { analyzify.log(`For ${ga4Props?.id}, the event "${eventName}" was triggered successfully for "${sendTo}".`, 'an_ga4_gads', 'sendGA4Event'); }, user_data: Object.keys(userData).length && window.analyzify?.shopify_customer?.type !== 'visitor' ? userData : null }; // Send the event to GA4 gtag("event", eventName, eventGa4Obj); } } } catch (error) { console.error("Error processing GA4 event:", error); } }; // Sending primary GA4 event sendGA4Event(ga4Props.primary, eventName, activeEvents.ga4Primary, "analyzify_ga_primary"); // Sending secondary GA4 event sendGA4Event(ga4Props.secondary, eventName, activeEvents.ga4Secondary, "analyzify_ga_secondary"); /* ADS SCOPE */ // Helper function to populate eccomm object const populateEccomm = (items, additionalObj) => { try { const eccomm = { ecomm_prodid: [], ecomm_prodname: [], ecomm_prodvalue: [], ecomm_totalvalue: 0, ecomm_category: [], ecomm_pagetype: window.analyzify?.shopify_template || null }; try { if (items && items.length > 0) { // Check if items has a value items.forEach((item, index) => { // Corrected the forEach parameters // Validate item properties before processing if (!item) { analyzify.log("Invalid item encountered:", item, 'an_ga4_gads', 'populateEccomm'); return; // Skip invalid items } eccomm.ecomm_prodid.push(item?.id || item?.sku || item?.item_id); eccomm.ecomm_prodname.push(item?.item_name || additionalObj?.[index]?.title || null); eccomm.ecomm_prodvalue.push(item?.price || 0); eccomm.ecomm_category.push(item?.item_category || additionalObj?.[index]?.type || null); eccomm.ecomm_totalvalue += (item?.price || 0) * (item?.quantity || 1); }); } } catch (error) { console.error("Error populating eccomm:", error); } return eccomm; } catch (error) { console.error("Error populating eccomm:", error); } }; const sendGAdsEvent = (eventName, eventParams, groups, sendTo, items) => { try { // Populate ecomm object using the provided items const eccomm = populateEccomm(items, {}); // Create the eventAdsObj with only the necessary parameters const eventAdsObj = { ...eventParams, send_to: sendTo, groups: groups, cart_id: window.analyzify?.cart_id || null, // Conditionally add ecomm parameters if they have values ...(eccomm.ecomm_prodid.length > 0 && { ecomm_prodid: eccomm.ecomm_prodid }), ...(eccomm.ecomm_prodname.length > 0 && { ecomm_prodname: eccomm.ecomm_prodname }), ...(eccomm.ecomm_prodvalue.length > 0 && { ecomm_prodvalue: eccomm.ecomm_prodvalue }), ...(eccomm.ecomm_totalvalue > 0 && { ecomm_totalvalue: window.analyzify.formatPrice(eccomm.ecomm_totalvalue, false) }), ...(eccomm.ecomm_category.length > 0 && { ecomm_category: eccomm.ecomm_category }), ...(eccomm.ecomm_pagetype && { ecomm_pagetype: eccomm.ecomm_pagetype }), event_callback: () => { analyzify.log(`Event "${eventName}" successfully triggered for "${sendTo}" with groups: ${groups}.`, 'an_ga4_gads', 'sendGAdsEvent'); }, }; gtag("event", eventName, eventAdsObj); } catch (error) { console.error("Error processing GAds event:", error); } }; const processItemsForGads = (items, product_id_format, feedRegion) => { try { return items.map((product) => gadsItemWrapper(product, product_id_format, feedRegion)); } catch (error) { console.error("Error processing items for GAds:", error); } }; const handleGAdsRMEvents = (gadsProps, eventName, activeEvents, gadsConfig, isSecondary = false) => { try { if (gadsProps.status || gadsProps.remarketing?.status) { const product_id_format = gadsConfig.remarketing.gads_remarketing_id_format; const feedRegion = gadsConfig?.feed_region || window.analyzify?.feed_region || null; const newItems = processItemsForGads(items, product_id_format, feedRegion); eventParams.items = newItems; // Populate ecomm object const eccomm = populateEccomm(newItems, items); if (eventName && activeEvents.includes(eventName)) { sendGAdsEvent(eventName, { ...eventParams, // Conditionally add ecomm parameters if they have values ...(eccomm.ecomm_prodid.length > 0 && { ecomm_prodid: eccomm.ecomm_prodid }), ...(eccomm.ecomm_prodname.length > 0 && { ecomm_prodname: eccomm.ecomm_prodname }), ...(eccomm.ecomm_prodvalue.length > 0 && { ecomm_prodvalue: eccomm.ecomm_prodvalue }), ...(eccomm.ecomm_totalvalue > 0 && { ecomm_totalvalue: window.analyzify.formatPrice(eccomm.ecomm_totalvalue, false) }), ...(eccomm.ecomm_category.length > 0 && { ecomm_category: eccomm.ecomm_category }), ...(eccomm.ecomm_pagetype && { ecomm_pagetype: eccomm.ecomm_pagetype }) }, isSecondary ? "analyzify_ads_secondary" : "analyzify_ads_primary", gadsProps.id?.toString()); } if (gadsProps.remarketing?.status && gadsProps.remarketing.events[eventName]) { if (eventName === "remove_from_cart") { sendGAdsEvent("remove_from_cart", { ...eventParams, // Conditionally add ecomm parameters if they have values ...(eccomm.ecomm_prodid.length > 0 && { ecomm_prodid: eccomm.ecomm_prodid }), ...(eccomm.ecomm_prodname.length > 0 && { ecomm_prodname: eccomm.ecomm_prodname }), ...(eccomm.ecomm_prodvalue.length > 0 && { ecomm_prodvalue: eccomm.ecomm_prodvalue }), ...(eccomm.ecomm_totalvalue > 0 && { ecomm_totalvalue: window.analyzify.formatPrice(eccomm.ecomm_totalvalue, false) }), ...(eccomm.ecomm_category.length > 0 && { ecomm_category: eccomm.ecomm_category }), ...(eccomm.ecomm_pagetype && { ecomm_pagetype: eccomm.ecomm_pagetype }) }, isSecondary ? "analyzify_ads_secondary" : "analyzify_ads_primary", gadsProps.id?.toString()); } } } } catch (error) { console.error("Error processing GAds events:", error); } }; const handleGAdsConversion = (gadsProps, eventName, activeEvents, gadsConfig, isSecondary = false) => { try { if (gadsProps?.status && gadsConfig.conversions[eventName]?.status) { // Initialize items array let items = []; if (window.analyzify.shopify_template === "product") { const getProducts = window.analyzify?.getProductObj?.product; const variantInput = window.analyzify?.getCurrentVariant()?.id || window.analyzify.getFirstVariant(getProducts)?.id; const variantDetails = window.analyzify.getVariantDetails(getProducts?.variants, variantInput); if(!getProducts || !variantDetails) return analyzify.log('Product object is not found', 'an_ga4_gads', 'handleGAdsConversion'); const itemIds = window.analyzify.getItemIds({ productObj: getProducts, product_id_format: gadsProps.product_id_format, variantDetails: variantDetails, eventName: 'view_item', feedRegion: window.analyzify.feed_region }); const compareAtPrice = variantDetails?.compare_at_price || getProducts?.compare_at_price || 0; const actualPrice = variantDetails?.price || window.analyzify.formatPrice(product?.price) || 0; const getDiscount = (compareAtPrice > 0 && compareAtPrice !== actualPrice) ? compareAtPrice - actualPrice : 0; items = [{ id: itemIds.selected, google_business_vertical: "retail", item_name: getProducts?.title?.trim() || null, item_category: getProducts?.type || (getProducts?.tags && getProducts?.tags?.length > 0 ? getProducts?.tags[0] : ""), item_brand: getProducts?.vendor?.trim() || null, item_sku: itemIds.ids.sku, discount: getDiscount || 0, item_barcode: variantDetails?.barcode || null, item_variant: variantDetails?.title?.trim() || null, item_variant_id: itemIds.ids.variant_id, price: actualPrice || 0, quantity: 1, currency: window.analyzify?.currency }]; } else if (window.analyzify.shopify_template === "cart") { const cartItems = window.analyzify?.detectedCart?.items || []; items = cartItems.map(item => { const itemIds = window.analyzify.getItemIds({ productObj: item, product_id_format: gadsProps.product_id_format, variantDetails: null, eventName: 'view_cart', feedRegion: window.analyzify.feed_region }); const getDiscount = Array.isArray(item?.line_level_discount_allocations) ? item.line_level_discount_allocations.reduce( (total, item) => total + (Number(item.amount) || 0), 0 ) : 0; return { id: itemIds.selected, google_business_vertical: "retail", item_name: item?.product_title?.trim() || item?.title?.trim() || null, item_category: item?.product_type || (item?.tags && item?.tags?.length > 0 ? item?.tags[0] : ""), item_brand: item?.vendor?.trim() || null, item_sku: itemIds.ids.sku, discount: window.analyzify.formatPrice(getDiscount) || 0, item_variant: item?.variant_title?.trim() || null, item_variant_id: itemIds.ids.variant_id, price: window.analyzify.formatPrice(item?.line_price || item?.price) || 0, quantity: item?.quantity || 1, currency: window.analyzify?.currency }; }); } // Check if items exist and proceed with conversion if (items?.length > 0) { if ( eventName && activeEvents.includes(eventName) && gadsConfig.id && gadsConfig.conversions[eventName].value ) { const { sha256_email_address, sha256_phone_number, sha256_first_name, sha256_last_name } = window.analyzify?.shopify_customer || {}; // Prepare user data object const userData = { sha256_phone_number: sha256_phone_number || null, sha256_email_address: sha256_email_address || null, address: [{ // Ensure address is an array sha256_first_name: sha256_first_name || null, sha256_last_name: sha256_last_name || null, }] }; const convObj = { ...eventParams, send_to: `${gadsConfig.id}/${gadsConfig.conversions[eventName].value}`, items: items, event_callback: () => { analyzify.log(`Conversion event successfully sent to: ${gadsConfig.id}/${gadsConfig.conversions[eventName].value}`, 'an_ga4_gads', 'handleGAdsConversion'); }, user_data: Object.keys(userData).length && window.analyzify?.shopify_customer?.type !== 'visitor' ? userData : null, new_customer: Object.keys(userData).length ? window.analyzify?.shopify_customer?.orders_count > 0 ? false : true : null, }; gtag("event", "conversion", convObj); } } else { analyzify.log("No items found for conversion event.", 'an_ga4_gads', 'handleGAdsConversion'); } } } catch (error) { console.error("Error processing GAds conversion:", error); } }; // Handle primary events handleGAdsRMEvents(gadsProps.primary, eventName, activeEvents.gadsRemPrimary, gads_primary); handleGAdsConversion(gadsProps.primary, eventName, activeEvents.gadsConvPrimary, gads_primary); // Handle secondary events handleGAdsRMEvents(gadsProps.secondary, eventName, activeEvents.gadsRemSecondary, gads_secondary, true); handleGAdsConversion(gadsProps.secondary, eventName, activeEvents.gadsConvSecondary, gads_secondary, true); } catch (error) { console.error("Error processing GAds events:", error); } }; if (window.analyzify.shopify_customer) { const { user_id, id, sha256_user_id, sha256_email_address, first_name, last_name, email_address, phone_number, orders_count = 0, total_spent = 0, sha256_first_name, sha256_last_name, type = 'visitor' } = analyzify.shopify_customer; const { user_id_format = 'cid', send_user_id = false } = window.analyzify || {}; const userProperties = type === 'member' ? { first_name: first_name || null, last_name: last_name || null, id: id || null, sha256_user_id: sha256_user_id || null, sha256_first_name: sha256_first_name || null, sha256_last_name: sha256_last_name || null, sha256_email_address: sha256_email_address || null, type: type || null, email_address: email_address || null, phone_number: phone_number || null, orders_count: orders_count || 0, total_spent: total_spent || null } : { type }; analyzify.log('userProperties', 'an_ga4_gads', 'userProperties'); analyzify.log(userProperties, 'an_ga4_gads', 'userProperties'); if ( userProperties?.type === "member" && ( userProperties?.sha256_email_address === undefined || userProperties?.sha256_email_address === null ) ) { analyzify.log(`User properties are incomplete for a ${userProperties?.type}.`, 'an_ga4_gads', 'userProperties'); // Check if analyzify.shopify_customer has a valid sha256_email_address if (analyzify?.shopify_customer?.sha256_email_address) { gtag("set", "user_properties", userProperties || analyzify?.shopify_customer); if (send_user_id) { const userId = user_id_format === 'email' ? analyzify?.shopify_customer?.sha256_email_address : user_id_format === 'hashed_cid' ? analyzify?.shopify_customer?.sha256_user_id : analyzify?.shopify_customer?.user_id || null; if (userId) gtag("set", "user_id", userId); } } else { let attempts = 0; const maxAttempts = 3; const intervalTime = 1000; // 1 second const intervalId = setInterval(() => { if ( userProperties?.type === "member" && userProperties?.sha256_email_address !== undefined && userProperties?.sha256_email_address !== null ) { gtag("set", "user_properties", userProperties || analyzify?.shopify_customer); if (send_user_id) { const userId = user_id_format === 'email' ? analyzify?.shopify_customer?.sha256_email_address : user_id_format === 'hashed_cid' ? analyzify?.shopify_customer?.sha256_user_id : analyzify?.shopify_customer?.user_id || null; if (userId) gtag("set", "user_id", userId); } clearInterval(intervalId); // Clear the interval once successful } else { attempts++; if (attempts >= maxAttempts) { analyzify.log("Failed to set user_properties after 3 attempts.", 'an_ga4_gads', 'userProperties'); clearInterval(intervalId); // Clear the interval after max attempts gtag("set", "user_properties", analyzify?.shopify_customer || userProperties || {}); if (send_user_id) { const userId = user_id_format === 'email' ? analyzify?.shopify_customer?.sha256_email_address : user_id_format === 'hashed_cid' ? analyzify?.shopify_customer?.sha256_user_id : analyzify?.shopify_customer?.user_id || null; if (userId) gtag("set", "user_id", userId); } } } }, intervalTime); } } else { gtag("set", "user_properties", userProperties); if (send_user_id) { const userId = user_id_format === 'email' ? analyzify?.shopify_customer?.sha256_email_address : user_id_format === 'hashed_cid' ? analyzify?.shopify_customer?.sha256_user_id : analyzify?.shopify_customer?.user_id || null; if (userId) gtag("set", "user_id", userId); } } document.addEventListener('userDataReady', (event) => { analyzify.log('userDataReady', 'an_ga4_gads', 'userDataReady'); analyzify.log(event.detail, 'an_ga4_gads', 'userDataReady'); }); } else { analyzify.log('shopify_customer is not ready.', 'an_ga4_gads', 'userProperties'); } // add_to_cart window.analyzify.gaAddToCart = (productObj, currentVariant) => { try { if (!productObj) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaAddToCart'); let { product, variant, collection } = productObj; if(!product) product = productObj; const addedItem = { ...product }; const firstVariant = window.analyzify.getFirstVariant(product); const variantDetails = window.analyzify.getVariantDetails(product?.variants, currentVariant || variant?.id || firstVariant?.id); const prodQty = product?.quantity || analyzify.findQuantity() || 1; if (!variantDetails) { return analyzify.log(`Variant with id ${variant?.id} not found`, 'an_ga4_gads', 'gaAddToCart'); } addedItem.item_variant_id = variantDetails?.id; addedItem.price = variantDetails?.price; addedItem.item_sku = variantDetails?.sku; addedItem.item_variant = variantDetails?.public_title || variantDetails?.title; addedItem.quantity = prodQty; addedItem.index = 0; if (collection) addedItem.item_list_id = collection?.id || null; if (collection?.title) addedItem.item_list_name = collection?.title || null; const multipleDestsObj = { eventName: "add_to_cart", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(variantDetails?.price * prodQty || 0, false), cart_id: window.analyzify?.cart_id || null, }, items: [addedItem], }; sendMultipleDests(multipleDestsObj); analyzify.log("Product add_to_cart", 'an_ga4_gads', 'gaAddToCart'); analyzify.log(window.dataLayer, 'an_ga4_gads', 'gaAddToCart'); } catch (error) { console.error("Error processing gaAddToCart:", error); } }; window.analyzify.gaAddToWishlist = (productObj) => { try { if (!productObj) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaAddToWishlist'); let { product, variant, collection } = productObj; if(!product) product = productObj; const wishedItem = { ...product }; const firstVariant = window.analyzify.getFirstVariant(product); const variantDetails = window.analyzify.getVariantDetails(product?.variants, variant?.id || firstVariant?.id); if (!variantDetails) { return analyzify.log(`Variant with id ${variant?.id} not found`, 'an_ga4_gads', 'gaAddToWishlist'); } wishedItem.item_variant_id = variantDetails?.id; wishedItem.price = variantDetails?.price; wishedItem.item_sku = variantDetails?.sku; wishedItem.item_variant = variantDetails?.public_title || variantDetails?.title const prodQty = analyzify.findQuantity() || 1; wishedItem.quantity = prodQty; wishedItem.index = 0; if (collection) wishedItem.item_list_id = collection?.id || null; if (collection?.title) wishedItem.item_list_name = collection?.title || null; const multipleDestsObj = { eventName: "add_to_wishlist", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(variantDetails?.price * prodQty || 0, false), cart_id: window.analyzify?.cart_id || null, }, items: [wishedItem], }; sendMultipleDests(multipleDestsObj); analyzify.log("Product add_to_wishlist", 'an_ga4_gads', 'gaAddToWishlist'); analyzify.log(window.dataLayer, 'an_ga4_gads', 'gaAddToWishlist'); } catch (error) { console.error("Error processing gaAddToWishlist:", error); } }; window.analyzify.gaBeginCheckout = (cartObj) => { try { if(!cartObj) return analyzify.log('Cart object is not found', 'an_ga4_gads', 'gaBeginCheckout'); if(!cartObj?.items) return analyzify.log('Cart items are not found', 'an_ga4_gads', 'gaBeginCheckout'); const multipleDestsObj = { eventName: "begin_checkout", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(cartObj?.total_price, true), total_quantity: Number(cartObj?.item_count), total_items: cartObj?.items?.length, cart_id: cartObj?.token.split('?')[0] || window.analyzify?.cart_id || null, }, items: cartObj?.items?.map(item => ({ ...item, price: window.analyzify.formatPrice(item.price, true) })), }; sendMultipleDests(multipleDestsObj); analyzify.log('multipleDestsObj: begin_checkout', 'an_ga4_gads', 'gaBeginCheckout'); analyzify.log(multipleDestsObj, 'an_ga4_gads', 'gaBeginCheckout'); } catch (error) { console.error("Error processing gaBeginCheckout:", error); } }; window.analyzify.gaHeroBannerClick = (hbElement) => { try { const allChildren = Array.from(hbElement.children); const targetChild = allChildren.find((sibling) => { const titleElement = analyzify.findElemInPath( Array.from(sibling.children).flatMap((child) => Array.from(child.children), ), analyzify.hero_banner_title_attributes, ); const subtitleElement = analyzify.findElemInPath( Array.from(sibling.children).flatMap((child) => Array.from(child.children), ), analyzify.hero_banner_subtitle_attributes, ); const ctaElement = analyzify.findElemInPath( Array.from(sibling.children).flatMap((child) => Array.from(child.children), ), analyzify.hero_banner_cta_attributes, ); const link = path.find( (element) => (element.tagName === "A" || element.tagName === "BUTTON") && element.href, ); if ((titleElement || subtitleElement) && link) { const heroBannerClickObj = { send_to: groups, heading: titleElement ? titleElement.textContent.trim().substring(0, 100) : null, description: subtitleElement ? subtitleElement.textContent.trim().substring(0, 100) : null, cta_title: ctaElement && link ? ctaElement.textContent.trim().substring(0, 100) : null, cta_url: link ? link.href : null, }; gtag("event", "hero_banner_click", heroBannerClickObj); analyzify.log('heroBannerClickObj', 'an_ga4_gads', 'gaHeroBannerClick'); analyzify.log(heroBannerClickObj, 'an_ga4_gads', 'gaHeroBannerClick'); } return titleElement || subtitleElement; }); } catch (error) { console.error("Error processing gaHeroBannerClick:", error); } }; window.analyzify.gaProductDetailAccordion = (pdaElement) => { try { const multipleDestsObj = { send_to: groups, title: pdaElement.textContent.replace(/\s+/g, " ").trim() || null, }; gtag("event", "product_detail_accordion", multipleDestsObj); analyzify.log('multipleDestsObj: product_detail_accordion', 'an_ga4_gads', 'gaProductDetailAccordion'); analyzify.log(multipleDestsObj, 'an_ga4_gads', 'gaProductDetailAccordion'); } catch (error) { console.error("Error processing gaProductDetailAccordion:", error); } }; window.analyzify.gaDisclosureChange = (disclosureElement) => { try { const multipleDestsObj = { send_to: groups, data_value: disclosureElement ? disclosureElement.hasAttribute("data-value") ? disclosureElement.getAttribute("data-value").trim() : null : null, selected_option: disclosureElement ? disclosureElement.textContent.replace(/\s+/g, " ").trim() : null, type: disclosureElement .closest("form") .classList.contains("localization-form") ? "localization-form" : null, }; gtag("event", "disclosure_changed", multipleDestsObj); analyzify.log('multipleDestsObj: disclosure_changed', 'an_ga4_gads', 'gaDisclosureChange'); analyzify.log(multipleDestsObj, 'an_ga4_gads', 'gaDisclosureChange'); } catch (error) { console.error("Error processing gaDisclosureChange:", error); } }; // nav_click window.analyzify.gaNavClick = (nav_elem, navTitle) => { try { if (!nav_elem) return analyzify.log("No navigation element found.", 'an_ga4_gads', 'gaNavClick'); const tagName = nav_elem.tagName; const type = window.analyzify.getTypeFromTag(tagName); const title = nav_elem.innerText.trim().split("\n")[0] || ""; let url = null; // Step 1: Check the element itself for data attributes or href if (nav_elem.hasAttribute("data-url") || nav_elem.hasAttribute("data-link")) { url = nav_elem.getAttribute("data-url") || nav_elem.getAttribute("data-link"); } else if (nav_elem.hasAttribute("href")) { url = nav_elem.getAttribute("href"); } else { // Step 2: Look for various common elements that might contain URLs // Check for any summary elements with data attributes const summaryElements = nav_elem.querySelectorAll('summary[data-link], summary[data-url]'); if (summaryElements.length > 0) { url = summaryElements[0].getAttribute("data-link") || summaryElements[0].getAttribute("data-url"); } // If still no URL, check for anchor tags if (!url) { const anchorElements = nav_elem.querySelectorAll('a[href]'); if (anchorElements.length > 0) { url = anchorElements[0].href; } } // If still no URL, check parent element if (!url) { const parent = nav_elem.parentElement; if (parent?.hasAttribute("href")) { url = parent.getAttribute("href"); } else if (parent?.hasAttribute("data-url") || parent?.hasAttribute("data-link")) { url = parent.getAttribute("data-url") || parent.getAttribute("data-link"); } } // If still no URL, check for closest elements with relevant attributes if (!url) { const closestAnchor = nav_elem.closest("a[href]"); if (closestAnchor) { url = closestAnchor.href; } else { const closestDataLink = nav_elem.closest("[data-url], [data-link]"); if (closestDataLink) { url = closestDataLink.getAttribute("data-url") || closestDataLink.getAttribute("data-link"); } } } } const navObj = { send_to: groups, nav: { position: navTitle, type, title, url }, }; if(ga4Props.status &&ga4Props.primary.status && ga4Props.primary.events.nav_click){ navObj.send_to = ga4Props.primary.id; gtag("event", "nav_click", navObj); } if(ga4Props.status && ga4Props.secondary.status && ga4Props.secondary.events.nav_click){ navObj.send_to = ga4Props.secondary.id; gtag("event", "nav_click", navObj); } analyzify.log(`navObj: nav_click -> ${JSON.stringify(navObj)}`, 'an_ga4_gads', 'gaNavClick'); } catch (error) { console.error("Error processing gaNavClick:", error); } }; // remove_from_cart window.analyzify.gaRebuyRfc = (productObj) => { try { if (!productObj) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaRebuyRfc'); analyzify.log('productObj: gaRebuyRfc', 'an_ga4_gads', 'gaRebuyRfc'); analyzify.log(productObj, 'an_ga4_gads', 'gaRebuyRfc'); const multipleDestsObj = { eventName: "remove_from_cart", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(productObj.price, false) * productObj.quantity, cart_id: window.analyzify?.cart_id || null, }, items: [productObj], }; sendMultipleDests(multipleDestsObj); } catch (error) { console.error("Error processing gaRebuyRfc:", error); } }; // select_item window.analyzify.gaSelectItem = (productObj) => { try { if (!productObj) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaSelectItem'); analyzify.log('productObj: gaSelectItem', 'an_ga4_gads', 'gaSelectItem'); analyzify.log(productObj, 'an_ga4_gads', 'gaSelectItem'); const collection = window.analyzify.getCollectionObj; const firstVariant = window.analyzify.getFirstVariant(productObj); const multipleDestsObj = { eventName: "select_item", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(firstVariant?.price || productObj?.price, true), item_list_id: collection ? collection?.id : null, item_list_name: collection ? collection?.title : null, cart_id: window.analyzify?.cart_id || null, }, items: [productObj], }; sendMultipleDests(multipleDestsObj); } catch (error) { console.error("Error processing gaSelectItem:", error); } }; if (window.analyzify.shopify_template == "collection") { // view_item_list window.analyzify.gaViewItemList = () => { try { const { products, id, title, handle } = ga4Obj.getCollectionObj; if(!products) return analyzify.log('Products are not found', 'an_ga4_gads', 'gaViewItemList'); if(ga4Props?.multiple_view_item_list) { const chunkSize = ga4Obj?.chunk_size; const itemsChunks = products.length > chunkSize ? products.map((item, index) => ({ ...item, index: index })).reduce((resultArray, item, index) => { const chunkIndex = Math.floor(index/chunkSize); if(!resultArray[chunkIndex]) { resultArray[chunkIndex] = []; } resultArray[chunkIndex].push(item); return resultArray; }, []) : [products.map((item, index) => ({ ...item, index: index }))]; itemsChunks.forEach((chunk, chunkIndex) => { const multipleDestsObj = { eventName: "view_item_list", eventParams: { item_list_id: id ? id : null, item_list_name: title ? title : null, value: window.analyzify.formatPrice(products.reduce((acc, curr) => acc + window.analyzify.formatPrice(curr.price), 0), true), currency: window.analyzify?.currency, total_quantity: products.length || 1, total_items: products.length || 1, cart_id: window.analyzify?.cart_id || null, }, items: chunk || [], }; window.analyzify.collection = { id: id ? id : null, title: title ? title : null, handle: handle ? handle : null, } sendMultipleDests(multipleDestsObj); }); } else { const multipleDestsObj = { eventName: "view_item_list", eventParams: { item_list_id: id ? id : null, item_list_name: title ? title : null, value: window.analyzify.formatPrice(products.reduce((acc, curr) => acc + window.analyzify.formatPrice(curr.price), 0), true), currency: window.analyzify?.currency, total_quantity: products.length || 1, total_items: products.length || 1, cart_id: window.analyzify?.cart_id || null, }, items: products || [], }; window.analyzify.collection = { id: id ? id : null, title: title ? title : null, handle: handle ? handle : null, } sendMultipleDests(multipleDestsObj); } } catch (error) { console.error("Error processing gaViewItemList:", error); } }; analyzify.gaViewItemList(); } else if (window.analyzify.shopify_template == "product") { const { getProductObj } = ga4Obj; // view_item window.analyzify.gaViewItem = (productObj, variantId) => { try { if (!productObj) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaViewItem'); const { product, variant } = productObj; if(!product) return analyzify.log('Product object is not found', 'an_ga4_gads', 'gaViewItem'); const variantInput = variantId || window.analyzify?.getCurrentVariant()?.id || variant?.id; const variantDetails = window.analyzify.getVariantDetails(product?.variants, variantInput); const ecommerce = { currency: window.analyzify?.currency || null, value: window.analyzify.formatPrice(variantDetails?.price, false), }; const multipleDestsObj = { eventName: "view_item", eventParams: ecommerce, cart_id: window.analyzify?.cart_id || null, items: [product] }; sendMultipleDests(multipleDestsObj); window.analyzify.gadsRemViewItem = (product) => { try { const ecommerce = { currency: window.analyzify?.currency || null, value: window.analyzify.formatPrice(firstVariant?.price, false), }; const multipleDestsObj = { eventName: "view_item", eventParams: ecommerce, cart_id: window.analyzify?.cart_id || null, items: [product], }; analyzify.log('multipleDestsObj: view_item', 'an_ga4_gads', 'gadsRemViewItem'); analyzify.log(multipleDestsObj, 'an_ga4_gads', 'gadsRemViewItem'); sendMultipleDests(multipleDestsObj); } catch (error) { console.error("Error processing gadsRemViewItem:", error); } }; } catch (error) { console.error("Error processing gaViewItem:", error); } }; analyzify.gaViewItem(getProductObj); // variant_changed window.analyzify.gaVariantChange = (variantData) => { try { if (!variantData) return analyzify.log('Variant data is not found', 'an_ga4_gads', 'gaVariantChange'); const { product } = window.analyzify.getProductObj; if(!product) return analyzify.log('Product object is not found', 'an_ga4_gads', 'gaVariantChange'); const selectedVariant = product?.variants?.find((variant) => variant.id.toString() === variantData.id.toString()); if(!selectedVariant) return analyzify.log('Selected variant is not found', 'an_ga4_gads', 'gaVariantChange'); const variantDetails = window.analyzify.getVariantDetails(product?.variants, selectedVariant?.id); if(!variantDetails) return analyzify.log('Variant details are not found', 'an_ga4_gads', 'gaVariantChange'); const variantObj = { variant_id: variantDetails?.id?.toString() || null, variant_title: variantDetails?.title || null, product_price: window.analyzify.formatPrice(variantDetails?.price, false), product_sku: variantDetails?.sku || null, product_id: product?.id || null, product_title: product?.title || null, cart_id: window.analyzify?.cart_id || null, variant_availability: selectedVariant?.available || false, }; if(!variantObj) return analyzify.log('Multiple destinations object is not found', 'an_ga4_gads', 'gaVariantChange'); console.log('ga4Props', ga4Props); console.log('ga4Props.primary.events.variant_changed', ga4Props.primary.events.variant_changed); console.log('ga4Props.secondary.events.variant_changed', ga4Props.secondary.events.variant_changed); if(ga4Props.status &&ga4Props.primary.status && ga4Props.primary.events.variant_changed){ variantObj.send_to = ga4Props.primary.id; gtag("event", "variant_changed", variantObj); } if(ga4Props.status && ga4Props.secondary.status && ga4Props.secondary.events.variant_changed){ variantObj.send_to = ga4Props.secondary.id; gtag("event", "variant_changed", variantObj); } if(ga4Props.status &&ga4Props.primary.status && ga4Props.primary.events.variant_changed && ga4Obj.variant_changed_with_view_item){ window.analyzify.gaViewItem(window.analyzify.getProductObj, selectedVariant?.id); } if(ga4Props.status && ga4Props.secondary.status && ga4Props.secondary.events.variant_changed && ga4Obj.variant_changed_with_view_item){ window.analyzify.gaViewItem(window.analyzify.getProductObj, selectedVariant?.id); } analyzify.log('variantObj: variant_changed', 'an_ga4_gads', 'gaVariantChange'); analyzify.log(variantObj, 'an_ga4_gads', 'gaVariantChange'); } catch (error) { console.error("Error processing gaVariantChange:", error); } }; analyzify.gaVariantChange(getProductObj.product); } else if (window.analyzify.shopify_template == "cart") { window.analyzify.gaViewCart = (cartObj) => { try { if (!cartObj) return analyzify.log('Cart object is not found', 'an_ga4_gads', 'gaViewCart'); if (cartObj?.items?.length == 0) return; const ecommerce = { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(cartObj?.total_price, true), cart_id: window.analyzify?.cart_id || null, total_quantity: Number(cartObj.item_count), total_items: cartObj.items.length, }; const multipleDestsObj = { eventName: "view_cart", eventParams: ecommerce, items: cartObj?.items, }; sendMultipleDests(multipleDestsObj); } catch (error) { console.error("Error processing gaViewCart:", error); } }; window.analyzify.gaViewCart(window.analyzify?.detectedCart); } else if (window.analyzify.shopify_template == "search") { // Search related view_item_list scope window.analyzify.gaSearch = (searchObj) => { try { const { term, products, resultsCount } = searchObj; gtag("event", "search", { send_to: groups, search_term: term }); const multipleDestsObj = { eventName: "view_item_list", eventParams: { item_list_id: "search_results", item_list_name: `Search Results: ${term}`, value: window.analyzify.formatPrice(products.reduce((acc, curr) => acc + window.analyzify.formatPrice(curr?.price), 0), true), currency: window.analyzify?.currency, total_quantity: resultsCount || 1, total_items: resultsCount || 1, cart_id: window.analyzify?.cart_id || null, }, items: products ? products : [], }; sendMultipleDests(multipleDestsObj); } catch (error) { console.error("Error processing searchHandle:", error); } }; analyzify.gaSearch(ga4Obj.getSearchObj); } // remove from cart window.analyzify.gaRemoveFromCart = (product) => { try { if (product) { if (!product) return analyzify.log("Product object is not found", 'an_ga4_gads', 'gaRemoveFromCart'); analyzify.log('productObj: gaRemoveFromCart', 'an_ga4_gads', 'gaRemoveFromCart'); analyzify.log(product, 'an_ga4_gads', 'gaRemoveFromCart'); const price = window.analyzify.formatPrice(product?.price || 0, false); const quantity = product?.quantity || 1; const totalPrice = price * quantity || 0; const multipleDestsObj = { eventName: "remove_from_cart", eventParams: { currency: window.analyzify?.currency, value: window.analyzify.formatPrice(totalPrice, false), cart_id: window.analyzify?.cart_id || null, }, items: [product], }; sendMultipleDests(multipleDestsObj); analyzify.log('multipleDestsObj: remove_from_cart', 'an_ga4_gads', 'gaRemoveFromCart'); analyzify.log(multipleDestsObj, 'an_ga4_gads', 'gaRemoveFromCart'); } } catch (error) { console.error("Error processing gaRemoveFromCart:", error); } }; if (window.analyzify.properties.GA4.primary.ga4_klaviyo_subscribe || window.analyzify.properties.GA4.secondary.ga4_klaviyo_subscribe) { window.analyzify.klaviyoSubscribe = (formData) => { try { gtag("event", "klaviyo_subscribe", { send_to: groups, ...formData }); analyzify.log('klaviyo_subscribe form data', 'an_ga4_gads', 'klaviyoSubscribe'); analyzify.log(formData, 'an_ga4_gads', 'klaviyoSubscribe'); } catch (error) { console.error("Error processing klaviyoSubscribe:", error); } }; } if (window.analyzify.properties.GA4.primary.ga4_klaviyo_subscribe || window.analyzify.properties.GA4.secondary.ga4_klaviyo_subscribe) { window.addEventListener("klaviyoForms", function (e) { try { if (e.detail.type == 'submit') { const formData = { formId: e.detail.formId, formTitle: e.detail.metaData.$source, cart_id: window.analyzify?.cart_id || null, }; analyzify.klaviyoSubscribe(formData); analyzify.log('klaviyoForms form data', 'an_ga4_gads', 'klaviyoForms'); analyzify.log(formData, 'an_ga4_gads', 'klaviyoForms'); } } catch (error) { console.error("Error processing klaviyoForms:", error); } }); } window.analyzify.submitContactForm = (formData) => { try { if (window.analyzify.properties.GA4.primary.ga4_contact_form || window.analyzify.properties.GA4.secondary.ga4_contact_form) { window.addEventListener("submit", (event) => { const formDataObj = new FormData(event.target); if (!formDataObj.get('contact[email]')) { return; } const formDataPairs = {}; for (const [key] of formDataObj.entries()) { formDataPairs[key] = formDataObj.get(key); } if (formDataPairs['form_type'] == 'contact') { const contactObj = { send_to: groups, eventParams: { method: 'contactForm', cart_id: window.analyzify?.cart_id || null, }, ...formDataPairs }; gtag("event", "contactForm", contactObj); analyzify.log("contactObj", 'an_ga4_gads', 'contactForm'); analyzify.log(contactObj, 'an_ga4_gads', 'contactForm'); } }); } } catch (error) { console.error("Error processing contact form:", error); } } window.analyzify.submitNewsletterForm = (formData) => { try { if (window.analyzify.properties.GA4.primary.ga4_newsletter || window.analyzify.properties.GA4.secondary.ga4_newsletter) { window.addEventListener("submit", (event) => { const formDataObj = new FormData(event.target); if (!formDataObj.get('contact[email]')) { return; } const formDataPairs = {}; for (const [key] of formDataObj.entries()) { formDataPairs[key] = formDataObj.get(key); } if (formDataPairs['form_type'] == 'customer') { const newsletterObj = { send_to: groups, eventParams: { method: 'newsletter', cart_id: window.analyzify?.cart_id || null, }, ...formDataPairs }; gtag("event", "newsletter", newsletterObj); analyzify.log("newsletterObj", 'an_ga4_gads', 'newsletterForm'); analyzify.log(newsletterObj, 'an_ga4_gads', 'newsletterForm'); } }) } } catch (error) { console.error("Error processing newsletter form:", error); } } analyzify.log('continueWith', 'an_ga4_gads', 'continueWith'); } // Ending of the an_ga4_gads js function } catch (error) { console.error("Error processing an_ga4_gads:", error); } };