{"id":42,"date":"2025-09-27T14:05:03","date_gmt":"2025-09-27T14:05:03","guid":{"rendered":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/datalayer-template-matomo-tracking\/"},"modified":"2025-09-27T14:05:03","modified_gmt":"2025-09-27T14:05:03","slug":"datalayer-template-matomo-tracking","status":"publish","type":"page","link":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/datalayer-template-matomo-tracking\/","title":{"rendered":"DataLayer Template &#8211; Matomo Tracking"},"content":{"rendered":"<p><!-- Matomo DataLayer Template for WordPress --><br \/>\n<script>\n\/\/ Initialize Matomo DataLayer - Universal Template\nwindow.matomoDataLayer = window.matomoDataLayer || [];<\/p>\n<p>\/\/ Page Information Data Layer\nfunction initializePageDataLayer() {\n  \/\/ Get current page info\n  const pageInfo = {\n    'event': 'page_view',\n    'pageType': document.body.classList.contains('single-post') ? 'blog-post' : \n                document.body.classList.contains('page') ? 'page' : \n                document.body.classList.contains('home') ? 'homepage' : 'other',\n    'pageTitle': document.title,\n    'pageUrl': window.location.href,\n    'pageReferrer': document.referrer || 'direct',\n    'userAgent': navigator.userAgent,\n    'language': navigator.language || 'en',\n    'timestamp': new Date().toISOString(),\n    'sessionId': generateSessionId(),\n    'userId': getUserId(), \/\/ If available\n    'visitorType': getVisitorType(),\n    'deviceType': getDeviceType(),\n    'browserInfo': getBrowserInfo(),\n    'screenResolution': screen.width + 'x' + screen.height,\n    'viewportSize': window.innerWidth + 'x' + window.innerHeight,\n    'colorDepth': screen.colorDepth,\n    'timezone': Intl.DateTimeFormat().resolvedOptions().timeZone,\n    'connectionType': getConnectionType()\n  };<\/p>\n<p>  \/\/ WordPress specific data\n  if (window.wp && window.wp.data) {\n    pageInfo.wordpressVersion = window.wp.data.select('core').getSite()?.version || 'unknown';\n  }<\/p>\n<p>  \/\/ Push to dataLayer\n  window.matomoDataLayer.push(pageInfo);\n  console.log('Matomo DataLayer initialized:', pageInfo);\n}<\/p>\n<p>\/\/ Helper Functions\nfunction generateSessionId() {\n  let sessionId = sessionStorage.getItem('matomo_session_id');\n  if (!sessionId) {\n    sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);\n    sessionStorage.setItem('matomo_session_id', sessionId);\n  }\n  return sessionId;\n}<\/p>\n<p>function getUserId() {\n  \/\/ Return logged-in user ID if available\n  return localStorage.getItem('user_id') || 'anonymous';\n}<\/p>\n<p>function getVisitorType() {\n  const returningVisitor = localStorage.getItem('matomo_returning_visitor');\n  if (!returningVisitor) {\n    localStorage.setItem('matomo_returning_visitor', 'true');\n    return 'new';\n  }\n  return 'returning';\n}<\/p>\n<p>function getDeviceType() {\n  const userAgent = navigator.userAgent;\n  if (\/tablet|ipad|playbook|silk\/i.test(userAgent)) {\n    return 'tablet';\n  }\n  if (\/mobile|iphone|ipod|android|blackberry|opera|mini|windows\\sce|palm|smartphone|iemobile\/i.test(userAgent)) {\n    return 'mobile';\n  }\n  return 'desktop';\n}<\/p>\n<p>function getBrowserInfo() {\n  const userAgent = navigator.userAgent;\n  let browser = 'unknown';<\/p>\n<p>  if (userAgent.indexOf('Chrome') > -1) browser = 'Chrome';\n  else if (userAgent.indexOf('Safari') > -1) browser = 'Safari';\n  else if (userAgent.indexOf('Firefox') > -1) browser = 'Firefox';\n  else if (userAgent.indexOf('Edge') > -1) browser = 'Edge';\n  else if (userAgent.indexOf('Opera') > -1) browser = 'Opera';<\/p>\n<p>  return {\n    name: browser,\n    version: getBrowserVersion(userAgent),\n    userAgent: userAgent\n  };\n}<\/p>\n<p>function getBrowserVersion(userAgent) {\n  const match = userAgent.match(\/(chrome|safari|firefox|edge|opera)\\\/(\\d+)\/i);\n  return match ? match[2] : 'unknown';\n}<\/p>\n<p>function getConnectionType() {\n  if ('connection' in navigator) {\n    return navigator.connection.effectiveType || 'unknown';\n  }\n  return 'unknown';\n}<\/p>\n<p>\/\/ Enhanced Event Tracking Functions\nfunction trackCustomEvent(eventName, eventData = {}) {\n  const eventPayload = {\n    'event': eventName,\n    'timestamp': new Date().toISOString(),\n    'sessionId': generateSessionId(),\n    'pageUrl': window.location.href,\n    ...eventData\n  };<\/p>\n<p>  window.matomoDataLayer.push(eventPayload);\n  console.log('Custom event tracked:', eventPayload);\n}<\/p>\n<p>\/\/ Form Tracking\nfunction trackFormSubmission(formId, formName = '') {\n  trackCustomEvent('form_submission', {\n    'formId': formId,\n    'formName': formName || formId,\n    'formUrl': window.location.href\n  });\n}<\/p>\n<p>\/\/ Download Tracking\nfunction trackDownload(fileName, fileType, fileSize = null) {\n  trackCustomEvent('file_download', {\n    'fileName': fileName,\n    'fileType': fileType,\n    'fileSize': fileSize,\n    'downloadUrl': window.location.href\n  });\n}<\/p>\n<p>\/\/ Video Tracking\nfunction trackVideoEvent(videoTitle, action, currentTime = 0, totalDuration = 0) {\n  trackCustomEvent('video_' + action, {\n    'videoTitle': videoTitle,\n    'videoAction': action,\n    'videoCurrentTime': currentTime,\n    'videoDuration': totalDuration,\n    'videoProgress': totalDuration > 0 ? Math.round((currentTime \/ totalDuration) * 100) : 0\n  });\n}<\/p>\n<p>\/\/ Scroll Depth Tracking\nlet scrollDepthTracked = [];\nfunction initScrollTracking() {\n  window.addEventListener('scroll', function() {\n    const scrollPercent = Math.round((window.scrollY \/ (document.body.scrollHeight - window.innerHeight)) * 100);<\/p>\n<p>    [25, 50, 75, 90, 100].forEach(threshold => {\n      if (scrollPercent >= threshold && !scrollDepthTracked.includes(threshold)) {\n        scrollDepthTracked.push(threshold);\n        trackCustomEvent('scroll_depth', {\n          'scrollDepth': threshold,\n          'scrollPixels': window.scrollY,\n          'documentHeight': document.body.scrollHeight,\n          'windowHeight': window.innerHeight\n        });\n      }\n    });\n  });\n}<\/p>\n<p>\/\/ Time on Page Tracking\nfunction initTimeTracking() {\n  const startTime = Date.now();<\/p>\n<p>  [30, 60, 120, 300, 600].forEach(seconds => {\n    setTimeout(function() {\n      trackCustomEvent('time_on_page', {\n        'timeOnPage': seconds,\n        'timeUnit': 'seconds',\n        'engagementLevel': seconds >= 300 ? 'high' : seconds >= 120 ? 'medium' : 'low'\n      });\n    }, seconds * 1000);\n  });\n}<\/p>\n<p>\/\/ Page Exit Detection\nfunction initExitTracking() {\n  window.addEventListener('beforeunload', function() {\n    const timeOnPage = Math.round((Date.now() - window.pageLoadTime) \/ 1000);\n    trackCustomEvent('page_exit', {\n      'exitType': 'beforeunload',\n      'timeOnPageBeforeExit': timeOnPage,\n      'scrollDepthAtExit': Math.round((window.scrollY \/ (document.body.scrollHeight - window.innerHeight)) * 100)\n    });\n  });<\/p>\n<p>  \/\/ Mouse leave detection for exit intent\n  document.addEventListener('mouseleave', function(e) {\n    if (e.clientY <= 0) {\n      trackCustomEvent('exit_intent', {\n        'exitType': 'mouse_leave',\n        'timeBeforeExit': Math.round((Date.now() - window.pageLoadTime) \/ 1000)\n      });\n    }\n  });\n}\n\n\/\/ E-commerce Tracking (if applicable)\nfunction trackPurchase(transactionId, items = [], totalValue = 0, currency = 'EUR') {\n  trackCustomEvent('purchase', {\n    'transactionId': transactionId,\n    'transactionItems': items,\n    'transactionValue': totalValue,\n    'transactionCurrency': currency,\n    'itemCount': items.length\n  });\n}\n\nfunction trackAddToCart(productId, productName, productPrice, productCategory = '') {\n  trackCustomEvent('add_to_cart', {\n    'productId': productId,\n    'productName': productName,\n    'productPrice': productPrice,\n    'productCategory': productCategory\n  });\n}\n\n\/\/ Initialize DataLayer on Page Load\ndocument.addEventListener('DOMContentLoaded', function() {\n  window.pageLoadTime = Date.now();\n  \n  \/\/ Initialize base tracking\n  initializePageDataLayer();\n  \n  \/\/ Initialize enhanced tracking\n  initScrollTracking();\n  initTimeTracking();\n  initExitTracking();\n  \n  \/\/ Auto-track external links\n  document.querySelectorAll('a[href^=\"http\"]').forEach(link => {\n    if (!link.href.includes(window.location.hostname)) {\n      link.addEventListener('click', function() {\n        trackCustomEvent('external_link_click', {\n          'linkUrl': this.href,\n          'linkText': this.innerText,\n          'linkTitle': this.title || ''\n        });\n      });\n    }\n  });<\/p>\n<p>  \/\/ Auto-track mailto links\n  document.querySelectorAll('a[href^=\"mailto:\"]').forEach(link => {\n    link.addEventListener('click', function() {\n      trackCustomEvent('email_click', {\n        'emailAddress': this.href.replace('mailto:', ''),\n        'linkText': this.innerText\n      });\n    });\n  });<\/p>\n<p>  \/\/ Auto-track tel links\n  document.querySelectorAll('a[href^=\"tel:\"]').forEach(link => {\n    link.addEventListener('click', function() {\n      trackCustomEvent('phone_click', {\n        'phoneNumber': this.href.replace('tel:', ''),\n        'linkText': this.innerText\n      });\n    });\n  });<\/p>\n<p>  console.log('Matomo DataLayer Template Loaded Successfully');\n});<\/p>\n<p>\/\/ Global function to track custom events from anywhere\nwindow.trackMatomoEvent = trackCustomEvent;\nwindow.trackMatomoForm = trackFormSubmission;\nwindow.trackMatomoDownload = trackDownload;\nwindow.trackMatomoVideo = trackVideoEvent;\n<\/script><\/p>\n<p><!-- Example Usage --><\/p>\n<div style=\"background: #f0f8ff; padding: 20px; border-radius: 8px; margin: 20px 0;\">\n<h3>DataLayer Template Documentation<\/h3>\n<p>This page contains a comprehensive Matomo DataLayer template that can be used across your WordPress site.<\/p>\n<h4>Features Included:<\/h4>\n<ul>\n<li>\u2705 Automatic page view tracking with device and browser detection<\/li>\n<li>\u2705 Scroll depth tracking (25%, 50%, 75%, 90%, 100%)<\/li>\n<li>\u2705 Time on page milestones<\/li>\n<li>\u2705 Exit intent detection<\/li>\n<li>\u2705 Automatic external link tracking<\/li>\n<li>\u2705 Email and phone link tracking<\/li>\n<li>\u2705 Form submission tracking<\/li>\n<li>\u2705 Download tracking<\/li>\n<li>\u2705 Video interaction tracking<\/li>\n<li>\u2705 E-commerce tracking functions<\/li>\n<\/ul>\n<h4>Test the DataLayer:<\/h4>\n<p>  <button onclick=\"trackMatomoEvent('test_button_click', {buttonName: 'Test Button', buttonColor: 'blue'})\" \n          style=\"background: #007cba; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; margin: 5px;\"><br \/>\n    Test Custom Event<br \/>\n  <\/button><\/p>\n<p>  <button onclick=\"trackMatomoForm('test-form', 'Newsletter Signup')\" \n          style=\"background: #28a745; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; margin: 5px;\"><br \/>\n    Test Form Tracking<br \/>\n  <\/button><\/p>\n<p>  <a href=\"mailto:test@example.com\" style=\"background: #dc3545; color: white; padding: 10px 20px; border-radius: 4px; text-decoration: none; margin: 5px; display: inline-block;\"><br \/>\n    Test Email Tracking<br \/>\n  <\/a><\/p>\n<p><strong>Open your browser&#8217;s developer console to see the dataLayer events being tracked!<\/strong><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>DataLayer Template Documentation This page contains a comprehensive Matomo DataLayer template that can be used across your WordPress site. Features Included: \u2705 Automatic page view tracking with device and browser detection \u2705 Scroll depth tracking (25%, 50%, 75%, 90%, 100%) \u2705 Time on page milestones \u2705 Exit intent detection \u2705 Automatic external link tracking \u2705 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-42","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/pages\/42","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/comments?post=42"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/pages\/42\/revisions"}],"wp:attachment":[{"href":"https:\/\/wordpress.ronan-chardonneau.online\/index.php\/wp-json\/wp\/v2\/media?parent=42"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}