Skip to main content
Jesuits
Euro-Mediterranean Province of the Society of Jesus

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(); );

<!-- Heartbeat Tracker --> <script src="matomo-heartbeat.js"></script>

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);

public function getEngagementMetrics($dateFrom, $dateTo) $stmt = $this->db->prepare(" SELECT COUNT(DISTINCT session_id) as total_sessions, SUM(total_engaged_time) as total_engagement_seconds, AVG(total_engaged_time) as avg_engagement_seconds, AVG(heartbeat_count) as avg_heartbeats_per_session, COUNT(CASE WHEN total_engaged_time > 60 THEN 1 END) as long_sessions, COUNT(CASE WHEN total_engaged_time < 10 THEN 1 END) as bounce_sessions FROM matomo_heartbeat_sessions WHERE start_time BETWEEN ? AND ? AND is_active = 0 "); $stmt->execute([$dateFrom, $dateTo]); $metrics = $stmt->fetch(PDO::FETCH_ASSOC); if ($metrics['total_sessions'] > 0) $metrics['bounce_rate'] = ($metrics['bounce_sessions'] / $metrics['total_sessions']) * 100; $metrics['engagement_rate'] = ($metrics['long_sessions'] / $metrics['total_sessions']) * 100; return $metrics;

private function sendToMatomo($data) $url = $this->matomoUrl . '/matomo.php?' . http_build_query($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 2); // Quick timeout $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $httpCode === 200;

Latest news
View all news

Matomo Heartbeat Free May 2026

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(); );

<!-- Heartbeat Tracker --> <script src="matomo-heartbeat.js"></script> 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); '/matomo

public function getEngagementMetrics($dateFrom, $dateTo) $stmt = $this->db->prepare(" SELECT COUNT(DISTINCT session_id) as total_sessions, SUM(total_engaged_time) as total_engagement_seconds, AVG(total_engaged_time) as avg_engagement_seconds, AVG(heartbeat_count) as avg_heartbeats_per_session, COUNT(CASE WHEN total_engaged_time > 60 THEN 1 END) as long_sessions, COUNT(CASE WHEN total_engaged_time < 10 THEN 1 END) as bounce_sessions FROM matomo_heartbeat_sessions WHERE start_time BETWEEN ? AND ? AND is_active = 0 "); $stmt->execute([$dateFrom, $dateTo]); $metrics = $stmt->fetch(PDO::FETCH_ASSOC); if ($metrics['total_sessions'] > 0) $metrics['bounce_rate'] = ($metrics['bounce_sessions'] / $metrics['total_sessions']) * 100; $metrics['engagement_rate'] = ($metrics['long_sessions'] / $metrics['total_sessions']) * 100; return $metrics; '/matomo.php?' . http_build_query($data)

private function sendToMatomo($data) $url = $this->matomoUrl . '/matomo.php?' . http_build_query($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 2); // Quick timeout $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $httpCode === 200;