### Setup and Build Commands for dataslayer Source: https://github.com/sean-adams/dataslayer/blob/master/CLAUDE.md Provides essential npm commands for setting up the project, building for production, and packaging the extension for distribution. ```bash npm install npm run build # Creates production build in ./build/ folder npm run package # Builds and creates package.zip for distribution ``` -------------------------------- ### Development Commands for dataslayer Source: https://github.com/sean-adams/dataslayer/blob/master/CLAUDE.md Lists npm commands for local development, running tests, and starting the development server for UI-only development. ```bash npm start # Starts local dev server with demo data (UI development only) npm test # Runs React test suite ``` -------------------------------- ### dataslayer Chrome Extension Manifest v3 Configuration Source: https://github.com/sean-adams/dataslayer/blob/master/CLAUDE.md Example of a Manifest v3 configuration file for the dataslayer Chrome extension, detailing service worker, action, and scripting details. ```json { "manifest_version": 3, "name": "dataslayer", "version": "2.0.0", "description": "Debug tag management systems and analytics implementations.", "permissions": [ "storage", "scripting", "webRequest" ], "host_permissions": [ "" ], "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": [""], "js": ["content.js", "inject.js"], "run_at": "document_start" } ], "action": { "default_popup": "index.html", "default_icon": { "16": "logo16.png", "48": "logo48.png", "128": "logo128.png" } }, "devtools_page": "devtools.html", "icons": { "16": "logo16.png", "48": "logo48.png", "128": "logo128.png" } } ``` -------------------------------- ### Loading dataslayer Extension in Browsers Source: https://github.com/sean-adams/dataslayer/blob/master/CLAUDE.md Instructions for loading the built dataslayer extension in Chrome and Firefox for testing purposes. ```bash # Chrome: Enable Developer mode at chrome://extensions/ → Load unpacked from "./build/" # Firefox: Go to about:debugging → Load Temporary Add-on from "./build/manifest.json" ``` -------------------------------- ### Manage Page Navigation and History (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Handles new page loads by creating new entries for data layer, tag history, URLs, and timestamps. It also renders all pages in reverse chronological order, displaying relevant data for each. Dependencies include the component's state and potentially a `Page` component. ```javascript // App.js - Handling new page navigation newPageLoad = (newurl) => { let newIndex = this.state.activeIndex + 1; let { datalayers, GTMs, urls, timestamps, tags } = this.state; datalayers[newIndex] = {}; GTMs[newIndex] = []; urls[newIndex] = newurl; timestamps[newIndex] = new Date().valueOf(); tags[newIndex] = []; this.setState({ loading: true, activeIndex: newIndex, datalayers, GTMs, urls, timestamps, tags }); if (isDevTools()) { chrome.runtime.sendMessage({ type: 'dataslayer_pageload', tabId: chrome.devtools.inspectedWindow.tabId }); } } // Rendering all pages in reverse chronological order render() { let pages = []; for (let a = this.state.urls.length - 1; a >= 0; a--) { let pageData = { GTM: this.state.GTMs[a], datalayers: this.state.datalayers[a], tags: this.state.tags[a], utagDatas: this.state.utagDatas[a], dtmDatas: this.state.dtmDatas[a] }; if (this.state.urls[a]) { pages.push( ); } } return pages; } ``` -------------------------------- ### Manage Settings and Options (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Handles loading, setting, and synchronizing user preferences for tag filtering, data layer display, and custom names. It utilizes localStorage for persistence and Chrome's sync storage for cross-device synchronization. Missing default options are filled in automatically. ```javascript // App.js - Loading and setting options loadSettings = () => { let options = Object.assign({}, defaults); try { if (typeof localStorage.options !== 'undefined') { options = JSON.parse(localStorage.options); } } catch (error) { console.log(error); } // Fill in any missing defaults for (let option of Object.keys(defaults)) { if (!options.hasOwnProperty(option)) { options[option] = defaults[option]; } } this.setState({ options }); if (isDevTools()) { chrome.storage.sync.get(null, (items) => { options = items; for (let option of Object.keys(defaults)) { if (!options.hasOwnProperty(option)) { options[option] = defaults[option]; } } localStorage.options = JSON.stringify(options); this.setState({ options }); }); } } setOption = (option, value) => { let options = this.state.options; if (typeof value === 'boolean') { options[option] = value; } else if (typeof value === 'string') { options[option] = value.length === 0 ? [] : value.split(';'); } try { localStorage['options'] = JSON.stringify(options); } catch(error) { console.log(error); } if (isDevTools()) { chrome.storage.sync.set(options); } this.setState({ options }); } ``` -------------------------------- ### Inject Content Scripts for Data Layer Monitoring (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Manages the injection of content scripts into web pages. The background script listens for specific messages ('dataslayer_opened', 'dataslayer_pageload') and uses the chrome.scripting.executeScript API to inject 'content.js'. The 'content.js' script then dynamically creates and appends a monitoring script, configured with data layer names and update intervals from sync storage. ```javascript // background.js - Injecting content script using Manifest v3 API chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { if (message.type === 'dataslayer_opened' || message.type === 'dataslayer_pageload') { chrome.scripting.executeScript({ target: { tabId: message.tabId, allFrames: true }, files: ['content.js'] }); } }); // content.js - Listening for messages and injecting monitoring script if (document.getElementById('dataslayer_script') === null) { var dataslayers = document.createElement('script'); dataslayers.id = 'dataslayer_script'; dataslayers.src = chrome.runtime.getURL('inject.js'); dataslayers.type = 'text/javascript'; chrome.storage.sync.get(null, function(items) { if (items.hasOwnProperty('dataLayers')) { dataslayers.setAttribute('data-layers', items.dataLayers.join(';')); } if (items.hasOwnProperty('updateInterval')) { dataslayers.setAttribute('data-interval', items.updateInterval); } document.head.appendChild(dataslayers); }); } ``` -------------------------------- ### Export and Import Debugging Session Data (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Handles exporting the current debugging session state to a JSON file and importing previously saved sessions for analysis. It uses browser APIs for file handling and JSON parsing. The export function creates a JSON string of the current state and triggers a download, while the import function reads a file, parses its JSON content, and updates the application state. ```javascript // App.js - Exporting current state handleExport = () => { const exportData = { datalayers: this.state.datalayers, utagDatas: this.state.utagDatas, tcoDatas: this.state.tcoDatas, varDatas: this.state.varDatas, dtmDatas: this.state.dtmDatas, tags: this.state.tags, GTMs: this.state.GTMs, urls: this.state.urls, timestamps: this.state.timestamps }; const dataStr = JSON.stringify(exportData, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `dataslayer-${timestamp()}.json`; link.click(); } // Importing previous session importFile = (e, callback) => { let file = e.target.files[0]; if (!file) { callback({ success: false }); } let reader = new FileReader(); reader.onload = (loaded) => { let contents = loaded.target.result; let parsed; try { parsed = JSON.parse(contents); this.clearHistory(); this.setState({ ...parsed }); this.forceUpdate(); callback({ success: true }); } catch (error) { callback({ success: false, message: 'Malformed JSON in import' }); } }; reader.readAsText(file); } ``` -------------------------------- ### Data Layer Monitoring: GTM Container Detection and Push Monitoring (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt This snippet from inject.js shows how Dataslayer detects Google Tag Manager containers by searching for specific script tags. It then uses the DataLayerHelper library to monitor data layer pushes, posting relevant information back to the parent window. Dependencies include the DataLayerHelper library and the browser's window object. ```javascript // inject.js - Detecting GTM containers dataslayer.gtmSearch = function() { var gtmList = document.querySelectorAll('script[src*=googletagmanager\.com]'); if (gtmList.length > 0) { for (var i = 0; i < gtmList.length; i++) { var gtmLocation = new URL(gtmList[i].src); dataslayer.gtmID[i] = gtmLocation.searchParams.get('id'); dataslayer.dLN[i] = gtmLocation.searchParams.get('l') || 'dataLayer'; if (typeof window[dataslayer.dLN[i]] !== 'undefined' && dataslayer.gtmAnnounced.indexOf(dataslayer.gtmID[i]) == -1) { dataslayer.gtmAnnounced.push(dataslayer.gtmID[i]); window.parent.postMessage({ type: 'dataslayer_gtm', data: 'found', gtmID: dataslayer.gtmID[i], dLN: dataslayer.dLN[i] }, '*'); // Create helper to monitor pushes dataslayer.helper[dataslayer.dLN[i]] = new DataLayerHelper( window[dataslayer.dLN[i]], dataslayer.helperListener, true, i ); } } } }; // Listener that fires on each data layer push dataslayer.helperListener = function(message, model) { window.parent.postMessage({ type: 'dataslayer_gtm_push', dLN: dataslayer.dLN[this.z], url: window == window.parent ? window.location.href : 'iframe', data: JSON.stringify(dataslayer.sanitize(model)) }, '*'); }; ``` -------------------------------- ### Extension Messaging: Background to DevTools Panel (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt This snippet demonstrates how the background script in the Dataslayer extension listens for 'dataslayer_gtm_push' messages from content scripts and forwards them to the DevTools panel. It highlights the use of chrome.runtime.onMessage and postMessage for inter-context communication. ```javascript // Background script receiving message from content script chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { if (message.type === 'dataslayer_gtm_push') { // Forward to DevTools panel message.tabId = sender.tab.id; devtoolsPort.forEach(function(v, i, x) { try { v.postMessage(message); } catch (e) { console.log(e); } }); } }); // App.js receiving message in DevTools panel messageListener = (message, sender, sendResponse) => { if ((message.type === 'dataslayer_gtm_push') && (message.tabId === chrome.devtools.inspectedWindow.tabId)) { let datalayers = this.state.datalayers; if (datalayers[this.state.activeIndex].hasOwnProperty(message.dLN)) { datalayers[this.state.activeIndex][message.dLN].push(JSON.parse(message.data)); } else { datalayers[this.state.activeIndex][message.dLN] = [JSON.parse(message.data)]; } this.setState({ datalayers }); } } ``` -------------------------------- ### Monitor Tealium UDO and Collapse Dot Notation (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Monitors Tealium's utag_data object by periodically checking for its existence. It captures the UDO name and ID, and upon finding the UDO, sends a message to the parent window and sets up a listener to send subsequent changes after sanitizing and collapsing dot-notation properties into nested objects. ```javascript // inject.js - Monitoring Tealium dataslayer.tlmTimerID = window.setInterval(function() { if (window.hasOwnProperty('utag')) { dataslayer.udoname = window.utag.udoname; dataslayer.utagID = window.utag.id; } if (typeof window[dataslayer.udoname] !== 'undefined') { window.parent.postMessage({ type: 'dataslayer_tlm', data: 'found', gtmID: dataslayer.utagID, dLN: dataslayer.udoname }, '*'); window.clearInterval(dataslayer.tlmTimerID); dataslayer.tlmHelperListener(); } }, 200); dataslayer.tlmHelperListener = function(change) { if (typeof window[dataslayer.udoname] !== 'undefined') { window.parent.postMessage({ type: 'dataslayer_tlm', gtmID: dataslayer.utagID, dLN: dataslayer.udoname, data: JSON.stringify(dataslayer.sanitize(window[dataslayer.udoname])) }, '*'); } }; // App.js - Collapsing Tealium UDO notation function collapseUDO(udo) { let newUDO = {}; let props = Object.getOwnPropertyNames(udo).sort(); for (let i in props) { let stack = props[i].split('.'); if (stack.length === 1) { newUDO[stack[0]] = udo[stack[0]]; } else { newUDO[stack[0]] = newUDO[stack[0]] || {}; newUDO[stack[0]] = collapseStack(newUDO[stack[0]], stack.slice(1), udo[props[i]]); } } return newUDO; } ``` -------------------------------- ### Extract Adobe Launch Data Elements (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Extracts and monitors all data elements defined in Adobe Launch (_satellite._container.dataElements). It retrieves the current value for each element, handling functions, Promises, and standard values, then posts this data to the parent window. A content script listener is included to trigger a refresh of these elements. ```javascript // inject.js - Loading Adobe Launch data elements dataslayer.loadLaunchDataElements = function() { if (window._satellite && window._satellite._container && window._satellite._container.dataElements) { var elementNames = Object.keys(window._satellite._container.dataElements).sort(); let launchElements = {}; for (const elementName of elementNames) { let cleanValue = window._satellite.getVar(elementName); if (typeof cleanValue === 'function') { cleanValue = '(function)'; } else if (cleanValue !== null && typeof cleanValue === 'object' && typeof cleanValue.then === 'function') { cleanValue = '(Promise)'; } launchElements[elementName] = cleanValue; } window.parent.postMessage({ type: 'dataslayer_launchdataelements', data: 'found', elements: launchElements }, '*'); } }; // Content script can request refresh chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if (request.ask == 'refreshLaunchDataElements') { const refreshTag = document.createElement('script'); refreshTag.type = 'text/javascript'; refreshTag.innerHTML = 'dataslayer.loadLaunchDataElements();'; document.head.appendChild(refreshTag); } }); ``` -------------------------------- ### Parse Universal Analytics and GA4 Tags (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Parses Universal Analytics and GA4 tags to extract custom dimensions, metrics, event parameters, and user parameters. It handles different tag types for Universal Analytics and distinguishes between event and user parameters for GA4. Dependencies include the data object containing tag information. ```javascript // Tags.js - Parsing Universal Analytics const parseUniversal = (data, keyPrefix = '') => { let params = []; switch (data.t) { case 'event': params.push( category{data.ec}, action{data.ea} ); if (data.el) params.push( label{data.el} ); if (data.ev) params.push( value{data.ev} ); break; case 'pageview': params.push( path{data.dp || data.dl} ); break; } // Extract custom dimensions and metrics for (let cd in data.utmCD) { params.push( CD {cd}{data.utmCD[cd]} ); } for (let cm in data.utmCM) { params.push( CM {cm}{data.utmCM[cm]} ); } return params; }; // Parsing GA4 event and user parameters const parseGA4 = (data, keyPrefix = '') => { let params = []; const { allParams } = data; let eventParams = []; let userParams = []; if (allParams.en) { params.push( event name{allParams.en} ); } for (const key of Object.keys(allParams).sort()) { if (/^epn?\..*/gi.test(key)) { eventParams.push({ key: key.replace(/^epn?\..*/gi, ''), value: allParams[key] }); } else if (/^upn?\..*/gi.test(key)) { userParams.push({ key: key.replace(/^upn?\..*/gi, ''), value: allParams[key] }); } } if (eventParams.length > 0) { params.push(event parameters); for (const eParam of eventParams) { params.push( {eParam.key} {eParam.value} ); } } return params; }; ``` -------------------------------- ### Intercept and Parse Analytics Requests (JavaScript) Source: https://context7.com/sean-adams/dataslayer/llms.txt Intercepts network requests using Chrome's DevTools API to identify and parse analytics tags from various vendors like Google Analytics (classic, GA4, universal), Adobe SiteCatalyst. It parses query parameters and post data, classifying requests by type. ```javascript // App.js - Intercepting and parsing analytics requests newRequest = (request) => { let reqType = ''; if (/__utm\.gif/i.test(request.request.url)) { reqType = 'classic'; } else if (/(analytics\.google)\.com\/(.\/)?collect/i.test(request.request.url)) { reqType = 'ga4'; } else if (/google-analytics\.com\/(.\/)?collect/i.test(request.request.url)) { reqType = 'universal'; } else if (//b\/ss\//i.test(request.request.url)) { reqType = 'sitecatalyst'; } else { return; // Not a tag we're tracking } let requestURI = request.request.method === 'GET' ? request.request.url.split('?')[1] : request.request.postData.text; // Parse query string into key/value pairs let queryParams = {}; requestURI.split('&').forEach((pair) => { pair = pair.split('='); queryParams[pair[0]] = decodeURIComponent(pair[1] || ''); }); let utmParams = { reqType, allParams: queryParams, __url: request.request.url, __uuid: uuid() }; let tags = this.state.tags; tags[this.state.activeIndex].push(utmParams); this.setState({ tags }); } // Setup network listener in componentDidMount chrome.devtools.network.onRequestFinished.addListener(this.newRequest); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.