Matomo Setup & Implementation | OpsBlu Docs

Matomo Setup & Implementation

How to implement Matomo analytics with self-hosted or cloud deployment. Covers tracking code installation, consent management, ecommerce tracking, custom.

Matomo is a privacy-first analytics platform available as self-hosted (On-Premise) or cloud-hosted (Matomo Cloud). Its core advantage is data ownership -- when self-hosted, all analytics data stays on your servers, making GDPR compliance straightforward because no third-party processor touches your data. However, self-hosted Matomo introduces operational complexity: you are responsible for server maintenance, database performance, archiving cron jobs, and SSL configuration. A proper implementation accounts for both the tracking configuration and the infrastructure requirements.

Why Proper Implementation Matters

Data Ownership Requires Operational Responsibility

Self-hosted Matomo gives you complete data ownership, but:

  • Database growth: Matomo stores raw visit data in MySQL/MariaDB. A site with 100K monthly visits generates ~2-5GB of data per year without archiving
  • Archiving performance: Matomo pre-computes reports via core:archive cron jobs. If these fail, the dashboard shows stale data or times out
  • PHP memory limits: Large report generation can exceed default PHP memory limits (128MB), causing incomplete reports
  • SSL requirement: Tracking requests must be HTTPS; mixed content blocks tracking on HTTPS websites
  • Geolocation database: GeoIP2 databases require periodic updates for accurate location data

Cookieless Tracking Is Not Automatic

Matomo can track without cookies (a major GDPR advantage), but this requires explicit configuration:

  • Default behavior uses first-party cookies (like Google Analytics)
  • Cookieless mode must be enabled per-site in Matomo settings
  • Cookieless tracking uses fingerprint-based visitor identification, which is less accurate
  • You must decide: cookies with consent, or cookieless without consent banner

Plugin Dependencies

Matomo's functionality depends on plugins. Core analytics are free, but advanced features require premium plugins:

Feature Plugin Self-Hosted Cost Cloud Included
Ecommerce Core Free Yes
Heatmaps Premium Paid license Yes (Business+)
Session Recording Premium Paid license Yes (Business+)
A/B Testing Premium Paid license Yes (Business+)
Funnels Premium Paid license Yes (Business+)
Custom Reports Premium Paid license Yes (Business+)
Media Analytics Premium Paid license Yes (Business+)

Plan your plugin requirements before deployment to avoid infrastructure sizing surprises.

Pre-Implementation Planning

Access and Permissions

Matomo Instance:

  1. For Cloud: Sign up at matomo.cloud and access at yoursite.matomo.cloud
  2. For Self-Hosted: Install Matomo on your server (see infrastructure requirements below)
  3. Log in as Super User (first account created during installation)

Required Roles:

Role Permissions Use Case
Super User Full system access, plugin management System admin
Admin Site settings, user management for assigned sites Site owner
Write Tag Manager access, goal configuration Implementation team
View Report access only Stakeholders

Key Identifiers:

ID Where to Find Format
Site ID (idsite) Administration > Websites > Manage Numeric (e.g., 1, 2, 3)
Tracker URL Administration > System > General Settings https://your-matomo.example.com/matomo.php
Auth Token Personal Settings > Security > Auth Tokens Alphanumeric string

Self-Hosted Infrastructure Requirements

Minimum Server Specifications (up to 100K visits/month):

Resource Minimum Recommended
CPU 2 cores 4 cores
RAM 2 GB 4 GB
Storage 20 GB 50 GB SSD
PHP 7.4+ 8.1+
MySQL/MariaDB 5.7+ / 10.3+ 8.0+ / 10.6+
Web Server Apache or Nginx Nginx (better performance)

Required PHP Extensions: mbstring, pdo, pdo_mysql, gd, curl, xml, json

Decide your consent strategy before implementation:

Option 1: Cookies with Consent (recommended for most sites)

  • Use Matomo's built-in consent management or external CMP
  • Full visitor tracking accuracy with cookies
  • Requires consent banner for EU/EEA visitors

Option 2: Cookieless Without Consent

  • Enable disableCookies() in tracking code
  • No consent banner needed (in most jurisdictions)
  • Reduced accuracy: repeat visitors may be counted as new
  • No cross-session user tracking

Option 3: Cookie Consent Mode

  • Track without cookies by default
  • Upgrade to cookie-based tracking after consent
  • Best of both worlds but more complex implementation

Implementation Walkthrough

Step 1: Install Matomo Tracking Code

