$ADMIN_USER,
'hash' => $hash,
'created' => date('Y-m-d H:i:s')
]));
chmod($configFile, 0600);
$_SESSION['analytics_auth'] = true;
$_SESSION['analytics_user'] = $ADMIN_USER;
header('Location: /analytics/');
exit;
}
}
// Show setup form
?>
HELP4BIS Analytics — Setup
HELP4BIS Analytics
First-time setup. Create your admin password.
= htmlspecialchars($setupError) ?>
HELP4BIS Analytics — Login
HELP4BIS Analytics
= htmlspecialchars($loginError) ?>
busyTimeout(5000);
}
// Date range
$range = $_GET['range'] ?? '7d';
$rangeMap = ['24h' => 1, '7d' => 7, '30d' => 30, '90d' => 90];
$days = $rangeMap[$range] ?? 7;
$since = date('Y-m-d', strtotime("-{$days} days"));
// Fetch metrics
$metrics = ['pageviews' => 0, 'unique_visitors' => 0, 'avg_duration' => 0, 'cta_clicks' => 0, 'form_submits' => 0, 'bounce_rate' => 0];
$topPages = [];
$topReferrers = [];
$topCTAs = [];
$dailyChart = [];
$scrollData = [];
if ($db) {
// Total pageviews
$r = $db->querySingle("SELECT COUNT(*) FROM events WHERE event='pageview' AND created_at >= '$since'");
$metrics['pageviews'] = (int)$r;
// Unique visitors
$r = $db->querySingle("SELECT COUNT(DISTINCT session_id) FROM events WHERE event='pageview' AND created_at >= '$since'");
$metrics['unique_visitors'] = (int)$r;
// Avg duration
$r = $db->querySingle("SELECT AVG(CAST(json_extract(extra,'$.seconds') AS REAL)) FROM events WHERE event='duration' AND created_at >= '$since'");
$metrics['avg_duration'] = round((float)$r, 1);
// CTA clicks
$r = $db->querySingle("SELECT COUNT(*) FROM events WHERE event='cta_click' AND created_at >= '$since'");
$metrics['cta_clicks'] = (int)$r;
// Form submits
$r = $db->querySingle("SELECT COUNT(*) FROM events WHERE event='form_submit' AND created_at >= '$since'");
$metrics['form_submits'] = (int)$r;
// Bounce rate (sessions with only 1 pageview)
$totalSessions = $db->querySingle("SELECT COUNT(DISTINCT session_id) FROM events WHERE event='pageview' AND created_at >= '$since'");
$singlePageSessions = $db->querySingle("SELECT COUNT(*) FROM (SELECT session_id, COUNT(*) as cnt FROM events WHERE event='pageview' AND created_at >= '$since' GROUP BY session_id HAVING cnt = 1)");
$metrics['bounce_rate'] = $totalSessions > 0 ? round(($singlePageSessions / $totalSessions) * 100, 1) : 0;
// Top pages
$result = $db->query("SELECT page, COUNT(*) as views, COUNT(DISTINCT session_id) as visitors
FROM events WHERE event='pageview' AND created_at >= '$since'
GROUP BY page ORDER BY views DESC LIMIT 15");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$topPages[] = $row;
}
// Top referrers
$result = $db->query("SELECT referrer, COUNT(*) as hits
FROM events WHERE event='pageview' AND referrer != '' AND created_at >= '$since'
GROUP BY referrer ORDER BY hits DESC LIMIT 10");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$topReferrers[] = $row;
}
// Top CTA clicks
$result = $db->query("SELECT json_extract(extra,'$.text') as label, json_extract(extra,'$.href') as href, COUNT(*) as clicks
FROM events WHERE event='cta_click' AND created_at >= '$since'
GROUP BY label, href ORDER BY clicks DESC LIMIT 10");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$topCTAs[] = $row;
}
// Daily chart data
$result = $db->query("SELECT date(created_at) as day, COUNT(*) as views, COUNT(DISTINCT session_id) as visitors
FROM events WHERE event='pageview' AND created_at >= '$since'
GROUP BY day ORDER BY day ASC");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$dailyChart[] = $row;
}
// Scroll depth
$result = $db->query("SELECT json_extract(extra,'$.depth') as depth, COUNT(*) as cnt
FROM events WHERE event='scroll' AND created_at >= '$since'
GROUP BY depth ORDER BY depth ASC");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$scrollData[] = $row;
}
$db->close();
}
$chartLabels = json_encode(array_column($dailyChart, 'day'));
$chartViews = json_encode(array_map('intval', array_column($dailyChart, 'views')));
$chartVisitors = json_encode(array_map('intval', array_column($dailyChart, 'visitors')));
?>
HELP4BIS Analytics Dashboard
'24 Hours','7d'=>'7 Days','30d'=>'30 Days','90d'=>'90 Days'] as $k=>$v): ?>
= $v ?>
No data yet
Analytics tracking is active. Data will appear here once visitors start arriving.
The tracker is loaded on all pages via <script src="/analytics/tracker.js">
Pageviews
= number_format($metrics['pageviews']) ?>
Last = $days ?> day= $days>1?'s':'' ?>
Unique Visitors
= number_format($metrics['unique_visitors']) ?>
By session hash
Avg. Duration
= $metrics['avg_duration'] ?>s
Time on page
Bounce Rate
= $metrics['bounce_rate'] ?>%
Single-page sessions
CTA Clicks
= number_format($metrics['cta_clicks']) ?>
Buttons & links
Form Submissions
= number_format($metrics['form_submits']) ?>
Contact / brief forms
Traffic Over Time
Top Pages
| Page | Views | Visitors |
| = htmlspecialchars($p['page'] === '/' ? 'Homepage' : ltrim($p['page'], '/')) ?> |
= number_format($p['views']) ?> |
= number_format($p['visitors']) ?> |
Top Referrers
No external referrers yet.
| Source | Visits |
| = htmlspecialchars(parse_url($r['referrer'], PHP_URL_HOST) ?: $r['referrer']) ?> |
= number_format($r['hits']) ?> |
CTA Clicks
No CTA clicks recorded yet.
| Button | Destination | Clicks |
| = htmlspecialchars(substr($c['label'] ?? '—', 0, 40)) ?> |
= htmlspecialchars(substr($c['href'] ?? '', 0, 40)) ?> |
= number_format($c['clicks']) ?> |
Scroll Depth
No scroll data yet.