Why your Matomo reports are suddenly full of bot traffic (and how to get it out)

If your Matomo visits doubled overnight, your server-side tracker reports two to three times what the JavaScript tag does, or you're drowning in Direct Entry, one-page, zero-second hits, bots are almost certainly the cause. Matomo already filters the honest ones. Here's how to handle the rest and clean up the reports you already have.

A sudden flood of Direct Entry, one-action, zero-duration visits is a strong bot signal. It is not proof by itself. Before filtering, confirm three things: bot tracking is not forced on, the spike is not a duplicate tracker or recent campaign/tracking change, and the extra visits come from user agents, IPs, providers, or log requests your JavaScript tag would not normally see.

TL;DR

A sudden flood of Direct Entry, one-action, zero-second visits is usually bots, but first confirm nobody turned tracking on for them with a stray bots=1 or --enable-bots. Once that's clear, install Tracking Spam Prevention and switch on only the filters that are safe for your tracking path, then add a temporary actions>=2 segment to clean up the visits you already have. Those filters are all off by default because some legitimate setups look automated, so if you track server-side, check the Visits Log before turning on cloud-provider or server-side-library blocking.

If you want the short version, work through it in this order:

  1. Search your JavaScript snippets, image-tracker URLs, HTTP API calls, and log-import commands for bots=1 or --enable-bots.
  2. Work out where the spike comes from: the JavaScript tag, the HTTP API or a server-side SDK, or log import.
  3. If log import is involved, expect a higher bot baseline and filter the access-log traffic. If the HTTP API or an SDK is involved, audit the calls you emit, the visitor IPs, and the visitor IDs before you assume bots.
  4. Create a temporary actions>=2 segment for the reports you already have. Push durable blocking upstream when Matomo has no honest bot signal to match.

It helps to start from what Matomo already does for you. Every tracking request that reaches it runs through the bundled DeviceDetector library, and anything matching the bot list is dropped before it becomes a normal visit, unless you explicitly override that. So detected bots stay out of your reports without any work on your part. What slips through is usually traffic DeviceDetector can't recognize yet, plus the gaps between browser-side, server-side, and log-based tracking.

Before you start filtering, prove the spike really is bots. A few things to check:

  • In Visits Log, look at the user agent, IP address, provider, country, entry page, action count, and visit duration for the suspect visits.
  • Compare matomo.php requests in your access logs with what the browser tag sends. If the server shows far more pageview calls than the browser, find which integration emits them.
  • Check for duplicate tracking: Matomo Tag Manager and the raw JavaScript snippet both firing, duplicate pageview calls in a single-page app, or a new server-side tracker running beside the browser tag.
  • Check whether consent, adblock handling, campaign tagging, static files, errors, redirects, or log-import options changed when the spike began.

Why some bots slip past Matomo's default filtering

Two things keep ordinary bots out of your reports by default, and knowing what they are tells you why the survivors get through.

The first is DeviceDetector. Matomo runs every request's user agent through it, and anything matching a known crawler, spider, or monitoring service is dropped before it is stored as a normal visit. That is why the well-behaved bots never show up in the first place: Googlebot, Bingbot, uptime checkers, and other tools that identify themselves.

The second filter is JavaScript itself. The standard Matomo tag only fires when a browser executes JavaScript, and most simple crawlers and scripts don't. They request the HTML, parse it, and move on without ever running your tracker.

That leaves three common paths for bot-looking traffic:

  • Log import reads web server access logs. Those logs include requests the JavaScript tag never saw, including requests from bots that do not execute JavaScript.
  • The HTTP Tracking API and server-side SDKs only record the pageviews and events your code sends to matomo.php. They bypass browser execution, so bots can appear if your server emits pageviews for bot requests, but a two- or three-times delta can also come from duplicate calls, missing or unstable visitor IDs, consent/adblock differences, or tracking static, error, and redirect requests.
  • Modern stealth bots use headless browsers, rotate through cloud or residential IP ranges, and copy real browser user-agent strings. DeviceDetector can only catch a bot that identifies itself, so a crawler wearing a current Chrome user agent can walk through the default filter.

First, make sure you aren't force-tracking them

Before adding filters, rule out the one setting that does the opposite of what you want. Matomo has a bots=1 parameter that explicitly turns bot tracking on, and it shows up in more places than people expect:

This setting overrides bot exclusion

bots=1 forces detected bots into normal visit/action tracking when Matomo's HTTP API recMode parameter is not set. Use it only when you deliberately want bot requests counted as ordinary visits.

text
// JavaScript tracker: remove this line if it's present
_paq.push(['appendToTrackingUrl', 'bots=1']);

// HTTP Tracking API / image tracker: drop &bots=1 from the request URL
https://example.org/matomo.php?idsite=1&rec=1&bots=1

// Log import: drop the --enable-bots flag
python3 import_logs.py --url=https://example.org --enable-bots access.log

If any of these is set, often copied from a forum answer or left over from debugging, bot tracking is on and Matomo's default filtering is being overridden. Remove it, and the default exclusion comes back.

Exclude the bots that identify themselves

For a bot that sends an honest, recognisable user agent that DeviceDetector somehow does not catch yet, exclude it by hand. In Matomo's admin, open Administration > Settings > Websites and use Global list of user agents to exclude and Global list of Excluded IPs. One user-agent entry per line; Matomo matches the substring anywhere in the visitor's user-agent string. The IP list accepts wildcards, ranges, and CIDR notation. Since Matomo 4.1.1 the user-agent list also accepts a regular expression:

text
/bot|spider|crawl|scanner/i