Standard Installation (with cookies):

<!-- Matomo Tracking Code -->
<script>
  var _paq = window._paq = window._paq || [];
  /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="https://your-matomo-instance.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>
<noscript><p><img referrerpolicy="no-referrer-when-downgrade"
  src="https://your-matomo-instance.example.com/matomo.php?idsite=1&rec=1"
  style="border:0;" alt="" /></p></noscript>
<!-- End Matomo Tracking Code -->

Cookieless Installation (no consent required):

<script>
  var _paq = window._paq = window._paq || [];
  _paq.push(['disableCookies']);           // No cookies set
  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="https://your-matomo-instance.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>

Consent Mode Installation (cookies only after consent):

<script>
  var _paq = window._paq = window._paq || [];

  // Require consent before tracking
  _paq.push(['requireConsent']);

  _paq.push(['trackPageView']);
  _paq.push(['enableLinkTracking']);
  (function() {
    var u="https://your-matomo-instance.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>

<script>
  // When user grants consent (called from your consent banner)
  function grantMatomoConsent() {
    _paq.push(['setConsentGiven']);
    // Consent is remembered for subsequent visits
  }

  // When user revokes consent
  function revokeMatomoConsent() {
    _paq.push(['forgetConsentGiven']);
  }
</script>

Step 2: Configure Cross-Domain Tracking

If your users navigate between multiple domains (e.g., www.example.com and shop.example.com):

// On both domains, add before trackPageView:
_paq.push(['setDomains', ['*.example.com', '*.shop.example.com']]);
_paq.push(['setCookieDomain', '.example.com']);  // Share cookies across subdomains
_paq.push(['enableCrossDomainLinking']);           // For different root domains
_paq.push(['trackPageView']);

Step 3: Implement Ecommerce Tracking

Product View:

// On product detail pages
_paq.push(['setEcommerceView',
  'SKU-12345',           // Product SKU
  'Premium Widget',       // Product Name
  'Widgets',             // Product Category (or array for nested categories)
  49.99                  // Product Price
]);
_paq.push(['trackPageView']);

Cart Update:

// When cart changes (add, remove, update quantity)
// Add each item in the cart:
_paq.push(['addEcommerceItem',
  'SKU-12345',           // Product SKU (required)
  'Premium Widget',       // Product Name
  'Widgets',             // Category
  49.99,                 // Unit Price
  2                      // Quantity
]);
_paq.push(['addEcommerceItem',
  'SKU-67890',
  'Deluxe Gadget',
  'Gadgets',
  79.99,
  1
]);

// Track the cart update with total value
_paq.push(['trackEcommerceCartUpdate', 179.97]);

Purchase:

// On order confirmation page
// First, add all purchased items:
_paq.push(['addEcommerceItem', 'SKU-12345', 'Premium Widget', 'Widgets', 49.99, 2]);
_paq.push(['addEcommerceItem', 'SKU-67890', 'Deluxe Gadget', 'Gadgets', 79.99, 1]);

// Then track the order:
_paq.push(['trackEcommerceOrder',
  'ORD-2024-12345',      // Order ID (required, unique)
  179.97,                // Grand Total (required)
  159.97,                // Subtotal (optional)
  12.80,                 // Tax (optional)
  7.20,                  // Shipping (optional)
  false                  // Discount applied (optional, boolean)
]);

Step 4: Set Up Custom Dimensions

Custom dimensions extend the default tracking with business-specific data:

  1. In Matomo Admin, go to Custom Dimensions (under Manage)
  2. Create dimensions:
Scope Name Example Values
Visit User Type free, pro, enterprise
Visit Logged In yes, no
Action Page Type product, category, blog, checkout
Action Author author name (for content sites)
  1. Implement in tracking code:
// Visit-scoped dimensions (set once per visit)
_paq.push(['setCustomDimension', 1, 'pro']);        // dimension1 = User Type
_paq.push(['setCustomDimension', 2, 'yes']);        // dimension2 = Logged In

// Action-scoped dimensions (set per page/event)
_paq.push(['setCustomDimension', 3, 'product']);    // dimension3 = Page Type
_paq.push(['setCustomDimension', 4, 'John Smith']); // dimension4 = Author

_paq.push(['trackPageView']);

Step 5: Configure Goals and Events

Goals (track conversions):

  1. In Matomo, go to Administration > Goals
  2. Create goals:
Goal Type Match
Purchase Completed Visit URL URL contains /order-confirmation
Newsletter Signup Event Category = "newsletter", Action = "signup"
Contact Form Submit Event Category = "form", Action = "submit"

Events (track interactions):

// Event tracking: Category, Action, Name (optional), Value (optional)
_paq.push(['trackEvent', 'Form', 'Submit', 'Contact Form']);
_paq.push(['trackEvent', 'Video', 'Play', 'Product Demo', 120]);  // 120 seconds
_paq.push(['trackEvent', 'Download', 'Click', 'Whitepaper.pdf']);
_paq.push(['trackEvent', 'Newsletter', 'Signup', 'Footer Form']);

Step 6: Self-Hosted Administration

Configure Archiving Cron Job (critical for self-hosted):

# Add to crontab (run every hour for sites under 500K visits/month)
# For higher traffic, consider running every 30 minutes
5 * * * * /usr/bin/php /var/www/matomo/console core:archive --url=https://your-matomo.example.com/ > /var/log/matomo-archive.log 2>&1

Disable Browser Archiving (after setting up cron):

In Matomo Admin > System > General Settings:

  • Set "Archive reports when viewed from the browser" to No
  • This forces all archiving through the cron job, improving dashboard performance

GeoIP2 Database Setup:

# Download MaxMind GeoIP2 database (requires free MaxMind account)
cd /var/www/matomo/misc/
wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=YOUR_KEY&suffix=tar.gz" -O GeoLite2-City.tar.gz
tar xzf GeoLite2-City.tar.gz
mv GeoLite2-City_*/GeoLite2-City.mmdb .

# Set up monthly auto-update via cron
0 3 1 * * cd /var/www/matomo/misc && wget -q "https://download.maxmind.com/..." -O GeoLite2-City.tar.gz && tar xzf GeoLite2-City.tar.gz && mv GeoLite2-City_*/GeoLite2-City.mmdb .

In Matomo Admin > System > Geolocation, select "GeoIP 2 (PHP)" as the provider.

Verification and QA

Matomo Tag Manager Preview

If using Matomo Tag Manager:

  1. Go to Tag Manager > Container > Preview/Debug
  2. Enable preview mode
  3. Navigate your website
  4. Check that tags fire correctly on expected pages

Real-Time Dashboard

  1. In Matomo, go to Visitors > Real-time Map or Real-time Visits
  2. Open your website in another tab
  3. Navigate through several pages
  4. Verify:
    • Visits appear in real-time
    • Page titles and URLs are correct
    • Custom dimensions display expected values
    • Geolocation is accurate

Network Tab Verification

  1. Open Chrome DevTools > Network tab
  2. Filter for matomo.php
  3. Navigate your site
  4. For each tracking request, verify:
    • idsite matches your site ID
    • action_name shows correct page title
    • e_c, e_a, e_n contain event data (if events fire)
    • Custom dimension parameters (dimension1, etc.) are present

Common Issues

Issue Cause Fix
No data in dashboard Wrong Site ID or tracker URL Verify setSiteId and setTrackerUrl in tracking code
Mixed content blocking Matomo on HTTP, site on HTTPS Configure Matomo with SSL certificate
Stale reports Archiving cron not running Check cron job, review /var/log/matomo-archive.log
Ecommerce not tracking Ecommerce plugin not enabled Admin > Websites > Manage > Enable Ecommerce
Cookie consent blocking requireConsent called but consent never granted Verify consent banner calls setConsentGiven
Slow dashboard Large database, no archiving Enable cron archiving, disable browser archiving
Geolocation shows "Unknown" GeoIP2 database not installed Download and configure GeoLite2 database

Deployment Artifacts

  • Site ID and Tracker URL: Per environment, central reference
  • Tracking code: Implementation per consent strategy (cookies, cookieless, consent mode)
  • Custom dimensions registry: Dimension IDs, names, scopes, and descriptions
  • Goal definitions: Names, match conditions, and revenue values
  • Ecommerce schema: Product field mapping (SKU, name, category, price)
  • Self-hosted configuration: Server specs, PHP settings, cron jobs, GeoIP setup
  • Plugin inventory: Installed plugins, license status, and update schedule
  • Consent implementation: CMP integration, consent/revoke flow documentation

Linked Runbooks

Change Log and Owners

  • Document who administers the Matomo instance (server admin for self-hosted)
  • Track plugin installations and license renewals
  • Maintain custom dimension allocations with owners
  • Record consent strategy changes with compliance review dates
  • Review quarterly: database size, archiving performance, GeoIP database freshness