header('Content-Type: application/json'); echo json_encode($result); <!DOCTYPE html> <html> <head> <!-- Matomo Tracking Code --> <script> var _paq = window._paq = window._paq || []; _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() var u="https://your-matomo-domain.com/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); )(); </script>
bindEvents() // Track user activity events const activityEvents = ['mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart', 'click']; activityEvents.forEach(event => document.addEventListener(event, () => this.resetIdleTimer()); ); // Page visibility API document.addEventListener('visibilitychange', () => if (document.hidden) this.stopHeartbeat(); this.log('Page hidden, stopping heartbeat'); else this.startHeartbeat(); this.log('Page visible, starting heartbeat'); ); // Before page unload window.addEventListener('beforeunload', () => this.sendFinalHeartbeat(); );
<?php // matomo-heartbeat-handler.php class MatomoHeartbeatHandler private $matomoUrl; private $siteId; private $tokenAuth; public function __construct($matomoUrl, $siteId, $tokenAuth = null) $this->matomoUrl = rtrim($matomoUrl, '/'); $this->siteId = $siteId; $this->tokenAuth = $tokenAuth; matomo heartbeat
public function getEngagementReport($dateRange = 'last30') $apiUrl = $this->matomoUrl . '/index.php'; $params = [ 'module' => 'API', 'method' => 'CustomEvents.getCustomEvent', 'idSite' => $this->siteId, 'period' => 'range', 'date' => $dateRange, 'format' => 'json', 'filter_limit' => -1 ]; if ($this->tokenAuth) $params['token_auth'] = $this->tokenAuth; $url = $apiUrl . '?' . http_build_query($params); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true);
<!-- Heartbeat Tracker --> <script src="matomo-heartbeat.js"></script> JavaScript Heartbeat Tracker // matomo-heartbeat
I'll help you develop a Matomo Heartbeat feature. This feature tracks user engagement time more accurately by sending periodic heartbeats to Matomo analytics. 1. JavaScript Heartbeat Tracker // matomo-heartbeat.js class MatomoHeartbeat { constructor(options = {}) this.options = heartbeatInterval: 15, // seconds minVisitLength: 5, // minimum seconds for a valid visit idleTimeout: 30, // seconds of inactivity to stop heartbeat debug: false, ...options ; this.intervalId = null; this.idleCheckId = null; this.lastActivity = Date.now(); this.visitStartTime = null; this.totalEngagedTime = 0; this.isActive = false; this.lastHeartbeatTime = null; this.init();
sendBeacon(data) // Use sendBeacon for reliable final tracking if (navigator.sendBeacon) const formData = new FormData(); Object.keys(data).forEach(key => formData.append(key, data[key]); ); navigator.sendBeacon('/matomo.php', formData); // seconds minVisitLength: 5
sendFinalHeartbeat() if (this.isActive && this.lastHeartbeatTime) const engagedTime = Math.floor((Date.now() - this.lastHeartbeatTime) / 1000); if (engagedTime >= this.options.minVisitLength) const finalData = action_name: 'Final Heartbeat', e_c: 'Engagement', e_a: 'end', e_n: 'Session End', e_v: engagedTime, total_engaged: this.totalEngagedTime + engagedTime ; if (window._paq) window._paq.push(['trackEvent', finalData.e_c, finalData.e_a, finalData.e_n, finalData.e_v]); // Use synchronous ping for final heartbeat this.sendBeacon(finalData);