Keep the patterns specific. A short string like bot will quietly match legitimate user agents too, so over-broad rules cost you real visits. These exclusions apply going forward only; they never delete visits you have already collected. If you have found a genuine bot that Matomo does not recognize, paste its user agent into Administration > Diagnostic > Device Detection or devicedetector.net to confirm. If it really is missed, open an issue or pull request on the matomo-org/device-detector repo so future versions catch it for everyone.

Catch the ones that don't: Tracking Spam Prevention

User-agent and IP lists only work on bots you can name, and the traffic inflating most reports usually does not give you a clean name to work with. For those, use Tracking Spam Prevention, an official Matomo plugin included with Matomo Cloud and available from the Marketplace for On-Premise and WordPress. Every filter is off by default, because some tracking setups send legitimate requests that look automated.

FilterBlocksEnable whenDo not enable whenFalse-positive risk
Cloud providersTracking requests from IP ranges such as AWS, Azure, Google Cloud, DigitalOcean, and Oracle Cloud. Some providers can also be detected through the geolocation database.You use the JavaScript tracker and Matomo sees the visitor's real IP address.Your HTTP API, SDK, replay, proxy, or log-import flow sends legitimate requests from a cloud server. Allowlist those senders first.Medium
Headless browsersCommon headless-browser signatures used by automation and scraping tools.You only want standard browser traffic in the reports.Your real traffic includes automated tests, app traffic, IoT devices, or non-traditional browser environments that should be counted.Medium
Server-side librariesRequests that identify as cURL, HTTP, Guzzle, Postman, and similar clients.Your site is JavaScript-only and those clients are not valid visitors.You use Matomo PHP, Java, Python, Android, iOS, or another server-side tracking method.High
Max actions per visitVisits that exceed a configured action count, after which Matomo stops recording further actions and can block the IP for up to 24 hours.The same visit or IP records hundreds of actions outside normal user behavior.You track highly interactive applications where real users can generate many actions.Medium
Country include/excludeCountries outside the market you intentionally track.The site has a narrow, stable service area.You serve a global audience, have unreliable geolocation, or care about travelers and VPN users.Medium

If you import logs, start with the filters that match the unwanted log traffic and test them against the Visits Log. If you use the HTTP API or a server-side SDK, first confirm Matomo receives the visitor IP, not your server or proxy IP, and allowlist any legitimate cloud sender before enabling cloud or server-side-library blocking.

Clean up the reports you already have: Segments

Everything above is forward-only. To get a cleaner picture of traffic that already landed, use a temporary reporting Segment. It filters the view without deleting any data, which is exactly right for visits you cannot un-track.

PurposeSegmentUse whenWhat it removes
Conservative engaged trafficactions>=2You need a quick baseline that drops the one-action flood.Real one-page visits and other legitimate bounces.
Engaged traffic with non-zero durationactions>=2;visitDuration>0The spike is mostly one-action, zero-duration traffic and duration matters for the report.Real short visits, especially when heartbeat timing is not representative.
Germany-only reporting viewactions>=2;countryCode==deThe site is genuinely Germany-only and non-German traffic is not part of the business question.Legitimate traffic from outside Germany, including VPNs and travelers.

Start with actions>=2. If obvious bots remain, test actions>=2;visitDuration>0. Do not make referrerType!=direct your default cleanup segment; it removes real direct visits. Use it only as a narrow diagnostic view when you intentionally want to inspect the Direct Entry flood without treating that as the cleaned baseline.

If you'd rather watch the bots than hide them

Sometimes you want bot activity visible, just not mixed into your real numbers. The community Bot Tracker plugin scans incoming user agents for bot keywords and logs those visits into separate reports, out of your normal visitor log.

Another option is to point bot traffic at a dedicated Matomo site with bots=1, so it is tracked deliberately and quarantined away from the site that matters. Be precise about what that does: bots=1 records detected bots as normal visits/actions in that isolated site. It is not native bot telemetry.

For Matomo 5.7+ HTTP API requests from supported user-triggered AI assistant bots, Matomo also documents recMode=1 for bot-only tracking and recMode=2 for automatic routing between bot tracking and normal visit tracking. That is a different path from bots=1, and current bot telemetry is limited to those supported AI assistant cases.

When user-agent filtering isn't enough

Fully disguised bots leave no honest signal to filter on: rotating residential IPs, current real browser user agents, genuine headless rendering. There's no Matomo setting that catches them, because there's nothing for Matomo to match. Push filtering upstream to your firewall, WAF, or Cloudflare, where you can rate-limit and challenge traffic before it reaches the tracker at all, and lean on behavioral segments (multi-page, has a referrer, reasonable dwell time) for whatever still gets through.

One technique you will see floated on the forum is conditional firing: only output the Matomo snippet for requests that carry valid Sec-Fetch-* headers and a current real browser user agent. It can help, but it is a community workaround, not a Matomo feature. I have seen this fail with full-page caches and plugin-managed snippets, and header behavior is not a stable analytics contract. Treat it as a last resort you test carefully, not a fix you rely on.

What we'd actually do

For most JavaScript-only sites the order is short: confirm bots=1 is not set anywhere, install Tracking Spam Prevention, switch on cloud-provider and headless-browser blocking after checking the Visits Log, then add an actions>=2 segment to clean up the history.

If you import logs, expect a higher bot baseline as the normal state of things and filter based on access-log evidence. If you track server-side, audit what your application emits before turning on filters that block cloud providers or server-side libraries. Save the user-agent and IP exclusion lists for specific offenders you can actually name; they are precise, but they do not scale to traffic that is actively hiding from you.

Martez connects Matomo with Meta Ads and Google Ads so ROAS, CLV, and attribution sit next to your web analytics instead of in a separate spreadsheet. It's in private beta. Join the waitlist if that's relevant.

Bots will always find your tracker. You won't shut them out completely, and you don't have to. The goal is keeping them out of the numbers you actually report on.