Matomo Server-Side vs Client-Side | OpsBlu Docs

Matomo Server-Side vs Client-Side

Server-side vs client-side tracking approaches for Matomo. Covers implementation trade-offs, data accuracy, privacy compliance, ad blocker resilience, and.

Overview

Matomo supports both client-side (browser JavaScript) and server-side (Tracking HTTP API) data collection. Understanding when to use each approach - and how to combine them effectively - is essential for accurate, comprehensive analytics.

Client-Side Collection

When to Use

  • Pageviews and navigation: Standard page loads and SPA route changes
  • User interactions: Clicks, scrolls, video plays, form engagements
  • Browser context data: Screen resolution, viewport, user agent, referrer
  • Real-time visitor insights: Live dashboards and session recordings
  • Consent management: Capturing user consent states and preferences

Implementation

<!-- Standard Matomo JavaScript Tracker -->
<script>
  var _paq = window._paq = window._paq || [];
  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="https://analytics.example.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>

Advantages

  • Full browser context automatically captured
  • Real-time visitor flow visibility
  • Session recordings and heatmaps available
  • Lower implementation complexity
  • Works with Matomo Tag Manager

Limitations

  • Subject to ad blockers and privacy extensions
  • Relies on JavaScript execution
  • Cannot capture server-only events (webhooks, backend processes)
  • Potential for data loss on navigation or page unload

Server-Side Collection

When to Use

  • Authoritative transactions: Orders, payments, refunds, subscriptions
  • Backend events: Webhook callbacks, API interactions, cron jobs
  • Sensitive data: Events requiring server-side validation before tracking
  • Ad blocker bypass: Critical conversions that must not be blocked
  • Offline or async events: Email opens, push notification interactions

Matomo Tracking HTTP API

Send events directly from your server:

# Basic pageview via HTTP API
curl "https://analytics.example.com/matomo.php?idsite=1&rec=1&action_name=Order%20Confirmation&url=https://example.com/order/12345&_id=abc123xyz&rand=12345"

PHP SDK Example

use MatomoTracker;

$tracker = new MatomoTracker($siteId, 'https://analytics.example.com/');
$tracker->setTokenAuth('your_token_auth');
$tracker->setUserId('user_12345');
$tracker->setVisitorId('abc123xyz789012'); // From client cookie

// Track ecommerce order
$tracker->addEcommerceItem('SKU-123', 'Product Name', 'Category', 79.99, 1);
$tracker->doTrackEcommerceOrder('ORD-98765', 92.38, 79.99, 6.40, 5.99, 10.00);

Required Parameters

Parameter Description Example
idsite Matomo Site ID 1
rec Required, always set to 1 1
url Full URL of the action https://example.com/checkout
action_name Page title or event name Order Confirmation
_id Visitor ID (16 hex characters) abc123def456789
token_auth API authentication token xyz789...

Advantages

  • Immune to ad blockers and browser restrictions
  • Server-validated data (no client manipulation)
  • Access to backend-only events
  • Guaranteed delivery with retry logic
  • Works for non-browser contexts (apps, IoT, APIs)

Limitations

  • No automatic browser context (must pass manually)
  • No session recordings or heatmaps
  • Requires more implementation effort
  • Must manage visitor ID correlation carefully

Hybrid Architecture

Most implementations benefit from combining both approaches:

┌─────────────────┐     ┌─────────────────┐
│   Browser       │     │   Server        │
│   (Client-Side) │     │   (Server-Side) │
├─────────────────┤     ├─────────────────┤
│ • Pageviews     │     │ • Orders        │
│ • Clicks        │     │ • Refunds       │
│ • Scroll depth  │     │ • Webhooks      │
│ • Video plays   │     │ • API events    │
│ • Form starts   │     │ • Backend jobs  │
└────────┬────────┘     └────────┬────────┘
         │                       │
         └───────────┬───────────┘
                     │
              ┌──────▼──────┐
              │   Matomo    │
              │   Server    │
              └─────────────┘

Visitor ID Correlation

The critical factor for hybrid tracking is maintaining visitor identity:

  1. Client captures visitor ID: Extract the Matomo _pk_id cookie value
  2. Pass to server: Include visitor ID in form submissions, AJAX calls, or session storage
  3. Server uses same ID: Pass the visitor ID in server-side API calls
// Client: Get visitor ID
var visitorId = Matomo.getTracker().getVisitorId();

// Pass to server in checkout form
document.getElementById('visitorId').value = visitorId;
// Server: Use the same visitor ID
$visitorId = $_POST['visitorId'];
$tracker->setVisitorId($visitorId);
$tracker->doTrackEcommerceOrder($orderId, $total, ...);

Deduplication Strategies

When both client and server might report the same event:

Option 1: Server-Only for Conversions

Configure client-side to skip conversion events entirely; server handles all orders/transactions.

// Client: Track checkout start, but not completion
_paq.push(['trackEvent', 'Checkout', 'start']);
// Server handles order completion tracking

Option 2: Client with Server Validation

Client fires immediately; server validates and sends authoritative version:

  1. Client tracks conversion with action_name prefix: [pending] Order
  2. Server validates and tracks: Order Confirmed
  3. Reporting filters for confirmed orders only

Option 3: Server-Side Deduplication

Use unique transaction IDs to prevent duplicates:

// Check if order already tracked before sending
if (!$this->isOrderTracked($orderId)) {
    $tracker->doTrackEcommerceOrder($orderId, ...);
    $this->markOrderTracked($orderId);
}

Performance Considerations

Client-Side

  • Use async script loading to prevent render blocking
  • Batch events where possible to reduce HTTP requests
  • Consider navigator.sendBeacon() for unload events

Server-Side

  • Implement queue-based sending for high-volume events
  • Use bulk tracking API for batch imports
  • Set appropriate timeouts and retry logic
  • Monitor tracking endpoint latency
// Bulk tracking example
$tracker->enableBulkTracking();
foreach ($orders as $order) {
    $tracker->doTrackEcommerceOrder(...);
}
$tracker->doBulkTrack();

Security Considerations

Token Authentication

Server-side tracking requires token_auth for write access:

  • Store tokens securely (environment variables, secrets manager)
  • Use tokens with minimal required permissions
  • Rotate tokens periodically
  • Never expose tokens in client-side code

Input Validation

Validate all data before sending to Matomo:

  • Sanitize user-provided values
  • Validate numeric fields (prices, quantities)
  • Reject suspicious visitor ID formats
  • Log validation failures for monitoring

Decision Matrix

Scenario Recommended Approach
Standard pageviews Client-side
User interactions (clicks, scrolls) Client-side
Ecommerce orders Server-side (authoritative)
Payment confirmations Server-side
Form submissions Client start, server complete
Webhook events Server-side only
Subscription renewals Server-side only
Ad blocker critical conversions Server-side