https://industryofallnations.com/cdn/shop/t/283/assets/ioan-tracki…?v=126267797285542666381789449171
1/*! 2 * IOAN tracking capture v1.1.2 3 * Consent-aware capture of incoming UTM / Triple Whale identifiers into PRIVATE 4 * Shopify cart attributes, so they land on the resulting order's 5 * "Additional details" in the Shopify admin. 6 * 7 * Owner: Industry of All Nations - marketing ops 8 * Namespace: __ioan_tracking_* (double underscore = private cart attribute; 9 * not readable from Liquid or the Ajax API, visible on the order 10 * in the Shopify admin. Ref: shopify.dev/docs/api/ajax/reference/cart) 11 * Rule: last eligible tagged landing for the current cart. 12 * 13 * What is stored, exactly: 14 * One sessionStorage key, "ioan_tracking_sig", whose value is 15 * "v3:" + fnv1a32(cartId + "|" + signature) 16 * - cartId = the cart token as returned in the /cart/update.js response of 17 * the write being recorded, with anything from "?" onward removed 18 * (the "?key=..." secret is never kept). No cookie is ever read. 19 * - signature = JSON.stringify of the ordered [field, value] pairs that were 20 * accepted (unambiguous: delimiter characters inside values 21 * cannot collide with field boundaries). 22 * The value is a 32-bit non-reversible digest (8 hex chars). It does not 23 * contain the campaign values or the cart token in plaintext. It is NOT a 24 * cryptographic guarantee; it is a dedupe key. It is written only after a 25 * consented cart write returned 2xx AND the response identified the cart that 26 * was written. If the cart identity is unknown (GET /cart.js failed, or the 27 * write response carried no token) nothing is persisted; that unidentified 28 * write is remembered in page memory only, and a later capture on the same 29 * page is always checked against a freshly read cart identity. 30 * The previous key is discarded the moment a new capture write is issued, so 31 * an uncertain or unidentified write can never leave stale proof behind. 32 * Before consent nothing is stored anywhere and no cart request is made. 33 * 34 * Write budget per page load: 35 * up to 3 capture writes and 3 cleanup writes. A capture is only issued while 36 * at least one cleanup write is still available, so a successful capture can 37 * always be withdrawn on the same page as long as the network cooperates. 38 * 39 * Cleanup limitation (stated, not guaranteed): 40 * On withdrawal this script issues ONE blanking request for its own namespace 41 * (queued behind any in-flight request). If that request fails, values that 42 * already reached the cart remain until a later successful cleanup or a new 43 * consented capture replaces them. There is deliberately no retry loop. 44 * Consent is re-checked at every write boundary, not only on the 45 * visitorConsentCollected event; a denial visible to the Customer Privacy API 46 * when a capture completes triggers one bounded cleanup whether or not its 47 * event has arrived. A withdrawal that is neither reported by the API nor 48 * delivered as an event cannot be acted on. 49 * 50 * Deliberately does NOT: wrap fetch/XHR, listen to cart or Rebuy events, 51 * rewrite links, read cookies, use localStorage, or block checkout. 52 * A failed capture must never prevent a purchase. 53 */(function(){"use strict";if(window.__ioanTrackingCaptureLoaded)return;window.__ioanTrackingCaptureLoaded=!0;var NS="__ioan_tracking_",VERSION="1.1.2",RULE="last_tagged_landing",FIELDS=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","tw_source","tw_adid"],META=["rule","version","captured_at","rejected"],MAX_LEN=128,MAX_CAPTURE_WRITES=3,MAX_CLEANUP_WRITES=3,SIG_KEY="ioan_tracking_sig",SIG_PREFIX="v3:",captureWrites=0,cleanupWrites=0,inFlight=!1,inFlightKind=null,queued=null,pending=null,epoch=0,dirty=!1,lastWrite=null;function clean(raw){if(typeof raw!="string")return null;var v=raw.replace(/[\x00-\x1F\x7F]/g,"").trim();return!v||(v.length>MAX_LEN&&(v=v.slice(0,MAX_LEN)),/\{\{|\}\}|%7B%7B/i.test(v))||/^__[A-Za-z0-9_]+__$/.test(v)?null:v}function validAdId(v){return/^[0-9]{1,32}$/.test(v)?v:null}function readSnapshot(){var params;try{params=new URLSearchParams(window.location.search)}catch(e){return null}for(var values={},rejected=[],present=!1,i=0;i<FIELDS.length;
53i++){var key=FIELDS[i];if(params.has(key)){present=!0;var v=clean(params.get(key));if(v===null){rejected.push(key);continue}if(key==="tw_adid"&&(v=validAdId(v),v===null)){rejected.push(key);continue}values[key]=v}}return!present||!Object.keys(values).length?null:{values:values,rejected:rejected}}function signature(values){for(var pairs=[],i=0;i<FIELDS.length;i++){var k=FIELDS[i];Object.prototype.hasOwnProperty.call(values,k)&&pairs.push([k,values[k]])}return JSON.stringify(pairs)}function fnv1a32(str){for(var h=2166136261,i=0;i<str.length;i++)h^=str.charCodeAt(i),h=h+((h<<1)+(h<<4)+(h<<7)+(h<<8)+(h<<24))>>>0;return("0000000"+h.toString(16)).slice(-8)}function cartIdFrom(cart){try{if(cart&&typeof cart.token=="string")return cart.token.split("?")[0]}catch(e){}return""}function dedupeKey(cartId,sig){return SIG_PREFIX+fnv1a32(cartId+"|"+sig)}function consentGranted(){try{var cp=window.Shopify&&window.Shopify.customerPrivacy;return!cp||typeof cp.marketingAllowed!="function"||typeof cp.analyticsProcessingAllowed!="function"?!1:cp.marketingAllowed()===!0&&cp.analyticsProcessingAllowed()===!0}catch(e){return!1}}function withPrivacyApi(cb){try{var S=window.Shopify;if(S&&S.customerPrivacy&&typeof S.customerPrivacy.marketingAllowed=="function"){cb();return}S&&typeof S.loadFeatures=="function"&&S.loadFeatures([{name:"consent-tracking-api",version:"0.1"}],function(err){if(!err)try{cb()}catch(e){}})}catch(e){}}function readSig(){try{return window.sessionStorage.getItem(SIG_KEY)}catch(e){return null}}function writeSig(v){try{window.sessionStorage.setItem(SIG_KEY,v)}catch(e){}}function dropSig(){try{window.sessionStorage.removeItem(SIG_KEY)}catch(e){}}function forgetCaptured(){dropSig(),lastWrite=null}function root(){try{if(window.Shopify&&window.Shopify.routes&&window.Shopify.routes.root)return window.Shopify.routes.root}catch(e){}return"/"}function request(method,path,body,cb){var done=!1;function finish(ok,json){if(!done){done=!0;try{cb(ok,json)}catch(e){}}}try{var opts={method:method,headers:{Accept:"application/json"}};body!==void 0&&(opts.headers["Content-Type"]="application/json",opts.body=JSON.stringify(body)),window.fetch(root()+path,opts).then(function(res){var ok=!!(res&&res.ok),p=null;try{p=res.json()}catch(e){p=null}p&&typeof p.then=="function"?p.then(function(j){finish(ok,j)},function(){finish(ok,null)}):finish(ok,null)}).catch(function(){finish(!1,null)})}catch(e){finish(!1,null)}}function buildAttributes(values,rejected){for(var attrs={},i=0;i<FIELDS.length;i++){var k=FIELDS[i];attrs[NS+k]=Object.prototype.hasOwnProperty.call(values,k)?values[k]:""}return attrs[NS+"rule"]=RULE,attrs[NS+"version"]=VERSION,attrs[NS+"captured_at"]=new Date().toISOString(),attrs[NS+"rejected"]=rejected&&rejected.length?rejected.join(","):"",attrs}function blankAttributes(){var attrs={},i;for(i=0;i<FIELDS.length;i++)attrs[NS+FIELDS[i]]="";for(i=0;i<META.length;i++)attrs[NS+META[i]]="";return attrs}function runQueued(){var q=queued;queued=null,q==="capture"?attemptCapture():q==="cleanup"&&attemptCleanup()}function cleanupSlotAvailable(){return cleanupWrites<MAX_CLEANUP_WRITES}function withdraw(){var mayHaveWritten=dirty||readSig()!==null;forgetCaptured(),queued==="capture"&&(queued=null),mayHaveWritten&&queued!=="cleanup"&&(inFlight&&inFlightKind==="cleanup"||attemptCleanup())}function attemptCapture(){if(pending){if(inFlight){queued="capture";return}if(!(captureWrites>=MAX_CAPTURE_WRITES)&&cleanupSlotAvailable()&&consentGranted()){var myEpoch=epoch,snapshot=pending,sig=signature(snapshot.values);lastWrite&&lastWrite.sig===sig&&lastWrite.cartId===""||(inFlight=!0,inFlightKind="capture",request("GET","cart.js",void 0,function(ok,cart){if(myEpoch!==epoch||!consentGranted()){inFlight=!1,runQueued();return}var cartId=ok?cartIdFrom(cart):"",seenInMemory=lastWrite!==null&&lastWrite.sig===sig&&lastWrite.cartId===cartId;if(cartId&&(seenInMemory||readSig()===dedupeKey(cartId,sig))){inFlight=!1,runQueued();return}if(captureWrites>=MAX_CAPTURE_WRITES||!cleanupSlotAvailable()){inFlight=!1,runQueued();return}captureWrites++,dirty=!0,dropSig(),lastWrite=null,request("POST","cart/update.js",{attributes:buildAttributes(snapshot.values,snapshot.rejected)},function(ok2,updated){inFlight=!1;var grantedNow=consentGranted();if(ok2&&grantedNow){var writtenId=cartIdFrom(updated);lastWrite={sig:sig,cartId:writtenId},writtenId&&myEpoch===epoch&&writeSig(dedupeKey(writtenId,sig))}else grantedNow||(forgetCaptured(),queued="cleanup");runQueued()})}))}}}function attemptCleanup(){if(inFlight){queued="cleanup";return}cleanupSlotAvailable()&&(cleanupWrites++,inFlight=!0,inFlightKind="cleanup",request("POST","cart/update.js",{attributes:blankAttributes()},function(ok){inFlight=!1,ok&&(dirty=!1),runQueued()}))}function onConsentChange(){if(epoch++,consentGranted()){queued==="cleanup"&&(queued=null),attemptCapture();return}withdraw()}
53function start(){pending=readSnapshot();try{document.addEventListener("visitorConsentCollected",onConsentChange)}catch(e){}pending&&withPrivacyApi(function(){attemptCapture()})}try{start()}catch(e){}})(); 54//# sourceMappingURL=/cdn/shop/t/283/assets/ioan-tracking-capture.js.map?v=126267797285542666381789449171
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.