Matomo Heartbeat May 2026

init() this.bindEvents(); this.startIdleMonitoring(); this.log('Matomo Heartbeat initialized');

public function recordHeartbeat($sessionId, $visitorId, $pageUrl, $engagedTime = 0) $stmt = $this->db->prepare(" SELECT id, total_engaged_time, last_heartbeat FROM matomo_heartbeat_sessions WHERE session_id = ? AND is_active = 1 "); $stmt->execute([$sessionId]); $session = $stmt->fetch(PDO::FETCH_ASSOC); $now = new DateTime(); if ($session) // Update existing session $lastHeartbeat = new DateTime($session['last_heartbeat']); $interval = $now->getTimestamp() - $lastHeartbeat->getTimestamp(); // Validate heartbeat interval if ($interval <= $this->heartbeatTimeout) $newTotalTime = $session['total_engaged_time'] + min($engagedTime, $interval); $update = $this->db->prepare(" UPDATE matomo_heartbeat_sessions SET last_heartbeat = ?, total_engaged_time = ?, heartbeat_count = heartbeat_count + 1 WHERE id = ? "); $update->execute([$now->format('Y-m-d H:i:s'), $newTotalTime, $session['id']]); return ['status' => 'updated', 'total_time' => $newTotalTime]; else // Session expired $this->endSession($session['id']); return $this->createNewSession($sessionId, $visitorId, $pageUrl); else // Create new session return $this->createNewSession($sessionId, $visitorId, $pageUrl); matomo heartbeat

header('Content-Type: application/json'); echo json_encode(['success' => $result]); <?php // matomo-engagement-tracker.php class MatomoEngagementTracker private $db; private $heartbeatTimeout = 35; // seconds public function __construct($pdo) $this->db = $pdo; $this->createHeartbeatTable(); init() this

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(); ); $data = json_decode(file_get_contents('php://input')

private function endSession($sessionId) $stmt = $this->db->prepare(" UPDATE matomo_heartbeat_sessions SET is_active = 0 WHERE id = ? "); $stmt->execute([$sessionId]);

$data = json_decode(file_get_contents('php://input'), true); $result = $tracker->recordHeartbeat( session_id(), $data['visitor_id'] ?? '', $data['page_url'] ?? '', $data['engaged_time'] ?? 0 );