Like to Use Matomo, but Stats Don't Add Up

I’ve been playing with Matomo off-and-on for about 2 months now, and though it’s REALLY interesting and looks comprehensive - the stats don’t seem to add up, and I can’t figure out why.

I cannot ask my boss to pay several thousand dollars for Matomo consulting if I can’t show him that we’ll get a return on our money.

The fact is, that Matomo’s numbers are between 10% and 20% of Google’s Analytics, and an even lower percentage of CloudFlare’s. I can stand 5-10% difference, but 80%-90% is just too much.

My assumption is that some browsers are simply not sending actions. My server is HTTPS, and I use CloudFlare’s always-HTTPS feature. That uses a CloudFlare certificate.

Do I need to put in a certificate matching subdomain.domain? Is there a way to tell if a browser won’t send a call?

Any help on this would be appreciated. If I can’t resolve this, I have to use something else, or ( god forbid ) roll my own. I’d REALLY like to use Matomo if possible.



This is something that gets asked often and there are ton’s of reasons for this.

The comparison to CloudFlare makes sense as they are counting something quite different (assuming you use js tracking). While they count the http requests, you count the people who execute Javascript and are not in Matomo’s Bot user agent list.

But there are stil reasons why there can be too little visits counted (see also here)

  • the user was using an adblocker that blocked Matomo
  • the user has disabled JS or blocked all third party scripts
  • the user has enabled DoNotTrack and therefore their visit isn’t tracked by Matomo by default
    • this is the most likely source for a difference as GA ignores DoNotTrack
  • the user has used the OptOut iFrame to OptOut of tracking and is therefore not tracked.
  • There is an error with your webserver causing some requests to be dropped (e.g. by using mod_security)
    • it is definitly possible that there is something wrong with your Webserver config that causes a small portion of requests to fail to reach Matomo.
    • for HTTPS you could check your Matomo domain at to see if the SSL-Config is correct
  • There was an PHP error when the data should have been stored.
    • While this is a bit unlikely, it isn’t impossible.

I’ll address each of your points in turn:

  1. Does an Ad Blocker block only Matomo and NOT GA?
  2. Would GA get called but not Matomo if JS is blocked? Also, my script is the same domain as the main site, but a different SUBdomain.
  3. I’ve turned-off donottrack to try to get some correlation
  4. I don’t know what OptOut iFrame is, I’ll look into that.
  5. Regarding webserver error, do I need to turn OFF mod_security? I don’t even know if it’s on ( I’ll check ). Also I’m losing a LARGE portion of request - 80-90% not a small portion.
  6. Looking at PHP error logs on last.

Couple of questions - should I change name of server to vs
Does it matter if the script is called “piwik.php” - should I change that name?
It would be a lot more work to change the pa push calls, do I need to do that?

Thanks. Any help is appreciated.

You are right, those were more meant when comparing to server logs.

It is highly likely that your local privacy laws require you to give your users a possibility to opt out of tracking.

mod_security is known to cause issues with Matomo as it blocks requests based on URL parts, but as Matomo sends data like referrer, etc. via GET parameters any arbitrary text is possible to appear in the URL.

It may make a difference, but only with people using adbockers (who also wouldn’t appear in GA)

I don’t know of anything that blocks based on the name of _paq, so this shouldn’t be necessary.

Thank you Lucas for your quick and cogent replies. I’m looking through these things now. One last question - do I push the setCustomDimension variable before the function or inside the function? I am using the dimension to set the subdomain of the site, as this site has 500+ subdomains, and dimensions look like a way to put that into separate boxes.


It’s important that it isn’t before var _paq = window._paq || [];, because _paq isn’t defined there and not after _paq.push(['trackPageView']); because otherwise it wouldn’t get sent with the request.

<script type="text/javascript">
  var _paq = window._paq || [];
// <-- Here
  (function() {
    var u="//{$PIWIK_URL}/";
    _paq.push(['setTrackerUrl', u+'piwik.php']);
    _paq.push(['setSiteId', {$IDSITE}]);
    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);