(function(){ const zoovuId = 'a9siHhCZcQn3ZIlJfn7abL7t99nnMwqHLhs27K5GUwU='; const domainId = '5017a5e0-f09d-46fe-9541-74aa13f99524'; const variables = [{"id":"a5881501-614d-4226-82ce-58fbb39eb40e","name":"Add to cart target url","type":"FUNCTION","valueType":"TEXT","function":function(event){return window.location.href.replace(window.location.origin, '') /* */},"scope":"LOCAL"},{"id":"17288887-bfdf-49b1-95b1-b30404e6aee6","name":"Clickout Label - add product from PLP","type":"CONSTANT","valueType":"TEXT","value":"Clickout, add product from PLP search result","scope":"LOCAL"},{"id":"39bbfe16-720b-4d45-ba8a-79c874321c6e","name":"Clickout Label - category click","type":"CONSTANT","valueType":"TEXT","value":"Clickout, category","scope":"LOCAL"},{"id":"2d131731-66b0-43db-832b-5831cf4218d6","name":"Clickout Label - go to PDP","type":"CONSTANT","valueType":"TEXT","value":"Go to PDP - search clickout","scope":"LOCAL"},{"id":"ab9498b9-e561-4e3d-836d-32f44cb55c58","name":"Currency","type":"CONSTANT","valueType":"TEXT","value":"USD","scope":"LOCAL"},{"id":"51fce128-5c88-4763-a805-ab3d50a47612","name":"Default quantity","type":"CONSTANT","valueType":"INTEGER","value":"1","scope":"LOCAL"},{"id":"6986b552-b31d-4484-a281-3800b6b64c16","name":"Empty Array","type":"FUNCTION","valueType":"LIST","function":function(event){return [] /* */},"scope":"LOCAL"},{"id":"862f679b-0606-4d95-ab95-e97b1b53faaf","name":"Empty Result Popup Label","type":"CONSTANT","valueType":"TEXT","value":"Empty search result popup","scope":"LOCAL"},{"id":"d58d779b-056c-4d5b-bb86-5d83a99cfdc9","name":"Empty search result page label","type":"CONSTANT","valueType":"TEXT","value":"Empty search result page","scope":"LOCAL"},{"id":"ad6080ea-719b-4732-952f-ef4f1ce45e02","name":"Event target","type":"FUNCTION","valueType":"EVENT","function":function(event){return event.target /* */},"scope":"GLOBAL"},{"id":"1e327f21-f8ab-4ffc-afbd-61bb59ee3728","name":"Event target - parent element","type":"FUNCTION","valueType":"EVENT","function":function(event){return event.target.parentElement; /* */},"scope":"GLOBAL"},{"id":"208cb3d2-e90c-4c00-9c47-f6f4144859db","name":"IsAddToListButton","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){const isAddToListButton = (event.target.className === 'btn-add STBTN button button--sm' || event.target.className === 'btn-add grey big button STBTN') ? event.target.attributes.value.textContent === 'Add To List' : false return isAddToListButton /* */},"scope":"LOCAL"},{"id":"209362c9-3047-40a3-83f8-d661b9791a5b","name":"IsCategorySearchResultLink","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return (event.target.localName === "a" && event.target.className.includes("productClickItemV2") && event.target.className.includes("productViewItem")) || (event.target.localName === 'a' && event.target.parentElement.className === "TA-liBR" ) || (event.target.parentElement.localName === 'a' && event.target.parentElement.parentElement.className === "TA-liBR" ) || (event.target.localName === 'img' && event.target.parentElement.className.includes("productClickItemV2 productViewItem") ) /* */},"scope":"LOCAL"},{"id":"c840913c-1a0b-4fa0-984f-ee20505d82e3","name":"IsEmptyPage","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return document.querySelector(".brand.SearchResultsNotFound") !== null /* */},"scope":"LOCAL"},{"id":"023b7c33-27d4-48de-970f-58c9b24306b8","name":"IsEmptyResultPopup","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return document.querySelector(".typeAheadResults") === null /* */},"scope":"LOCAL"},{"id":"b6f7939a-3839-4a99-8510-7344b4d3d409","name":"IsPDPPage","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return window.location.href.includes('/product/') /* */},"scope":"LOCAL"},{"id":"48d25357-b1b7-4109-85fa-b38ad625f680","name":"IsQuickView","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return event.target.parentElement.parentElement.parentElement.id === 'tab-overview' /* */},"scope":"LOCAL"},{"id":"0cbf922b-3b2e-40eb-9882-e81de975f079","name":"IsSearchBarEmpty","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return event.target.value === "" /* */},"scope":"LOCAL"},{"id":"718fda17-7370-4de6-9ba1-16a7072c8d86","name":"IsSearchInputFilled","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return document.querySelector("#search-query")?.value !== "" /* */},"scope":"LOCAL"},{"id":"a1ed6dcd-963c-445f-adbd-a9468a153c00","name":"IsSearchResultPage","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){return window.location.href.includes("search/search_results") || document.querySelector("#search-query")?.value !== "" /* */},"scope":"LOCAL"},{"id":"c6a419fa-26f9-47be-b65b-30ff29213142","name":"IsTrashButtonFromCart","type":"FUNCTION","valueType":"BOOLEAN","function":function(event){const trashButtonForm = event.target.closest('form')?.getAttribute('action') return trashButtonForm === '/cart/cartremove' /* */},"scope":"LOCAL"},{"id":"efbb7ae9-c2bd-4a3c-bcc1-b16c1fbacc4b","name":"Label - Input Quantity Update","type":"CONSTANT","valueType":"TEXT","value":"Update cart - Input Quantity update","scope":"LOCAL"},{"id":"c4a17945-595a-4999-9814-d647e1fe0f28","name":"Locale","type":"CONSTANT","valueType":"TEXT","value":"en-US","scope":"LOCAL"},{"id":"6c77635c-e95a-4eca-8086-f6be1b1193e8","name":"Named referral: Search","type":"CONSTANT","valueType":"TEXT","value":"Search","scope":"GLOBAL"},{"id":"a160c59c-225e-4a2d-8804-e20ab4c405e1","name":"Negative Quantity","type":"CONSTANT","valueType":"INTEGER","value":"-1","scope":"LOCAL"},{"id":"eb685af8-9053-4387-9b69-6ec4f1ed5396","name":"Ordered products list","type":"FUNCTION","valueType":"LIST","function":function(event){function extractPriceFromWebsite(initialPrice) { const parsedPrice = initialPrice .replace(/\.$/, '') .replace(/([^.',\s\d])*/g, '') .replace(/([.',\s](?=\d{3}))/g, '') .replace(/([.',](?=\d{2}))/g, '.'); return Number(parsedPrice); } function extractProductData() { const products = []; const rows = document.querySelectorAll('table.text-charcoal.checkout-table tbody tr'); rows.forEach(row => { const product = {}; const nameElement = row.querySelector('td strong'); if (nameElement) { product.name = nameElement.textContent.trim(); } const quantityElement = row.querySelector('td.text-right'); if (quantityElement) { product.quantity = parseInt(quantityElement.textContent.trim(), 10); } const priceElement = row.querySelectorAll('td.text-right')[1]; // The second "text-right" is for the price if (priceElement) { product.price = extractPriceFromWebsite(priceElement.textContent.trim()) } const skuElement = row.querySelector('td div'); if (skuElement) { product.sku = skuElement.textContent.trim().replace('SKU: ', '').trim(); } product.unit = "unit"; if (product.name && product.sku && !isNaN(product.quantity) && !isNaN(product.price)) { products.push(product); } }); return products; } const productList = extractProductData(); return productList; /* */},"scope":"LOCAL"},{"id":"75cf8fd1-fafe-44be-9806-23ff3017c9c1","name":"Page URL","type":"FUNCTION","valueType":"TEXT","function":function(event){return window.location.href; /* */},"scope":"GLOBAL"},{"id":"85d0a46a-ebfa-4084-a225-d050d2d8d7af","name":"PDP link target URL","type":"FUNCTION","valueType":"TEXT","function":function(event){return event.target.href /* */},"scope":"LOCAL"},{"id":"0d872be2-fcdb-4b28-9116-89c268ce779b","name":"Price from Cart Tile","type":"FUNCTION","valueType":"DECIMAL","function":function(event){const priceElement = event.target?.closest(".cart-item")?.querySelector('.text-red')?.innerText; return priceElement ? getNumericPriceFromString(priceElement) : 0; /* */},"scope":"LOCAL"},{"id":"9b349d5a-c04a-4802-9f24-cb50b3dc773e","name":"Price from PDP","type":"FUNCTION","valueType":"DECIMAL","function":function(event){const pricingElement = document.querySelector('#pricing'); if (!pricingElement) { return 0; } const priceElement = pricingElement.getAttribute('content'); if (!priceElement) { return 0; } return getNumericPriceFromString(priceElement); /* */},"scope":"LOCAL"},{"id":"17c4fea8-190e-4bfc-9d96-b0fea5a43546","name":"Price from quick view","type":"FUNCTION","valueType":"DECIMAL","function":function(event){function extractPriceFromWebsite(initialPrice) { const parsedPrice = initialPrice .replace(/\.$/, '') .replace(/([^.',\s\d])*/g, '') .replace(/([.',\s](?=\d{3}))/g, '') .replace(/([.',](?=\d{2}))/g, '.'); return Number(parsedPrice); } const priceString = event.target.parentElement.parentElement.parentElement.querySelector("span#pricing").innerText.replace(/[^\d]/g, '') return extractPriceFromWebsite(`${priceString.slice(0, priceString.length - 2)}.${priceString.slice(priceString.length - 2)}`); /* */},"scope":"LOCAL"},{"id":"e2774223-5b41-4371-955a-3552ceb6b7cf","name":"Price from Recommendations","type":"FUNCTION","valueType":"DECIMAL","function":function(event){function extractPriceFromWebsite(initialPrice) { const parsedPrice = initialPrice .replace(/\.$/, '') .replace(/([^.',\s\d])*/g, '') .replace(/([.',\s](?=\d{3}))/g, '') .replace(/([.',](?=\d{2}))/g, '.'); return Number(parsedPrice); } const priceString = event.target.parentElement.parentElement.parentElement.querySelector('.sp').textContent const regex = /\$[\d,]+(\.\d{2})?/; const extarctedPrice = priceString.match(regex); return extractPriceFromWebsite(extarctedPrice[0]) /* */},"scope":"LOCAL"},{"id":"1faee253-9b78-4104-bbbb-36d263dc6b77","name":"Price from Result Page","type":"FUNCTION","valueType":"DECIMAL","function":function(event){if (event.target?.closest(".details")) { const priceSpan = event.target.closest(".details").querySelector('.price span[itemprop="price"]'); const priceMatch = priceSpan?.textContent?.match(/\$([0-9,]+\.\d{2})/); return priceMatch?.[1] ? getNumericPriceFromString(priceMatch[1]) : 0; } else { const parentElement = event.target?.parentElement?.parentElement?.parentElement; const priceElement = parentElement?.querySelector("p a") ?? parentElement?.querySelector('[class^="ProductLink_"]'); const priceString = priceElement?.getAttribute("data-price"); return priceString ? getNumericPriceFromString(priceString) : 0; } /* */},"scope":"LOCAL"},{"id":"784edfb2-ca0c-42f5-ae54-e1cc5f1070a7","name":"Product image target URL","type":"FUNCTION","valueType":"TEXT","function":function(event){return event.target.parentElement.href /* */},"scope":"LOCAL"},{"id":"a6bdbf42-fc80-41f0-b1f6-d768a8f71c57","name":"Quantity from Cart Tile","type":"FUNCTION","valueType":"INTEGER","function":function(event){ const quantity = event.target.closest(".cart-item").querySelector('.qty-input input[type="number"]').value return Number(quantity) /* */},"scope":"LOCAL"},{"id":"54a23c2b-0f61-43f5-af9b-361397ffe8f6","name":"Search result category clickout - target url","type":"FUNCTION","valueType":"TEXT","function":function(event){return event.target.href ?? event.target.parentElement.href /* */},"scope":"LOCAL"},{"id":"e8a19539-1005-4d51-a160-4a21079e9524","name":"SKU from Cart Tile","type":"FUNCTION","valueType":"TEXT","function":function(event){const skuString = event.target.closest(".cart-item").querySelector('.text-charcoal').innerText return skuString.match(/SKU:\s*(\d+)/)[1]; /* */},"scope":"LOCAL"},{"id":"91fab559-07e7-44d3-a12f-8af1bb09e4d4","name":"SKU from PDP","type":"FUNCTION","valueType":"TEXT","function":function(event){return document.querySelector('.sku')?.lastChild?.textContent?.trim() ?? ''; /* */},"scope":"LOCAL"},{"id":"167559fa-56ed-453e-ba48-eb87855fd244","name":"SKU from quick view","type":"FUNCTION","valueType":"TEXT","function":function(event){return event.target.parentElement.parentElement.parentElement.querySelector("form input[name='sku']").value /* */},"scope":"LOCAL"},{"id":"cf8095c0-fb4b-4de6-8f17-fe8eaa991e74","name":"SKU from Recommendations","type":"FUNCTION","valueType":"TEXT","function":function(event){const targetButton = event.target; const skuText = targetButton.querySelector('.hide-text').textContent; const skuMatch = skuText.match(/SKU (\d+)/); return skuMatch[1] /* */},"scope":"LOCAL"},{"id":"ad5264dc-fd0b-4ece-a1c8-442b9ef61fa1","name":"SKU from result page item","type":"FUNCTION","valueType":"TEXT","function":function(event){if (event.target.closest(".details") !== null) { return event.target.closest(".details").querySelector('.sku').textContent.match(/SKU:\s*(\d+)/)[1]; } else { const skuElement = event.target.parentElement.parentElement.querySelector('input[class^="sku"]') ?? event.target.parentElement.parentElement.querySelector('input[name="sku"]') return skuElement.value; } /* */},"scope":"LOCAL"},{"id":"14fe6b24-537e-4f7d-8849-026bf2eac017","name":"transactionId","type":"FUNCTION","valueType":"TEXT","function":function(event){return document.querySelectorAll('.text-charcoal')[1].textContent /* */},"scope":"LOCAL"},{"id":"eddeaa57-276b-49da-b06b-f3323296f7f6","name":"True","type":"CONSTANT","valueType":"BOOLEAN","value":"true","scope":"GLOBAL"},{"id":"01131809-5b9c-4137-85b4-47c366be1306","name":"Update cart quantity input","type":"FUNCTION","valueType":"INTEGER","function":function(event){return Number(event.target.value) /* */},"scope":"LOCAL"}]; const script = {"id":"6d47ec42-0a09-454f-8833-8f997422a265","rows":[{"id":"1d488f41-4bfc-4a3a-9962-f193219aba30","rowType":"EVENT","trigger":{"id":"a7ef627b-2e12-43d1-800c-658a212250a3","name":"PDP link","type":"CLICK","groups":[{"id":"893b3f76-3574-4ea9-8ed5-66eb691f64d1","rows":[{"valueType":"EVENT","id":"dad6da1f-9c11-4e0d-928f-cc5fe636d738","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"hypProductH2_","operator":"CONTAINS_ID"},{"valueType":"BOOLEAN","id":"151cadf3-867c-4fd0-b77d-31822dd646e3","variableId":"a1ed6dcd-963c-445f-adbd-a9468a153c00","value":"true","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"bddb9316-2871-4e7a-accc-d2d05c423192","variableId":"718fda17-7370-4de6-9ba1-16a7072c8d86","value":"true","operator":"EQUALS"}]}]},"action":{"type":"CLICKOUT"},"fields":[{"id":"dfa078f5-142f-4155-be21-452df5645ad0","variableId":"6c77635c-e95a-4eca-8086-f6be1b1193e8","fieldName":"namedReferral"},{"id":"e1e9b733-51e4-49c8-a40a-e11dc05aab84","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"fa104b87-7fe5-4f25-8672-8f727e8e225d","variableId":"2d131731-66b0-43db-832b-5831cf4218d6","fieldName":"eventLabel"},{"id":"d88c9f76-1e1a-40ae-bc63-9ea991fc8fd9","variableId":"85d0a46a-ebfa-4084-a225-d050d2d8d7af","fieldName":"targetUrl"}]},{"id":"ba3ec8a9-6c8b-4bf1-a166-be27240f7879","rowType":"EVENT","trigger":{"id":"b49f5f19-2fde-48fc-9dfa-cf37dbed7ffb","name":"Product image link","type":"CLICK","groups":[{"id":"7dbf371b-9dcf-49ce-bacd-d28374a3820e","rows":[{"valueType":"EVENT","id":"b48c2ce4-1f77-4372-ab63-3503efac2e6d","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"SearchResultProductImage","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"caa1800e-35d3-4225-82d0-7bf42fe9b0ff","variableId":"a1ed6dcd-963c-445f-adbd-a9468a153c00","value":"true","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"d0ccaa52-efbe-4056-83f8-97f0b4b4667f","variableId":"718fda17-7370-4de6-9ba1-16a7072c8d86","value":"true","operator":"EQUALS"}]}]},"action":{"type":"CLICKOUT"},"fields":[{"id":"3e629a79-0fdc-48f2-98dc-218a023801d1","variableId":"6c77635c-e95a-4eca-8086-f6be1b1193e8","fieldName":"namedReferral"},{"id":"b47dfe1a-23b4-4e95-95da-0ce311e3de06","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"c16b8f7b-c9ae-497d-b520-4a8c1b491d98","variableId":"2d131731-66b0-43db-832b-5831cf4218d6","fieldName":"eventLabel"},{"id":"f2cec707-6095-4e2d-8d3c-792323c2e903","variableId":"784edfb2-ca0c-42f5-ae54-e1cc5f1070a7","fieldName":"targetUrl"}]},{"id":"22efff96-8ba0-428d-8534-0c68acb2f71d","rowType":"EVENT","trigger":{"id":"85e71312-1960-4224-b834-a85fab4cd7b6","name":"Add to cart from search result page / Top Picks products","type":"CLICK","groups":[{"id":"1586b2f7-3a9f-4156-ab31-cf6aae205965","rows":[{"valueType":"EVENT","id":"90d6ea3b-eb51-4580-9318-b907ce1bc539","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add STBTN","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"2e9b0584-6375-4ebc-851b-a687930c7848","variableId":"48d25357-b1b7-4109-85fa-b38ad625f680","value":"false","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"36ca3be5-94de-4032-999d-d86c7654f4f4","variableId":"a1ed6dcd-963c-445f-adbd-a9468a153c00","value":"true","operator":"EQUALS"}]},{"id":"38ebf7bb-b2c5-4ede-8805-763299088b26","rows":[{"valueType":"EVENT","id":"a9c3307b-66ed-44f7-a22d-42e82acd04fd","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add STBTN","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"11a81487-7121-406a-8581-7dc8cd795910","variableId":"48d25357-b1b7-4109-85fa-b38ad625f680","value":"false","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"1d35805e-d991-4850-ad93-ad5753499c9d","variableId":"b6f7939a-3839-4a99-8510-7344b4d3d409","value":"true","operator":"EQUALS"}]}]},"action":{"type":"ADD_TO_CART"},"fields":[{"id":"825786c6-d6e1-4ea2-9b8e-2e8904c0836f","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"cde9628e-72da-4b1d-8b18-0fe35c8ed8ee","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"6bdc1263-fbc6-4722-8e42-30d0e3cf1bd7","variableId":"51fce128-5c88-4763-a805-ab3d50a47612","fieldName":"quantity"},{"id":"96b4570b-7a5e-4840-b85c-8de8b59c8456","variableId":"1faee253-9b78-4104-bbbb-36d263dc6b77","fieldName":"price"},{"id":"d43bea45-f06e-4951-88b1-b3a58e669f6f","variableId":"ad5264dc-fd0b-4ece-a1c8-442b9ef61fa1","fieldName":"sku"}]},{"id":"c48051e2-6a28-4df8-b501-7d2511b9a3d5","rowType":"EVENT","trigger":{"id":"6102fbff-87b0-411c-86c9-6bab8e3e13e5","name":"Order confirmation page load","type":"PAGE_LOAD","groups":[{"id":"eafa2719-83be-44fc-8dae-6ab9499149de","rows":[{"valueType":"TEXT","id":"a6760d4c-d9aa-4c1b-8db7-3c21dacc6ff8","variableId":"75cf8fd1-fafe-44be-9806-23ff3017c9c1","value":"/checkout/confirmation","operator":"CONTAINS"}]}]},"action":{"type":"PURCHASED"},"fields":[{"id":"cc90e706-8cf6-47d2-99c0-d31446d8baf6","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"98711f2f-0118-46f5-a0f5-9415d6bb3e2d","variableId":"eb685af8-9053-4387-9b69-6ec4f1ed5396","fieldName":"products"},{"id":"29cdbac3-16c1-4e1c-bbad-fd8d39e8eda9","variableId":"14fe6b24-537e-4f7d-8849-026bf2eac017","fieldName":"transactionId"}]},{"id":"faf07a32-5d99-4bda-aa71-3f2815d4d635","rowType":"EVENT","trigger":{"id":"06716232-5cfc-4bdd-b12a-727bb535b7ff","name":"Add to cart from PDP","type":"CLICK","groups":[{"id":"c5496f1b-0582-4300-89e0-ea7740793c95","rows":[{"valueType":"EVENT","id":"ab319007-a3da-4f87-80bf-7320f328e514","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add grey big button STBTN","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"24692790-4c09-4553-b852-ca57b4339bda","variableId":"208cb3d2-e90c-4c00-9c47-f6f4144859db","value":"false","operator":"EQUALS"}]},{"id":"7b9fd9ed-a23f-44b3-b27d-3699cd62d2ba","rows":[{"valueType":"EVENT","id":"3af41617-c604-4de9-900f-33d6b5f43e8a","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add grey big button BUY-NOW button bg-dark-blue","operator":"MATCHES_CLASS"}]}]},"action":{"type":"ADD_TO_CART"},"fields":[{"id":"4a1f7bd6-ba5d-4f52-aba6-ecf4a7853e10","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"5caf6881-a1c3-4aca-ac70-aa9a2c290401","variableId":"91fab559-07e7-44d3-a12f-8af1bb09e4d4","fieldName":"sku"},{"id":"783b9593-e4dc-4ed2-b881-50cb189ff6aa","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"648af8c4-dd8e-47bb-b70d-d313b9ce6c8c","variableId":"51fce128-5c88-4763-a805-ab3d50a47612","fieldName":"quantity"},{"id":"1cf1c514-7c9c-44a4-82e3-cd8cff70b705","variableId":"9b349d5a-c04a-4802-9f24-cb50b3dc773e","fieldName":"price"}]},{"id":"2e3b6668-5aa0-48a5-9599-86db8a6d783c","rowType":"EVENT","trigger":{"id":"54fd42c5-48ee-4012-a662-4d529c2b2d30","name":"Add to cart from Recommendations","type":"CLICK","groups":[{"id":"90d076c6-ed14-4c69-952c-bb4d8a636aa7","rows":[{"valueType":"EVENT","id":"e18cd766-f7e4-4203-8f90-cdbd90ce3cdf","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add STBTN button button--sm","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"affdeb51-4c3c-42a2-928d-389fc33e252b","variableId":"208cb3d2-e90c-4c00-9c47-f6f4144859db","value":"false","operator":"EQUALS"}]}]},"action":{"type":"ADD_TO_CART"},"fields":[{"id":"fc84659e-bf78-4ef8-9946-e25453904a3f","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"8e3e54e4-7fe0-4501-8ca6-140f4e9586b4","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"386c9d62-a00f-4a16-a786-935f0dc44ab6","variableId":"51fce128-5c88-4763-a805-ab3d50a47612","fieldName":"quantity"},{"id":"a653a880-ea20-401e-ba7b-a055e023758d","variableId":"cf8095c0-fb4b-4de6-8f17-fe8eaa991e74","fieldName":"sku"},{"id":"5a50084f-48b9-4838-acb1-90b7dd6c2ce0","variableId":"e2774223-5b41-4371-955a-3552ceb6b7cf","fieldName":"price"}]},{"id":"3daf4844-7dca-481e-8a61-6daaae3b8f95","rowType":"EVENT","trigger":{"id":"33a6c06e-53bc-4966-98ca-8f3e9fc8eb5a","name":"Remove from cart TrashButton","type":"CLICK","groups":[{"id":"93eec90d-9634-470e-922f-cd1fed9a1ccd","rows":[{"valueType":"BOOLEAN","id":"cd32bb6e-0c91-445e-a4e5-f2e57655b77f","variableId":"c6a419fa-26f9-47be-b65b-30ff29213142","value":"true","operator":"EQUALS"}]}]},"action":{"type":"REMOVE_FROM_CART"},"fields":[{"id":"6792fb47-263d-48be-a8c2-11e25430a645","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"a781a910-764d-4f7e-b0d1-d3d8f2f6a2a2","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"e362a4ce-b38e-45fc-b527-00c040234da6","variableId":"0d872be2-fcdb-4b28-9116-89c268ce779b","fieldName":"price"},{"id":"2d7fbdd9-6ac4-460b-8e1f-03aeee1cde40","variableId":"e8a19539-1005-4d51-a160-4a21079e9524","fieldName":"sku"},{"id":"0ee5362c-1021-4f10-a63f-ed825388ae78","variableId":"a6bdbf42-fc80-41f0-b1f6-d768a8f71c57","fieldName":"quantity"}]},{"id":"f6ca02b5-a40b-4e30-92c3-40f9ac4eacca","rowType":"EVENT","trigger":{"id":"48cb61fa-a13f-45fd-85ce-0d974bf16cd8","name":"Quantity update Input","type":"INPUT","delayMs":1500,"groups":[{"id":"380e2674-b602-4aec-9f24-831d593546e2","rows":[{"valueType":"EVENT","id":"294a7108-e510-4329-b323-a719cf858d5c","variableId":"1e327f21-f8ab-4ffc-afbd-61bb59ee3728","value":"qty-input","operator":"MATCHES_CLASS"}]}]},"action":{"type":"UPDATE_CART"},"fields":[{"id":"217a1792-8552-4221-87bd-58bf74ded785","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"8fcd2a4d-6737-4386-a914-8ab086b829c9","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"36afe191-fff1-4dad-bfa8-d5766a94aead","variableId":"0d872be2-fcdb-4b28-9116-89c268ce779b","fieldName":"price"},{"id":"703ee95e-f6c8-4499-ab67-84c1a9d7f687","variableId":"e8a19539-1005-4d51-a160-4a21079e9524","fieldName":"sku"},{"id":"9c9cbf8b-574d-4830-a30c-3f17338b0a40","variableId":"efbb7ae9-c2bd-4a3c-bcc1-b16c1fbacc4b","fieldName":"eventLabel"},{"id":"858283e1-105a-4240-8902-ba03fb2995b4","variableId":"01131809-5b9c-4137-85b4-47c366be1306","fieldName":"quantity"}]},{"id":"87ca646a-06a7-48ae-a23a-8a0b36e7ae9b","rowType":"EVENT","trigger":{"id":"9f18a3ba-35a5-4050-8e71-6332c74b14ff","name":"Empty result page loaded","type":"PAGE_LOAD","groups":[{"id":"3e9593a1-195f-4daa-8057-1c570ea48292","rows":[{"valueType":"BOOLEAN","id":"6a189585-b68e-4b0b-b527-56e1eb95d601","variableId":"c840913c-1a0b-4fa0-984f-ee20505d82e3","value":"true","operator":"EQUALS"},{"valueType":"TEXT","id":"08bc7702-afbe-4120-8efc-c3a1538c68f8","variableId":"75cf8fd1-fafe-44be-9806-23ff3017c9c1","value":"search/search_results","operator":"CONTAINS"}]}]},"action":{"type":"SEARCH_RESULT"},"fields":[{"id":"30a7dcd3-0b51-4607-b0d4-f1acc7d39f56","variableId":"eddeaa57-276b-49da-b06b-f3323296f7f6","fieldName":"isEmpty"},{"id":"e9643af3-b912-4d35-b40f-80a343fa3a06","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"78d4e2ea-42aa-4ef6-b472-43e594361c98","variableId":"6986b552-b31d-4484-a281-3800b6b64c16","fieldName":"skus"},{"id":"5db5cfe9-7db4-4b9c-96fe-444cdcf3d84a","variableId":"d58d779b-056c-4d5b-bb86-5d83a99cfdc9","fieldName":"eventLabel"}]},{"id":"7ac9026a-fe2f-4e54-abc1-0f52421e3f7e","rowType":"EVENT","trigger":{"id":"fc913613-b2b5-4d0f-95e0-439d2ce85b47","name":"Search Bar","type":"INPUT","delayMs":1500,"groups":[{"id":"5abbdf87-646b-4e10-a70a-2e55fc99a414","rows":[{"valueType":"EVENT","id":"be0cb502-87a1-4cef-9b21-33caa57be282","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"search-query","operator":"MATCHES_ID"},{"valueType":"BOOLEAN","id":"d2dec22e-ace8-416e-b233-ba60ba8f483e","variableId":"0cbf922b-3b2e-40eb-9882-e81de975f079","value":"false","operator":"EQUALS"}]}]},"action":{"type":"SEARCH"},"fields":[{"id":"153c87e9-38e0-4843-ba9f-1cc82e17ad4f","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"}]},{"id":"918cd46d-1cc5-4925-b6b4-ec5327ffbfc4","rowType":"EVENT","trigger":{"id":"2cec9c3f-7ae2-468d-888d-943d7e57d6c4","name":"Empty Result Popup","type":"INPUT","delayMs":1500,"groups":[{"id":"7ae963ee-f77f-4183-91b8-87c7964c9af0","rows":[{"valueType":"EVENT","id":"ffa1b276-423e-4102-b91f-fd10b59cdd37","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"search-query","operator":"MATCHES_ID"},{"valueType":"BOOLEAN","id":"0c7d6ab0-9ef5-4f84-89e5-aee26a605238","variableId":"023b7c33-27d4-48de-970f-58c9b24306b8","value":"true","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"af1c0f7b-d54c-4813-8464-95957412cd2f","variableId":"0cbf922b-3b2e-40eb-9882-e81de975f079","value":"false","operator":"EQUALS"}]}]},"action":{"type":"SEARCH_RESULT"},"fields":[{"id":"983540eb-8a64-4bb2-9563-da23c1ff4cb3","variableId":"eddeaa57-276b-49da-b06b-f3323296f7f6","fieldName":"isEmpty"},{"id":"dfb2b7ec-7da9-4640-820f-9ade90650a32","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"da0cada7-8ec0-42a2-bc1a-1e3525f734f6","variableId":"6986b552-b31d-4484-a281-3800b6b64c16","fieldName":"skus"},{"id":"d1060871-3b11-4b34-8af1-7d3ca7764b29","variableId":"862f679b-0606-4d95-ab95-e97b1b53faaf","fieldName":"eventLabel"}]},{"id":"737b2e88-5f5d-46a3-a58d-f07daa58e3e4","rowType":"EVENT","trigger":{"id":"1dfb9cc8-6c4e-49b7-802a-1f3e44ddb47b","name":"Clickout - category","type":"CLICK","groups":[{"id":"d588c6e1-265c-4d7d-a8c7-906bc047bda0","rows":[{"valueType":"BOOLEAN","id":"97300491-6593-47a3-8fa0-85c3eb57a780","variableId":"209362c9-3047-40a3-83f8-d661b9791a5b","value":"true","operator":"EQUALS"}]}]},"action":{"type":"CLICKOUT"},"fields":[{"id":"2b67050d-4817-470d-bd61-d4a035b7a4d1","variableId":"6c77635c-e95a-4eca-8086-f6be1b1193e8","fieldName":"namedReferral"},{"id":"80ba0bcf-7433-46b7-8c5e-b9377744295f","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"74eb83f3-84dd-4b3b-a867-9a5c371c478b","variableId":"39bbfe16-720b-4d45-ba8a-79c874321c6e","fieldName":"eventLabel"},{"id":"7fb521a1-0d0e-47c8-9e65-f62720fc3d85","variableId":"54a23c2b-0f61-43f5-af9b-361397ffe8f6","fieldName":"targetUrl"}]},{"id":"132c410e-d423-4df4-a3d7-f60065416071","rowType":"EVENT","trigger":{"id":"ed1f4fcc-a2e7-4b83-9fd6-2f806929ea1a","name":"Add to cart from quick view","type":"CLICK","groups":[{"id":"79b54091-314a-452b-8981-90a2c6cd70fa","rows":[{"valueType":"EVENT","id":"4e12c68f-c85a-4874-8bbb-4ad93350434b","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add STBTN","operator":"MATCHES_CLASS"},{"valueType":"BOOLEAN","id":"3c0a7141-5b9e-476b-96a0-c9a8db3e8d78","variableId":"48d25357-b1b7-4109-85fa-b38ad625f680","value":"true","operator":"EQUALS"},{"valueType":"BOOLEAN","id":"a7b1a0df-6819-4354-a016-814828de20c2","variableId":"a1ed6dcd-963c-445f-adbd-a9468a153c00","value":"true","operator":"EQUALS"},{"valueType":"EVENT","id":"e0a413b9-a235-4871-9b1d-5993c483f8a7","variableId":"1e327f21-f8ab-4ffc-afbd-61bb59ee3728","value":"crtfrm Matrix-PickupOnly","operator":"MATCHES_CLASS"}]}]},"action":{"type":"ADD_TO_CART"},"fields":[{"id":"9102377c-dfc0-4c20-a2a9-e35b6bf5989d","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"c7b0e51d-d794-4db7-8ce7-cbe39b257e64","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"2a7668d7-5f8f-4628-a588-7f2317d1f7d4","variableId":"51fce128-5c88-4763-a805-ab3d50a47612","fieldName":"quantity"},{"id":"b3b1d56c-fe2d-4c5d-a810-1ba1b99499fb","variableId":"167559fa-56ed-453e-ba48-eb87855fd244","fieldName":"sku"},{"id":"243461ed-b4dd-4744-91dd-065d758d026c","variableId":"17c4fea8-190e-4bfc-9d96-b0fea5a43546","fieldName":"price"}]},{"id":"89232982-0edf-4598-a13d-bde396219b3f","rowType":"EVENT","trigger":{"id":"dd99ce9b-0a0f-41a0-9e95-33d2cb4074d8","name":"PDP page load","type":"PAGE_LOAD","groups":[{"id":"29667947-bc75-4cee-b5ad-91e17923eb8f","rows":[{"valueType":"TEXT","id":"b8a64742-445e-48b1-9847-d260e41ed073","variableId":"75cf8fd1-fafe-44be-9806-23ff3017c9c1","value":"/product/","operator":"CONTAINS"}]}]},"action":{"type":"PDP_VISITED"},"fields":[{"id":"b6888e95-2659-4b10-8c33-88f5a9ee78f6","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"9ba0c94a-bc57-4035-adf7-45fac2e7697a","variableId":"91fab559-07e7-44d3-a12f-8af1bb09e4d4","fieldName":"sku"},{"id":"ba028eeb-b8ae-4212-8fb5-dd64a96a2cea","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"07851180-c514-439d-b50b-ef02f674906e","variableId":"9b349d5a-c04a-4802-9f24-cb50b3dc773e","fieldName":"price"}]},{"id":"d080a684-e544-4bcf-9371-fb0a1fd9b9ac","rowType":"EVENT","trigger":{"id":"716ec754-5e1b-46ea-b926-1c69e7bcd015","name":"Page Load [Proper one]","type":"PAGE_LOAD","groups":[{"id":"871620c8-d29b-4b5c-8200-9726127d5f97","rows":[{"valueType":"BOOLEAN","id":"fedf4423-070f-4f89-b710-9ae0d4aea88e","variableId":"b6f7939a-3839-4a99-8510-7344b4d3d409","value":"false","operator":"EQUALS"}]}]},"action":{"type":"PAGE_VISITED"},"fields":[{"id":"3ca7d78f-10f4-446f-b810-94592f9cc0bb","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"}]},{"id":"5a3acf88-c2ae-40c7-abfc-556a49b6d3f6","rowType":"EVENT","trigger":{"id":"74c6cb3c-538f-45c6-a1df-3bf35a4c7f4f","name":"Add to cart from PlusButton","type":"CLICK","groups":[{"id":"2aa34281-a681-4588-a789-93615b8b537d","rows":[{"valueType":"EVENT","id":"417ce80c-78e7-4ac5-be01-cbe6157b422b","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"qty-input__add","operator":"MATCHES_CLASS"}]},{"id":"80da37aa-1394-49d5-8205-59988a3ce697","rows":[{"valueType":"EVENT","id":"197b51dd-dd26-43b8-a473-ad6519141cc4","variableId":"1e327f21-f8ab-4ffc-afbd-61bb59ee3728","value":"qty-input__add","operator":"MATCHES_CLASS"}]}]},"action":{"type":"UPDATE_CART"},"fields":[{"id":"bcbce938-1357-47b8-ae84-6a584e254398","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"1239fab7-1547-43d6-a317-6a3e98a05524","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"d55b4c7f-1aa2-4921-856e-c5c3fe7a6c27","variableId":"51fce128-5c88-4763-a805-ab3d50a47612","fieldName":"quantity"},{"id":"e860c2ea-94b5-4dc6-ac18-d563cece7ec1","variableId":"0d872be2-fcdb-4b28-9116-89c268ce779b","fieldName":"price"},{"id":"e51b7803-e5f9-4e0d-a2e4-1cf3a6901f0d","variableId":"e8a19539-1005-4d51-a160-4a21079e9524","fieldName":"sku"}]},{"id":"cafb92d5-e70d-48c8-9e1a-7da661b16e1e","rowType":"EVENT","trigger":{"id":"18dda43c-511b-4e3c-b6c2-2259eee46ff1","name":"Remove from cart MinusButton","type":"CLICK","groups":[{"id":"950464e1-98aa-439f-9dc9-772f95b32270","rows":[{"valueType":"EVENT","id":"7673cf79-4a45-4177-af5f-1f1421d890ed","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"qty-input__sub","operator":"MATCHES_CLASS"}]},{"id":"284fc337-59a0-4013-8a2a-9f67f922031f","rows":[{"valueType":"EVENT","id":"9de625f1-e500-4143-9642-ed16706d7c87","variableId":"1e327f21-f8ab-4ffc-afbd-61bb59ee3728","value":"qty-input__sub","operator":"MATCHES_CLASS"}]}]},"action":{"type":"UPDATE_CART"},"fields":[{"id":"cf910797-d070-421e-85d7-cfdd70c0cb9b","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"affb6ab0-d71f-4617-a90c-926790a48179","variableId":"ab9498b9-e561-4e3d-836d-32f44cb55c58","fieldName":"currencyCode"},{"id":"35e2a766-228a-4159-b25b-bcea3662b7dd","variableId":"0d872be2-fcdb-4b28-9116-89c268ce779b","fieldName":"price"},{"id":"fa45001b-de74-4fec-976e-2d271a4f1de2","variableId":"e8a19539-1005-4d51-a160-4a21079e9524","fieldName":"sku"},{"id":"90b852f1-2b03-4257-ab1d-9b6d7d171de6","variableId":"a160c59c-225e-4a2d-8804-e20ab4c405e1","fieldName":"quantity"}]},{"id":"9a68bea1-b30b-41a3-a5f5-7e51bc15935a","rowType":"EVENT","trigger":{"id":"e32bca4f-bbae-4c6a-be9c-b3adeb652299","name":"Add to cart from result page / quick view CLICKOUT","type":"CLICK","groups":[{"id":"21def8f4-6389-4851-859c-94f61a75ab51","rows":[{"valueType":"BOOLEAN","id":"8606aac6-a772-4cca-8aac-3225aa359bbe","variableId":"718fda17-7370-4de6-9ba1-16a7072c8d86","value":"true","operator":"EQUALS"},{"valueType":"EVENT","id":"9f50fd46-eb3c-448a-bdc7-a13f5fdcb2c1","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"STBTN","operator":"CONTAINS_CLASS"},{"valueType":"EVENT","id":"91699ad0-cd71-48f0-875c-0366dd573295","variableId":"ad6080ea-719b-4732-952f-ef4f1ce45e02","value":"btn-add","operator":"CONTAINS_CLASS"},{"valueType":"BOOLEAN","id":"f05c302e-c67c-4140-85fc-736312d1755b","variableId":"a1ed6dcd-963c-445f-adbd-a9468a153c00","value":"true","operator":"EQUALS"}]}]},"action":{"type":"CLICKOUT"},"fields":[{"id":"0f38673e-2856-464b-acbf-958f8d8b16b2","variableId":"6c77635c-e95a-4eca-8086-f6be1b1193e8","fieldName":"namedReferral"},{"id":"45b5f451-f7c0-443f-8616-a594ecd26be6","variableId":"c4a17945-595a-4999-9814-d647e1fe0f28","fieldName":"locale"},{"id":"5c0d6010-bd2a-450f-b86e-ec9aaf545b71","variableId":"17288887-bfdf-49b1-95b1-b30404e6aee6","fieldName":"eventLabel"},{"id":"bf89df0a-d8c9-4f7a-b26d-c257646245d2","variableId":"a5881501-614d-4226-82ce-58fbb39eb40e","fieldName":"targetUrl"}]}]}; const advancedCode = function(){const cookieString = decodeURIComponent(document.cookie) const groupsMatch = cookieString.match(/groups=([^&;]+)/); if (!groupsMatch) { disableTracking(); return; } const groupsValue = groupsMatch[1]; const groups = {}; groupsValue.split(',').forEach(group => { const [key, value] = group.split(':'); if (key && value !== undefined) { groups[key] = parseInt(value, 10); } }); const isC0001Enabled = groups['C0001'] === 1; const isC0003Enabled = groups['C0003'] === 1; const isC0004Enabled = groups['C0004'] === 1; if (isC0001Enabled && isC0003Enabled && isC0004Enabled) { enableTracking(); } else { disableTracking(); }}; const url = 'https://queue-propagator.zoovu.com'; const currentEnvironment = 'orca'; const currentAccountId = 250000757; const currencies = ['FJD', 'STD', 'MXN', 'LVL', 'SCR', 'CDF', 'BBD', 'UGX', 'HNL', 'MXV', 'ZAR', 'STN', 'CUC', 'SDD', 'BSD', 'SDG', 'IQD', 'CUP', 'GMD', 'TWD', 'RSD', 'UYI', 'MYR', 'FKP', 'XOF', 'UYU', 'CVE', 'OMR', 'SEK', 'KES', 'BTN', 'GNF', 'MZN', 'SVC', 'MZM', 'ARS', 'QAR', 'IRR', 'NLG', 'XPD', 'XPF', 'UZS', 'THB', 'BDT', 'LYD', 'KWD', 'XPT', 'RUB', 'ISK', 'BEF', 'MKD', 'RUR', 'DZD', 'PAB', 'SGD', 'KGS', 'XAD', 'XAF', 'XAG', 'ATS', 'ITL', 'CHF', 'HRK', 'CHE', 'DJF', 'TZS', 'VND', 'ADP', 'XAU', 'AUD', 'CHW', 'KHR', 'XBA', 'IDR', 'KYD', 'XBC', 'XBB', 'BWP', 'SHP', 'XBD', 'CYP', 'TJS', 'AED', 'RWF', 'DKK', 'ZWD', 'BGL', 'BGN', 'MMK', 'NOK', 'SYP', 'ZWG', 'ZWL', 'ZWN', 'YUM', 'LKR', 'ZWR', 'IEP', 'CZK', 'GRD', 'XCD', 'HTG', 'XSU', 'AFA', 'XCG', 'SIT', 'BHD', 'PTE', 'KZT', 'SZL', 'YER', 'AFN', 'BYB', 'AWG', 'NPR', 'MNT', 'GBP', 'XTS', 'BYN', 'HUF', 'BYR', 'BIF', 'XUA', 'XDR', 'BZD', 'MOP', 'NAD', 'SKK', 'TMM', 'PEN', 'WST', 'TMT', 'FRF', 'CLF', 'GTQ', 'CLP', 'TND', 'SLE', 'SLL', 'AYM', 'XFO', 'DOP', 'KMF', 'XFU', 'GEL', 'MAD', 'AZM', 'TOP', 'AZN', 'PGK', 'UAH', 'ERN', 'TPE', 'MRO', 'CNY', 'MRU', 'BMD', 'XXX', 'PHP', 'PYG', 'JMD', 'GWP', 'ESP', 'COP', 'USD', 'COU', 'USN', 'ETB', 'VEB', 'USS', 'VED', 'VUV', 'SOS', 'VEF', 'LAK', 'ZMK', 'BND', 'LRD', 'ALL', 'GHC', 'MTL', 'VES', 'ZMW', 'TRL', 'ILS', 'GYD', 'KPW', 'GHS', 'BOB', 'MDL', 'AMD', 'TRY', 'LBP', 'JOD', 'HKD', 'EUR', 'LSL', 'CAD', 'BOV', 'EEK', 'MUR', 'ROL', 'GIP', 'RON', 'NGN', 'CRC', 'PKR', 'ANG', 'SRD', 'TTD', 'SAR', 'LTL', 'MVR', 'SRG', 'INR', 'KRW', 'JPY', 'AOA', 'PLN', 'SBD', 'CSD', 'LUF', 'MWK', 'MGA', 'FIM', 'DEM', 'MGF', 'BAM', 'EGP', 'SSP', 'NIO', 'NZD', 'BRL'] // ------------------------- API ------------------------- let trackingEnabled = true; let hasLauncher = typeof advancedCode === 'function' && advancedCode.toString().includes('/behavioral-launchers-script'); let signalReady = false; let signalReadyPromise = null; let signalCheckAttempts = 0; const MAX_SIGNAL_CHECK_ATTEMPTS = 20; // 20 attempts const SIGNAL_CHECK_INTERVAL_MS = 200; // Check every 200ms (total 4 seconds max wait) let eventQueue = []; function disableTracking() { trackingEnabled = false; } function enableTracking() { trackingEnabled = true; } function getNumericPriceFromString(stringPrice) { const parsedPrice = stringPrice .replace(/\.$/, '') .replace(/([^.',\s\d])*/g, '') .replace(/([.',\s](?=\d{3}))/g, '') .replace(/([.',](?=\d{2}))/g, '.') .trim() .replace(/\s+/g, '') .replace(/\.+(?=\.)/g, '') .replace(/\.$/, ''); return Number(parsedPrice); } // helper for loading launcher from advancedmode function loadLauncher(launcherUrl, callback, id) { if (launcherUrl) { const script = document.createElement('script'); script.type = 'text/javascript'; script.src = launcherUrl; script.id = id || 'zv-launcher'; script.onload = callback; document.head.appendChild(script); } } function setSignalReady() { signalReady = true; if (eventQueue.length > 0) { console.debug(`Signal ready - flushing ${eventQueue.length} queued events`); const eventsToFlush = [...eventQueue]; eventQueue = []; eventsToFlush.forEach(queuedEvent => { sendEventImmediately(queuedEvent); }); } } if (typeof window !== 'undefined') { if (typeof window.ZoovuTrackingManager === 'undefined') { window.ZoovuTrackingManager = {}; } window.ZoovuTrackingManager.setSignalReady = setSignalReady; } class TrackingExecutionError extends Error { constructor(message, trackingEntityType, variableId, triggerId, scriptId, trackingErrorType) { super(message); this.trackingEntityType = trackingEntityType; this.variableId = variableId; this.triggerId = triggerId; this.scriptId = scriptId; this.trackingErrorType = trackingErrorType; } } // ------------------------- helpers ------------------------- const eventTypes = Object.freeze({ PAGE_VISITED: "PAGE_VISITED", ADD_TO_CART: "ADD_TO_CART", REMOVE_FROM_CART: "REMOVE_FROM_CART", PDP_VISITED: "PDP_VISITED", PURCHASED: "PURCHASED", UPDATE_CART: "UPDATE_CART", DECLINE_TRACKING: "DECLINE_TRACKING", SEARCH: "SEARCH", SEARCH_RESULT: "SEARCH_RESULT", CLICKOUT: "CLICKOUT", LEAD_GEN: "LEAD_GEN" }); const trackingEventTypes = Object.freeze({ TRACKING_SUCCESSFUL_EXECUTION: 'TRACKING_SUCCESSFUL_EXECUTION', TRACKING_EXECUTION_FAILURE: 'TRACKING_EXECUTION_FAILURE' }) const actionTypes = Object.freeze({ ...eventTypes, CUSTOM: 'CUSTOM' }) const triggerTypes = Object.freeze({ CLICK: 'CLICK', INPUT: 'INPUT', PAGE_LOAD: 'PAGE_LOAD' }); const variableTypes = Object.freeze({ FUNCTION: 'FUNCTION', CONSTANT: 'CONSTANT' }); const trackingEntityTypes = Object.freeze({ VARIABLE: 'VARIABLE', TRIGGER: 'TRIGGER', CUSTOM_ACTION: 'CUSTOM_ACTION' }); const trackingErrorTypes = Object.freeze({ MISSING_VALUE: 'MISSING_VALUE', TYPE_MISMATCH: 'TYPE_MISMATCH', UNSUPPORTED_VARIABLE: 'UNSUPPORTED_VARIABLE', MISSING_VARIABLE: 'MISSING_VARIABLE', OTHER: 'OTHER' }); const trackingVariableScopes = Object.freeze({ GLOBAL: 'GLOBAL', LOCAL: 'LOCAL' }); const namedReferrals = Object.freeze({ SEARCH: 'SEARCH' }) const getElementAttribute = (target, attributeName) => { const attribute = target[attributeName]; if (typeof attribute === 'string') { return attribute; } if (attribute && attribute.baseVal !== undefined) { return attribute.baseVal; } return target.getAttribute(attributeName === 'className' ? 'class' : attributeName) || ''; }; const getElementId = (target) => { return getElementAttribute(target, 'id'); }; const getElementClassName = (target) => { return getElementAttribute(target, 'className'); }; const matchers = Object.freeze({ EQUALS: (a, b) => a === b, DOES_NOT_EQUAL: (a, b) => a !== b, CONTAINS: (a, b) => a.indexOf(b) >= 0, DOES_NOT_CONTAIN: (a, b) => a.indexOf(b) === -1, GREATER_THAN: (a, b) => a > b, LESS_THAN: (a, b) => a < b, GREATER_THAN_OR_EQUAL: (a, b) => a >= b, LESS_THAN_OR_EQUAL: (a, b) => a <= b, MATCHES_CSS_SELECTOR: (target, test) => target.matches(test), MATCHES_ID: (target, test) => getElementId(target) === test, CONTAINS_ID: (target, test) => getElementId(target).includes(test), DOES_NOT_CONTAIN_ID: (target, test) => !getElementId(target).includes(test), MATCHES_CLASS: (target, test) => getElementClassName(target) === test, CONTAINS_CLASS: (target, test) => getElementClassName(target).includes(test), DOES_NOT_CONTAIN_CLASS: (target, test) => !getElementClassName(target).includes(test), MATCHES_REGEX: (a, b) => parseRegexString(b).test(a), }); const trackingFieldName = `${domainId}_${zoovuId}_trackingExecutions` const MAX_RECORDS = 100 // helper to retrieve variableId later let eventFields = [] if (!JSON.parse(localStorage.getItem(trackingFieldName))) { localStorage.setItem(trackingFieldName, JSON.stringify([])) } function parseRegexString(input) { const trimmed = input.trim(); // check if it starts and ends with slashes (e.g., /^abc$/gi) const match = trimmed.match(/^\/(.+)\/([a-z]*)$/i); if (match) { const pattern = match[1]; const flags = match[2]; return new RegExp(pattern, flags); } // no flags return new RegExp(trimmed); } function checkValue(type, value) { switch (type) { case 'BOOLEAN': return value === true || value === 'true'; case 'TEXT': return value; case 'DECIMAL': return typeof value === 'string' ? parseFloat(value) : value; case 'INTEGER': return typeof value === 'string' ? parseInt(value) : value; default: return value; } } function cast(type, value) { switch (type) { case 'BOOLEAN': return value === true || value === 'true'; case 'TEXT': return value; case 'DECIMAL': return typeof value === 'string' ? parseFloat(value) : value; case 'INTEGER': return typeof value === 'string' ? parseInt(value) : value; default: return value; } } function debounce(fn, delay, useTrailing = false) { if (useTrailing) { // Trailing debounce for INPUT triggers - only fires once after delay using requestAnimationFrame let lastCallTime = 0; let animationFrameId = null; let hasScheduledExecution = false; function checkAndExecute(context, args) { const currentTime = performance.now(); const timeSinceLastCall = currentTime - lastCallTime; if (timeSinceLastCall >= delay) { // Delay has passed, execute the function fn.apply(context, args); hasScheduledExecution = false; } else { // Keep checking until delay has passed animationFrameId = requestAnimationFrame(() => { checkAndExecute(context, args); }); } } return function () { const context = this, args = arguments; lastCallTime = performance.now(); if (!hasScheduledExecution) { hasScheduledExecution = true; animationFrameId = requestAnimationFrame(() => { checkAndExecute(context, args); }); } }; } // Original requestAnimationFrame-based debounce for other triggers let lastCallTime = 0; let animationFrameId = null; let isScheduled = false; function execute(context, args, currentTime) { if (currentTime - lastCallTime >= delay) { fn.apply(context, args); isScheduled = false; } else { animationFrameId = requestAnimationFrame((newTime) => { execute(context, args, newTime); }); } } return function () { const context = this, args = arguments; lastCallTime = performance.now(); if (!isScheduled) { isScheduled = true; animationFrameId = requestAnimationFrame((currentTime) => { execute(context, args, currentTime); }); } }; } function getOrganization() { return zoovuId; } function getDomainId() { return domainId; } function getTimezone() { return Intl.DateTimeFormat().resolvedOptions().timeZone; } function getReferrer() { const referrer = document.referrer; if (/^(https?|android-app):\/\//i.test(referrer)) { return referrer; } else { return undefined; } } function getPath() { return window.location.href.replace(window.location.origin, ''); } function getCookieValue(cookieName) { const cookies = document.cookie.split('; '); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].split('='); // Skip malformed cookies with multiple '=' signs if (cookie.length !== 2) { continue; } if (cookie[0] === cookieName) { return cookie[1]; } } return null; } function getAllCookieValues(cookieName) { const cookies = document.cookie.split('; '); const values = []; for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].split('='); // Skip malformed cookies with multiple '=' signs if (cookie.length !== 2) { continue; } if (cookie[0] === cookieName) { values.push(cookie[1]); } } return values; } function generateUuid() { return self.crypto.randomUUID(); } function isValidCidFormat(cid) { // UUID (36 chars) or UUID_timestamp (36 + 1 + 13 = 50 chars) // Max 60 chars to allow some buffer return cid && cid.length <= 60; } let cachedRegistrableDomain = null; function getRegistrableDomain(hostname) { if (cachedRegistrableDomain) { return cachedRegistrableDomain; } const parts = hostname.split('.'); if (parts.length <= 2) { cachedRegistrableDomain = hostname; return hostname; } // Probe from broadest to narrowest domain level. // Browsers refuse to set cookies on public suffixes (e.g. "co.uk"), // so the first level that accepts a cookie is the registrable domain. const probe = '__zoovu_dt'; for (let i = 2; i <= parts.length; i++) { const candidate = parts.slice(-i).join('.'); document.cookie = `${probe}=1; domain=.${candidate}; path=/`; if (getCookieValue(probe) !== null) { // Clean up the probe cookie document.cookie = `${probe}=; domain=.${candidate}; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`; cachedRegistrableDomain = candidate; return candidate; } } // Fallback – should rarely be reached cachedRegistrableDomain = parts.slice(-2).join('.'); return cachedRegistrableDomain; } function removeZoovuCidCookie() { const hostname = window.location.hostname; const domain = getRegistrableDomain(hostname); // Set expiration to past date to remove cookie document.cookie = `zoovu-cid=; path=/; domain=.${domain}; expires=Thu, 01 Jan 1970 00:00:00 GMT`; document.cookie = `zoovu-cid=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`; } function removeMalformedZoovuCidCookies() { const cookies = document.cookie.split('; '); let hasMalformed = false; // Check for structurally malformed cookies (multiple '=' signs) for (let i = 0; i < cookies.length; i++) { const parts = cookies[i].split('='); if (parts[0] === 'zoovu-cid' && parts.length !== 2) { hasMalformed = true; break; } } // Check for invalid CID formats in properly structured cookies if (!hasMalformed) { const allCids = getAllCookieValues('zoovu-cid'); hasMalformed = allCids.some(cid => !isValidCidFormat(cid)); } if (hasMalformed) { console.debug('[Zoovu Tracking] Found malformed CID cookies, removing them'); removeZoovuCidCookie(); } } function addZoovuCidToCookies() { const uuid = generateUuid(); const hostname = window.location.hostname; const domain = getRegistrableDomain(hostname); const zoovuCid = `zoovu-cid=${uuid}; path=/; domain=.${domain}`; document.cookie = zoovuCid; return uuid; } function getCID() { removeMalformedZoovuCidCookies(); // Check if we have a valid cookie const existingCid = getCookieValue(`zoovu-cid`); if (existingCid !== null && isValidCidFormat(existingCid)) { return existingCid; } // No valid cookie exists, create a new one return addZoovuCidToCookies(); } function getEnvironment() { return currentEnvironment; } function getAccountId() { return currentAccountId; } function getPropertyTypeError(propertyName, expectedType, currentType) { return `TYPE MISMATCH: ${propertyName}: should be ${expectedType} but is ${currentType}` } function typeCheckValue(value, variableType, propertyName, variableId, triggerId) { let errorMessage = ''; if (value === undefined || value === null) { throw new TrackingExecutionError(`${propertyName}: value is not defined.`, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.MISSING_VALUE) } switch (variableType) { case "TEXT": if (typeof value !== 'string') errorMessage = getPropertyTypeError(propertyName, 'string', typeof value); break; case "INTEGER": case "DECIMAL": if (typeof value !== 'number') errorMessage = getPropertyTypeError(propertyName, 'number', typeof value); break; case "BOOLEAN": if (typeof value !== 'boolean') errorMessage = getPropertyTypeError(propertyName, 'boolean', typeof value); break; case 'LIST': if (!Array.isArray(value)) errorMessage = getPropertyTypeError(propertyName, 'list', typeof value); break; case 'EVENT': break; default: throw new TrackingExecutionError(`Not supported variable type: ${variableType}`, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.UNSUPPORTED_VARIABLE) } if (errorMessage) { throw new TrackingExecutionError(errorMessage, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.TYPE_MISMATCH) } } function ensureRequiredFieldsPresent(fields, eventType) { return Object.entries(fields).every(([key, value]) => { if (!value) { const variableId = eventFields.find(field => field.fieldName === key).variableId; // empty eventFields eventFields = []; throw new TrackingExecutionError( `Required property ${key} missing value for ${eventType}.`, trackingEntityTypes.VARIABLE, variableId, null, script.id, trackingErrorTypes.MISSING_VALUE ) } return true; }); } function getBaseEventBody(eventType) { return { origin: 'CLIENT', queryParams: {}, organization: getOrganization(), domainId: getDomainId(), path: getPath(), referrer: getReferrer(), cid: getCID(), timezone: getTimezone(), // dynamic eventType: eventType ?? '', eventLabel: '', }; } function getEventExecutable(actionType) { switch (actionType) { case actionTypes.PAGE_VISITED: return sendPageVisitedEvent; case actionTypes.ADD_TO_CART: return sendAddToCartEvent; case actionTypes.CLICKOUT: return sendClickoutEvent; case actionTypes.REMOVE_FROM_CART: return sendRemoveFromCartEvent; case actionTypes.PDP_VISITED: return sendPdpVisitedEvent; case actionTypes.PURCHASED: return sendPurchaseEvent; case actionTypes.DECLINE_TRACKING: return sendDeclineTrackingEvent; case actionTypes.UPDATE_CART: return sendUpdateCartEvent; case actionTypes.SEARCH: return sendSearchEvent; case actionTypes.SEARCH_RESULT: return sendSearchResultEvent; case actionTypes.LEAD_GEN: return sendLeadGenEvent; } } function checkSpecificFieldValues(fieldName, value, variableId) { if (fieldName === 'currencyCode' && !currencies.includes(value)) { throw new TrackingExecutionError( `Value ${value} is not compatible with currencyCode.`, trackingEntityTypes.VARIABLE, variableId, null, script.id, trackingErrorTypes.OTHER ) } if (fieldName === 'namedReferral' && !namedReferrals[value.toUpperCase()]) { throw new TrackingExecutionError( `Value ${value} is not compatible with namedReferral.`, trackingEntityTypes.VARIABLE, variableId, null, script.id, trackingErrorTypes.OTHER ) } } function getVariableValueById(variableId, event, fieldName, triggerId) { const foundVariable = variables.find(v => v.id === variableId); let variableValue = null; if (foundVariable) { if (foundVariable.type === variableTypes.CONSTANT) { variableValue = cast(foundVariable.valueType, foundVariable.value); } else if (foundVariable.type === variableTypes.FUNCTION && typeof foundVariable.function === 'function') { try { variableValue = foundVariable.function(event); } catch (e) { throw new TrackingExecutionError( e.message, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.OTHER ) } } else { throw new TrackingExecutionError( `${foundVariable.type} is not supported.`, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.UNSUPPORTED_VARIABLE ) } typeCheckValue(variableValue, foundVariable.valueType, fieldName ? fieldName : foundVariable.name, variableId, triggerId); if (fieldName === 'currencyCode' || fieldName === 'namedReferral') { checkSpecificFieldValues(fieldName, variableValue, variableId) } return variableValue; } else { throw new TrackingExecutionError( `No variable with ID ${variableId}`, trackingEntityTypes.VARIABLE, variableId, triggerId, script.id, trackingErrorTypes.MISSING_VARIABLE ) } } function evaluateSingleTriggerRow(row, event, triggerId) { const target = getVariableValueById(row.variableId, event, undefined, triggerId); const matcher = matchers[row.operator]; checkValue(row.valueType, row.value); const value = cast(row.valueType, row.value); if (matcher && typeof matcher === 'function') { return matcher(target, value); } return false; } function preparePayloadFromFields(fields, event) { const payload = {}; fields.forEach(f => { payload[f.fieldName] = getVariableValueById(f.variableId, event, f.fieldName) }) return payload; } function evaluateTriggerConditions(trigger, event) { // OR between groups return trigger.groups.some(group => // AND between rows group.rows.every(row => evaluateSingleTriggerRow(row, event, trigger.id))) } function runAction(action, fields, event, trigger) { const trackingExecutions = jsonParser(trackingFieldName) if (action.type === actionTypes.CUSTOM && typeof action.code === 'function') { // add script custom action trackingExecutions.push(createTrackingSuccessfulExecutionRecord(trackingEntityTypes.CUSTOM_ACTION, action.id)) try { action.code(event); } catch (e) { throw new TrackingExecutionError( e.message, trackingEntityTypes.CUSTOM_ACTION, action.id, null, script.id, trackingErrorTypes.OTHER ) } localStorage.setItem(trackingFieldName, JSON.stringify(trackingExecutions)); } else { const sendEventFunction = getEventExecutable(action.type); eventFields = [...fields]; if (sendEventFunction && typeof sendEventFunction === 'function') { const payload = preparePayloadFromFields(fields, event) sendEventFunction(payload); addSuccessfulExecutions(trigger, fields) } } } // Store debounced functions per rule to reuse them const debouncedRuleActions = new Map(); let ruleCounter = 0; function evaluateSingleRule(rule, event) { // Assign unique ID to rule if it doesn't have one if (!rule._uniqueId) { rule._uniqueId = ruleCounter++; } if (evaluateTriggerConditions(rule.trigger, event)) { // Set default delay for INPUT triggers if delayMs is undefined const delay = rule.trigger.type === triggerTypes.INPUT && rule.trigger.delayMs === undefined ? 1500 : rule.trigger.delayMs; if (delay) { // Get or create debounced function for this rule using unique rule ID const ruleKey = rule._uniqueId; if (!debouncedRuleActions.has(ruleKey)) { const useTrailing = rule.trigger.type === triggerTypes.INPUT; const debounced = debounce(function (event) { runAction(rule.action, rule.fields, event, rule.trigger); }, delay, useTrailing); debouncedRuleActions.set(ruleKey, debounced); } debouncedRuleActions.get(ruleKey)(event); } else { runAction(rule.action, rule.fields, event, rule.trigger); } } } function evaluateRules(rules, event) { try { rules.forEach(rule => { evaluateSingleRule(rule, event) }); } catch (error) { const trackingExecutions = jsonParser(trackingFieldName); const {message, trackingEntityType, variableId, triggerId, scriptId, trackingErrorType} = error; const failedExecution = createTrackingFailedExecutionRecord( trackingEntityType, variableId, triggerId, scriptId, trackingErrorType, message ) trackingExecutions.push(failedExecution) localStorage.setItem(trackingFieldName, JSON.stringify(trackingExecutions)); console.debug(error) } } function observeAndReactOnPageChange(callback) { let oldHref; if (oldHref === undefined) { callback(); oldHref = document.location.href; } const body = document.querySelector('body'); const observer = new MutationObserver(() => { if (oldHref !== document.location.href) { oldHref = document.location.href; callback(); } }); observer.observe(body, {childList: true, subtree: true}); } function executeAdvancedCode() { if (typeof advancedCode === 'function') { advancedCode(); } } function jsonParser(key) { const foundValue = JSON.parse(localStorage.getItem(key)) if (!Array.isArray(foundValue)) { throw Error('Invalid value in localStorage for key ' + key) } return foundValue } function createTrackingSuccessfulExecutionRecord(entityType, entityId) { const executionTime = Date.now(); return { organization: getOrganization(), domainId: getDomainId(), eventType: trackingEventTypes.TRACKING_SUCCESSFUL_EXECUTION, trackingEntityType: entityType, trackingEntityId: entityId, executionTime } } function createTrackingFailedExecutionRecord(entityType, entityId, triggerId, scriptId, errorType, message) { const executionTime = Date.now(); return { organization: getOrganization(), domainId: getDomainId(), eventType: trackingEventTypes.TRACKING_EXECUTION_FAILURE, trackingEntityType: entityType, trackingEntityId: entityId, executionTime, triggerId: triggerId || null, scriptId: scriptId || null, error: { type: errorType, message } } } function addSuccessfulExecutions(trigger, fields) { const successfulExecutions = jsonParser(trackingFieldName) // add script trigger successfulExecutions.push(createTrackingSuccessfulExecutionRecord(trackingEntityTypes.TRIGGER, trigger.id)) // add script function variables fields.forEach(field => { const foundVariableInField = variables.find(variable => variable.id === field.variableId) if (foundVariableInField.type === variableTypes.FUNCTION && foundVariableInField.scope === trackingVariableScopes.LOCAL) { successfulExecutions.push(createTrackingSuccessfulExecutionRecord(trackingEntityTypes.VARIABLE, foundVariableInField.id)) } }) // add trigger function variables trigger.groups.forEach(groups => { groups.rows.forEach(row => { const foundVariable = variables.find(variable => variable.id === row.variableId) if (foundVariable.type === variableTypes.FUNCTION && foundVariable.scope === trackingVariableScopes.LOCAL) { successfulExecutions.push(createTrackingSuccessfulExecutionRecord(trackingEntityTypes.VARIABLE, foundVariable.id)) } }) }) localStorage.setItem(trackingFieldName, JSON.stringify(successfulExecutions)); } // ------------------------- events ------------------------- async function sendEventImmediately(body) { if (trackingEnabled) { await fetch(`${url}/fact`, { method: 'POST', mode: 'cors', cache: 'no-cache', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', }, redirect: 'follow', referrerPolicy: 'no-referrer', body: JSON.stringify(body), }); } else { console.debug("Tracking disabled - no permission to track"); } } function getSignalReadyPromise() { // Return existing promise if already polling if (signalReadyPromise) { return signalReadyPromise; } // Signal already ready, return resolved promise if (signalReady) { return Promise.resolve(); } // Create new polling promise signalReadyPromise = new Promise((resolve) => { signalCheckAttempts = 0; const checkInterval = setInterval(() => { signalCheckAttempts++; if (signalReady) { clearInterval(checkInterval); signalReadyPromise = null; resolve(); } else if (signalCheckAttempts >= MAX_SIGNAL_CHECK_ATTEMPTS) { clearInterval(checkInterval); signalReadyPromise = null; console.debug('Signal connection timeout - proceeding without signal'); resolve(); } }, SIGNAL_CHECK_INTERVAL_MS); }); return signalReadyPromise; } async function sendEvent(body) { if (trackingEnabled) { // Check if we should wait for signal connection // Only wait if launcher exists (hasLauncher) and signal is not ready yet if (hasLauncher && !signalReady && signalCheckAttempts < MAX_SIGNAL_CHECK_ATTEMPTS) { // Queue the event - don't block, just queue it eventQueue.push(body); // Trigger polling in background (fire and forget) getSignalReadyPromise().then(() => { // Flush happens in setSignalReady, but handle timeout case if (!signalReady && eventQueue.length > 0) { const eventsToFlush = [...eventQueue]; eventQueue = []; eventsToFlush.forEach(queuedEvent => { sendEventImmediately(queuedEvent); }); } }); } else { // Send immediately if no launcher or signal already ready await sendEventImmediately(body); } } else { console.debug("Tracking disabled - no permission to track"); } } async function sendSSTRPurchaseEvent(body) { if (trackingEnabled) { const purchaseUrl = 'https://ev-co.zoovu.com/v1/CollectSalesEvent'; await fetch(purchaseUrl, { method: 'POST', mode: 'cors', cache: 'no-cache', headers: { 'Content-Type': 'application/json', }, redirect: 'follow', referrerPolicy: 'no-referrer', body: JSON.stringify(body), }); } else { console.debug("Tracking disabled - no permission to track"); } } async function sendTrackingSuccessfulExecution(body) { if (trackingEnabled) { await fetch(`${url}/tracking/executions`, { method: 'POST', mode: 'cors', cache: 'no-cache', headers: { 'Content-Type': 'application/json', }, redirect: 'follow', referrerPolicy: 'no-referrer', body: JSON.stringify(body), }); } else { console.debug("Tracking disabled - no permission to track"); } } function sendFactEventBase(eventType, eventSpecificBody) { const body = { ...getBaseEventBody(eventType), // event label + custom per-event fields ...eventSpecificBody, }; sendEvent(body); }; function sendPageVisitedEvent({locale, category, eventLabel = 'Page visit'}) { const body = { locale, eventLabel, // optional category, }; if (ensureRequiredFieldsPresent({locale}, eventTypes.PAGE_VISITED)) { sendFactEventBase(eventTypes.PAGE_VISITED, body); } }; function sendPdpVisitedEvent({ locale, sku, quantity = 1, currencyCode, eventLabel = "Product details page visit", price, category }) { const body = { locale, sku, eventLabel, // optional category, price, currencyCode, quantity, }; if (ensureRequiredFieldsPresent({locale, sku}, eventTypes.PDP_VISITED)) { sendFactEventBase(eventTypes.PDP_VISITED, body); } }; function sendAddToCartEvent({ locale, sku, quantity = 1, currencyCode, eventLabel = "Add to cart", price, category }) { const body = { locale, sku, eventLabel, // optional category, price, currencyCode, quantity, }; if (ensureRequiredFieldsPresent({locale, sku}, eventTypes.ADD_TO_CART)) { sendFactEventBase(eventTypes.ADD_TO_CART, body); } }; function sendRemoveFromCartEvent({ locale, sku, quantity = 1, currencyCode, eventLabel = "Remove from cart", price, category }) { const body = { locale, sku, eventLabel, // optional category, price, currencyCode, quantity, }; if (ensureRequiredFieldsPresent({locale, sku}, eventTypes.REMOVE_FROM_CART)) { sendFactEventBase(eventTypes.REMOVE_FROM_CART, body); } }; function sendUpdateCartEvent({ locale, sku, quantity = 1, currencyCode, eventLabel = "Update cart", price, category }) { const body = { locale, sku, eventLabel, // optional category, price, currencyCode, quantity, }; if (ensureRequiredFieldsPresent({locale, sku}, eventTypes.UPDATE_CART)) { sendFactEventBase(eventTypes.UPDATE_CART, body); } }; function sendDeclineTrackingEvent({ locale, eventLabel = "No permission to track", category }) { const body = { locale, eventLabel, // optional category }; if (ensureRequiredFieldsPresent({locale}, eventTypes.DECLINE_TRACKING)) { sendFactEventBase(eventTypes.DECLINE_TRACKING, body); disableTracking(); } }; function sendSearchEvent({ locale, eventLabel = "Search phrase typed", category }) { const body = { locale, eventLabel, // optional category, }; if (ensureRequiredFieldsPresent({locale}, eventTypes.SEARCH)) { sendFactEventBase(eventTypes.SEARCH, body); } }; function sendSearchResultEvent({ locale, isEmpty = false, eventLabel = "Search results", skus, category }) { const body = { locale, isEmpty, skus, eventLabel, // optional category }; if (ensureRequiredFieldsPresent({locale, skus}, eventTypes.SEARCH_RESULT)) { sendFactEventBase(eventTypes.SEARCH_RESULT, body); } }; function sendClickoutEvent({ locale, targetUrl, namedReferral, eventLabel = "Clickout", category }) { const body = { locale, targetUrl, namedReferral, eventLabel, // optional category }; if (ensureRequiredFieldsPresent({locale, targetUrl, namedReferral}, eventTypes.CLICKOUT)) { sendFactEventBase(eventTypes.CLICKOUT, body); } }; function sendPurchaseEvent({ currencyCode, transactionId, products }) { const sstrBody = { transactionId, products, currency: currencyCode, browserTimestamp: Date.now(), env: getEnvironment(), accountId: getAccountId(), clientId: getCID(), }; if (ensureRequiredFieldsPresent({products, currencyCode,}, eventTypes.PURCHASED)) { sendSSTRPurchaseEvent(sstrBody); } }; function sendLeadGenEvent({ locale, currencyCode, products, leadId, leadType, category, eventLabel = "Lead gen sent" }) { const body = { locale, eventLabel, // optional currencyCode, products, leadId, leadType, category }; if (ensureRequiredFieldsPresent({locale}, eventTypes.LEAD_GEN)) { sendFactEventBase(eventTypes.LEAD_GEN, body); } }; function sendSuccessfulExecutionEvent(forceSend) { const successfulExecutions = jsonParser(trackingFieldName) if (successfulExecutions.length === MAX_RECORDS || (forceSend && successfulExecutions.length > 0)) { sendTrackingSuccessfulExecution(successfulExecutions) localStorage.setItem(trackingFieldName, JSON.stringify([])) } } function exposeTrackingApi() { if (typeof window !== 'undefined') { if (typeof window.ZoovuTrackingManager === 'undefined') { window.ZoovuTrackingManager = {}; } // Public API with stable contract - these signatures won't change const sendPageVisitedEventPublic = (event) => sendPageVisitedEvent(event); const sendPdpVisitedEventPublic = (event) => sendPdpVisitedEvent(event); const sendAddToCartEventPublic = (event) => sendAddToCartEvent(event); const sendRemoveFromCartEventPublic = (event) => sendRemoveFromCartEvent(event); const sendUpdateCartEventPublic = (event) => sendUpdateCartEvent(event); const sendDeclineTrackingEventPublic = (event) => sendDeclineTrackingEvent(event); const sendSearchEventPublic = (event) => sendSearchEvent(event); const sendSearchResultEventPublic = (event) => sendSearchResultEvent(event); const sendClickoutEventPublic = (event) => sendClickoutEvent(event); const sendPurchaseEventPublic = (event) => sendPurchaseEvent(event); const sendLeadGenEventPublic = (event) => sendLeadGenEvent(event); window.ZoovuTrackingManager = { // Public API - stable contract sendPageVisitedEvent: sendPageVisitedEventPublic, sendPdpVisitedEvent: sendPdpVisitedEventPublic, sendAddToCartEvent: sendAddToCartEventPublic, sendRemoveFromCartEvent: sendRemoveFromCartEventPublic, sendUpdateCartEvent: sendUpdateCartEventPublic, sendDeclineTrackingEvent: sendDeclineTrackingEventPublic, sendSearchEvent: sendSearchEventPublic, sendSearchResultEvent: sendSearchResultEventPublic, sendClickoutEvent: sendClickoutEventPublic, sendPurchaseEvent: sendPurchaseEventPublic, sendLeadGenEvent: sendLeadGenEventPublic, // Utility methods disableTracking, enableTracking, getNumericPriceFromString, // private setSignalReady, }; } } // ------------------------- core ------------------------- function reactOnLoad() { const pageLoadRules = script.rows.filter(row => row.trigger.type === triggerTypes.PAGE_LOAD); const handler = (event) => { observeAndReactOnPageChange(() => { evaluateRules(pageLoadRules, event); sendSuccessfulExecutionEvent(); }); }; // Check if page already loaded if (document.readyState === "complete") { handler(new Event('load')); } else { window.addEventListener("load", handler, {capture: true}); } } function reactOnClick() { const clickRules = script.rows.filter(row => row.trigger.type === triggerTypes.CLICK); // click via mouse document.querySelector('body').addEventListener('mousedown', (event) => { evaluateRules(clickRules, event); sendSuccessfulExecutionEvent() }, {capture: true}); // click via enter button document.querySelector('body').addEventListener('keydown', (event) => { if (event.code === "Enter" || event.code === "NumpadEnter") { evaluateRules(clickRules, event); sendSuccessfulExecutionEvent() } }, {capture: true}); } function reactOnInput() { const inputRules = script.rows.filter(row => row.trigger.type === triggerTypes.INPUT); document.querySelector('body').addEventListener('input', function (event) { evaluateRules(inputRules, event); sendSuccessfulExecutionEvent() }, {capture: true}); } function reactOnMouseLeave() { document.addEventListener("mouseleave", function (event) { if (event.clientY <= 0 || event.clientX <= 0 || (event.clientX >= window.innerWidth || event.clientY >= window.innerHeight)) { sendSuccessfulExecutionEvent(true) } }); } // Expose API immediately - doesn't require DOM or event listeners exposeTrackingApi(); function track() { try { executeAdvancedCode(); reactOnLoad(); reactOnClick(); reactOnInput(); reactOnMouseLeave(); } catch (error) { console.debug("Tracking disabled", error); } } // RUN SCRIPT AFTER PAGE LOAD if (document.readyState === "loading" || document.readyState === "interactive") { // Loading hasn't finished yet document.addEventListener("readystatechange", (event) => { if (event.target.readyState === "complete") { track(); } }); } else { track(); } })();