matomo/matomo-php-tracker
PHP Client for Matomo Analytics Tracking API
4.0.1
4.6M downloads/mo
#1005 most downloaded on Packagist
matomo-org/matomo-php-tracker
What this package is like to depend on
Last release 20 days ago
03 Aug 2026
Release timing varies
gaps range from 2 weeks to 1.2 years
Some releases are documented
notes for 11 of 32 stable releases
Nothing withdrawn
no release was ever pulled
12 years old
32 releases · first in 2014
3 releases in the last 12 months
see the full history below
Release timeline
32 releases · Dec 2014 to Aug 2026Releases
latest 32-
4.0.103 Aug 2026Release notes
Open source →Fixed
- Loading
MatomoTracker.phpno longer emits a deprecation notice for the predefined$http_response_headervariable on PHP 8.5. PHP reports it at compile time, so it was emitted on every include (#155).
- Loading
-
4.0.027 Jul 2026Release notes
Open source →Attention: this is a major release with breaking changes.
Upgrade note — the
false"not known" sentinel is gone. Tracker 3.x let you passfalseto many optional arguments to mean "value not known" (e.g.doTrackEvent($cat, $act, $name, false),addEcommerceItem($sku, $name, $cat, false),setLatitude(false)). Those arguments are now typed (?Tor numeric unions). If your calling code does not usedeclare(strict_types=1)— the usual case for a drop-in tracker — PHP's weak-mode coercion silently turnsfalseinto0/0.0/''instead of raising an error, so such calls now send a value (e_v=0,lat=0, item price0) where 3.x omitted the parameter. Replace everyfalse"not known" argument withnullor simply omit it; passingfalseno longer means "unset".Removed
- Support for PHP versions lower than 8.1. The tracker now requires PHP 8.1 or newer.
- The
#[AllowDynamicProperties]attribute. All properties are now declared explicitly, so setting undeclared dynamic properties on a tracker instance is no longer supported (extendMatomoTrackerand declare the property instead).
Changed
declare(strict_types=1)is now enabled and every method has proper parameter and return type hints aligned with how Matomo core handles the corresponding tracking parameters. Passing a value whose type cannot be coerced now throws aTypeError(for example a non-numeric string for a numeric parameter, or any type mismatch when the calling code itself declaresstrict_types=1). Note that for ordinary (non-strict) callers PHP's weak-mode coercion still applies, so e.g.falsebecomes0/''rather than raising — see the upgrade note above about the removedfalsesentinel.- Optional "unset" parameters and their corresponding properties and getters now use
nullinstead of the previousfalsesentinel. For examplegetUserId(),getUserAgent(),getIp()andgetPageviewId()now returnnull(notfalse) when no value is set, anddoTrackEvent()/getUrlTrackEvent()default the event name and value tonull. - All public properties are now natively typed. Assigning a legacy sentinel value such as
falseto e.g.$tracker->userAgentnow throws aTypeError; theattributionInfoproperty defaults to an empty array instead offalse. Subclasses overriding methods with the old untyped signatures may need to be updated to the new signatures. setUserId()now acceptsnullto de-assign a previously set User ID, as the method documentation always promised (previously thestringtype hint made that impossible).setUrlReferrer()(and the deprecatedsetUrlReferer()) acceptnullto unset the referrer.setCustomTrackingParameter()accepts an array value again (serialized viahttp_build_query, as the JS tracker does); this restores the pre-3.4.0 behavior for multi-value parameters.setLatitude()/setLongitude()values of0.0(equator / prime meridian) are now sent to Matomo. Previously coordinates of exactly zero were silently dropped.- Goal and Ecommerce revenue amounts now distinguish "not set" from an explicit
0.doTrackGoal()/getUrlTrackGoal()(and theMatomo_/Piwik_goal helpers) take?float $revenue = null:nullomitsrevenue(so Matomo uses the goal's configured revenue) while0.0now sendsrevenue=0. Likewise the optional Ecommerce amounts ($subTotal,$tax,$shipping,$discountofdoTrackEcommerceOrder()etc.) are?float = nulland only sent when provided, and the required Ecommerce grand total is now always sent (a0.0order/cart sendsrevenue=0). Previously an explicit0/0.0was silently omitted for all of these. - The
do*tracking methods now declare astring|boolreturn type. In bulk mode they return booleantrue(previously the value was coerced to the string"1"). doTrackSiteSearch()/getUrlTrackSiteSearch()accept?int $countResultsand only send&search_countwhen a count is provided (previously&search_count=0was always sent).- Both transports now consistently throw a
RuntimeExceptionon request failure (DNS, connection or timeout errors) by default; previously only the cURL transport threw while the stream fallback silently returnedfalse. CallsetExceptionsEnabled(false)to make failed requests returnfalseinstead, so tracking never breaks the calling application (#105). - Lowered the default request timeouts from 600s/300s to 5s/2s so a slow or unreachable Matomo can no longer block the calling page for minutes (#88). Raise them again via
setRequestTimeout()/setRequestConnectTimeout()if needed. - Bumped the test suite to PHPUnit 10.5.
Fixed
- All tracking parameter names and values are now consistently URL-encoded (including
_refts,data/customData,cs/charset and thedownload/linkaction type passed togetUrlTrackAction()/doTrackAction()), and the visitor ID read from the first-party cookie is validated as a 16-character hexadecimal string. - Request-failure exceptions no longer include the full request URL (only the target host), so its query string is never surfaced in error messages/logs. The request URL and body are also marked
#[\SensitiveParameter]so they are redacted from exception stack traces. - Authenticated requests that carry
token_authin the request body are now sent asPOST; previously the stream transport sent them asGET, so Matomo ignored the token in the body. - The stream transport now returns the response body for HTTP 4xx/5xx responses (like cURL) instead of turning them into a failure.
- Bulk tracking uses a more generous request timeout (at least 30s) and no longer discards the queued actions when a batch fails to send, so the batch can be retried.
- Outgoing tracker cookies are now joined with
;(not&), and all incomingSet-Cookieresponse headers are parsed instead of only the last one;getIncomingTrackerCookie()returnsstring|false. setAttributionInfo()no longer includes the supplied payload in its exception message (the parameter is also marked#[\SensitiveParameter]).- Event and content tracking requests now send
&ca=1(custom action), so Matomo no longer falls back to recording them as page views if the handling plugin is disabled (#80). - The
cip(override IP) tracking parameter is now URL-encoded like every other value (#151). - No longer calls the deprecated
curl_close()(it was already a no-op on the supported PHP versions) (#149). - Auto-detection of the tracked page URL now uses
REQUEST_URIas the source instead ofPATH_INFO. With front-controller / path-info routing (e.g./dir1/pagehandled bydir1/index.php),PATH_INFOonly holds the trailing/page, so the tracker previously recorded a truncated URL; it now records the full requested path.PATH_INFOis no longer used at all (SCRIPT_NAMEremains the fallback whenREQUEST_URIis unavailable) (#141).
Added
- Detect Google-GeminiNotebook as an AI bot by @eldk in #153
- Add method to track an AI bot request, if the current user agent is a known AI bot by @diosmosis in #148
- PHPStan static analysis at max level (
phpstan.neon.dist) and the Matomo coding standard via PHP_CodeSniffer (phpcs.xml.dist), both enforced for every pull request through GitHub Actions. - A greatly expanded unit test suite covering all tracking parameters, cookie handling and request preparation.
setDebugTrackingParameter()(@internaltest helper) to append a raw, unvalidated tracking parameter that overrides any built-in parameter of the same name, so integration tests can verify server-side handling of malformed values.setCurlOptions(array)to pass additional cURL options (e.g.CURLOPT_IPRESOLVE,CURLOPT_HTTP_VERSION) for the tracking requests; they are applied after the built-in options (#92). CustomCURLOPT_HTTPHEADERentries are merged with the tracker's own headers rather than replacing them, so adding a header no longer drops the built-inContent-Type(which would otherwise break bulk requests).
New Contributors
Full Changelog: 3.4.0...4.0.0
Release notes
Open source →Attention: this is a major release with breaking changes.
Upgrade note — the
false"not known" sentinel is gone. Tracker 3.x let you passfalseto many optional arguments to mean "value not known" (e.g.doTrackEvent($cat, $act, $name, false),addEcommerceItem($sku, $name, $cat, false),setLatitude(false)). Those arguments are now typed (?Tor numeric unions). If your calling code does not usedeclare(strict_types=1)— the usual case for a drop-in tracker — PHP's weak-mode coercion silently turnsfalseinto0/0.0/''instead of raising an error, so such calls now send a value (e_v=0,lat=0, item price0) where 3.x omitted the parameter. Replace everyfalse"not known" argument withnullor simply omit it; passingfalseno longer means "unset".Removed
- Support for PHP versions lower than 8.1. The tracker now requires PHP 8.1 or newer.
- The
#[AllowDynamicProperties]attribute. All properties are now declared explicitly, so setting undeclared dynamic properties on a tracker instance is no longer supported (extendMatomoTrackerand declare the property instead).
Changed
declare(strict_types=1)is now enabled and every method has proper parameter and return type hints aligned with how Matomo core handles the corresponding tracking parameters. Passing a value whose type cannot be coerced now throws aTypeError(for example a non-numeric string for a numeric parameter, or any type mismatch when the calling code itself declaresstrict_types=1). Note that for ordinary (non-strict) callers PHP's weak-mode coercion still applies, so e.g.falsebecomes0/''rather than raising — see the upgrade note above about the removedfalsesentinel.- Optional "unset" parameters and their corresponding properties and getters now use
nullinstead of the previousfalsesentinel. For examplegetUserId(),getUserAgent(),getIp()andgetPageviewId()now returnnull(notfalse) when no value is set, anddoTrackEvent()/getUrlTrackEvent()default the event name and value tonull. - All public properties are now natively typed. Assigning a legacy sentinel value such as
falseto e.g.$tracker->userAgentnow throws aTypeError; theattributionInfoproperty defaults to an empty array instead offalse. Subclasses overriding methods with the old untyped signatures may need to be updated to the new signatures. setUserId()now acceptsnullto de-assign a previously set User ID, as the method documentation always promised (previously thestringtype hint made that impossible).setUrlReferrer()(and the deprecatedsetUrlReferer()) acceptnullto unset the referrer.setCustomTrackingParameter()accepts an array value again (serialized viahttp_build_query, as the JS tracker does); this restores the pre-3.4.0 behavior for multi-value parameters.setLatitude()/setLongitude()values of0.0(equator / prime meridian) are now sent to Matomo. Previously coordinates of exactly zero were silently dropped.- Goal and Ecommerce revenue amounts now distinguish "not set" from an explicit
0.doTrackGoal()/getUrlTrackGoal()(and theMatomo_/Piwik_goal helpers) take?float $revenue = null:nullomitsrevenue(so Matomo uses the goal's configured revenue) while0.0now sendsrevenue=0. Likewise the optional Ecommerce amounts ($subTotal,$tax,$shipping,$discountofdoTrackEcommerceOrder()etc.) are?float = nulland only sent when provided, and the required Ecommerce grand total is now always sent (a0.0order/cart sendsrevenue=0). Previously an explicit0/0.0was silently omitted for all of these. - The
do*tracking methods now declare astring|boolreturn type. In bulk mode they return booleantrue(previously the value was coerced to the string"1"). doTrackSiteSearch()/getUrlTrackSiteSearch()accept?int $countResultsand only send&search_countwhen a count is provided (previously&search_count=0was always sent).- Both transports now consistently throw a
RuntimeExceptionon request failure (DNS, connection or timeout errors) by default; previously only the cURL transport threw while the stream fallback silently returnedfalse. CallsetExceptionsEnabled(false)to make failed requests returnfalseinstead, so tracking never breaks the calling application (#105). - Lowered the default request timeouts from 600s/300s to 5s/2s so a slow or unreachable Matomo can no longer block the calling page for minutes (#88). Raise them again via
setRequestTimeout()/setRequestConnectTimeout()if needed. - Bumped the test suite to PHPUnit 10.5.
Fixed
- All tracking parameter names and values are now consistently URL-encoded (including
_refts,data/customData,cs/charset and thedownload/linkaction type passed togetUrlTrackAction()/doTrackAction()), and the visitor ID read from the first-party cookie is validated as a 16-character hexadecimal string. - Request-failure exceptions no longer include the full request URL (only the target host), so its query string is never surfaced in error messages/logs. The request URL and body are also marked
#[\SensitiveParameter]so they are redacted from exception stack traces. - Authenticated requests that carry
token_authin the request body are now sent asPOST; previously the stream transport sent them asGET, so Matomo ignored the token in the body. - The stream transport now returns the response body for HTTP 4xx/5xx responses (like cURL) instead of turning them into a failure.
- Bulk tracking uses a more generous request timeout (at least 30s) and no longer discards the queued actions when a batch fails to send, so the batch can be retried.
- Outgoing tracker cookies are now joined with
;(not&), and all incomingSet-Cookieresponse headers are parsed instead of only the last one;getIncomingTrackerCookie()returnsstring|false. setAttributionInfo()no longer includes the supplied payload in its exception message (the parameter is also marked#[\SensitiveParameter]).- Event and content tracking requests now send
&ca=1(custom action), so Matomo no longer falls back to recording them as page views if the handling plugin is disabled (#80). - The
cip(override IP) tracking parameter is now URL-encoded like every other value (#151). - No longer calls the deprecated
curl_close()(it was already a no-op on the supported PHP versions) (#149). - Auto-detection of the tracked page URL now uses
REQUEST_URIas the source instead ofPATH_INFO. With front-controller / path-info routing (e.g./dir1/pagehandled bydir1/index.php),PATH_INFOonly holds the trailing/page, so the tracker previously recorded a truncated URL; it now records the full requested path.PATH_INFOis no longer used at all (SCRIPT_NAMEremains the fallback whenREQUEST_URIis unavailable) (#141).
Added
- PHPStan static analysis at max level (
phpstan.neon.dist) and the Matomo coding standard via PHP_CodeSniffer (phpcs.xml.dist), both enforced for every pull request through GitHub Actions. - A greatly expanded unit test suite covering all tracking parameters, cookie handling and request preparation.
setDebugTrackingParameter()(@internaltest helper) to append a raw, unvalidated tracking parameter that overrides any built-in parameter of the same name, so integration tests can verify server-side handling of malformed values.setCurlOptions(array)to pass additional cURL options (e.g.CURLOPT_IPRESOLVE,CURLOPT_HTTP_VERSION) for the tracking requests; they are applied after the built-in options (#92). CustomCURLOPT_HTTPHEADERentries are merged with the tracker's own headers rather than replacing them, so adding a header no longer drops the built-inContent-Type(which would otherwise break bulk requests).
-
3.4.020 Dec 2025Release notes
Open source →What's Changed
- Strict types for arguments and return types by @lutdev in #135
- Exclude development resources from dist archive by @mbrodala in #138
- Fix deprecation notice for $http_response_header by @sgiehl in #143
- Declare supported PHP versions explicitly and run tests on all supported versions by @gsteel in #147
- Fix: Not possible to create multiple Piwik tracker instances having different API urls by @lutdev in #145
New Contributors
Full Changelog: 3.3.1...3.4.0
Release notes
Open source →Changed
- Fixed PHP 8.5 deprecation notice
- static
$URLis deprecated - a lot of arguments of
MatomoTrackermethods have explicitly types - a lot of
MatomoTrackermethod return types have strict types
Added
- new private property
apiUrlfor storing API URL
-
3.3.209 Oct 2024Release notes
Open source →Changed
- Support for formFactors client hint parameter, supported as of Matomo 5.2.0
-
3.3.121 May 2024Release notes
Open source → -
3.3.017 May 2024Release notes
Open source →What's Changed
- feat: remove composer.lock by @Chris53897 in #117
- fix: wrong method description by @revoltek-daniel in #125
- feat: Functions to get and set the page view id manually by @EPNW-Eric in #126
- feat: default folder structure, allow phpunit 10 by @Chris53897 in #116
- fix: Check for cURL error before throwing exception in sendRequest method by @mzaman in #130
- fix: Creation of dynamic property MatomoTracker::$currentTs is deprecated by @lutdev in #131
- feat: Drop support of older php versions by @lutdev in #132
New Contributors
- @Chris53897 made their first contribution in #117
- @revoltek-daniel made their first contribution in #125
- @EPNW-Eric made their first contribution in #126
- @mzaman made their first contribution in #130
- @lutdev made their first contribution in #131
Full Changelog: 3.2.0...3.3.0
Release notes
Open source →Removed
- support for PHP versions lower than 7.2
Changed
- all
MatomoTrackerclass constants are now explicitly public - all
MatomoTrackerdynamic properties are now explicitly public
-
3.2.024 Mar 2023Release notes
Open source →What's Changed
- add support for CURLOPT_CONNECTTIMEOUT by @vpapaloukas in #115
New Contributors
- @vpapaloukas made their first contribution in #115
Full Changelog: 3.1.3...3.2.0
-
3.1.307 Mar 2023 -
3.1.218 Jan 2023Release notes
Open source →- Improve PHP 8.2 compatibility (by temporarily allowing dynamic properties)
-
3.1.107 Dec 2022 -
3.1.004 Jul 2022Nothing published for this version
-
3.0.415 Nov 2021Nothing published for this version
-
3.0.315 Nov 2021Nothing published for this version
-
3.0.214 Nov 2021Nothing published for this version
-
3.0.119 May 2021Nothing published for this version
-
3.0.021 Nov 2020Release notes
Open source →Attention: This version of Matomo PHP Tracker is no longer compatible with Matomo 3.x or earlier
- Support for new page performance metrics (added in Matomo 4) has been added. You can use
setPerformanceTimings()to set them for page views. - Setting page generation time using
setGenerationTime()has been discontinued. The method still exists to not break applications still using it, but it does not have any effect. Please use new page performance metrics as replacement. - Sending requests using cURL will now throw an exception if an error occurs in a request.
- Matomo does not longer support tracking of these browser plugins: Gears, Director. Therefor the signature of
setPlugins()changed. - Implementation of ecommerce views changed from custom variables to raw parameters
- It is now possible to configure cookie options for Secure, HTTPOnly and SameSite.
- Add method setRequestMethodNonBulk() to allow (non bulk) POST requests.
- Support for new page performance metrics (added in Matomo 4) has been added. You can use
-
2.0.314 Jan 2020Nothing published for this version
-
2.0.214 Jan 2020Nothing published for this version
-
2.0.102 Jan 2020Nothing published for this version
-
2.0.001 Jan 2020Nothing published for this version
-
1.5.223 Dec 2019Nothing published for this version
-
1.5.106 Nov 2019Nothing published for this version
-
1.5.006 Nov 2019Nothing published for this version
-
1.4.112 Oct 2018Nothing published for this version
-
1.4.009 Nov 2017Nothing published for this version
-
1.3.008 Jun 2017Nothing published for this version
-
1.2.018 Feb 2017Nothing published for this version
-
1.1.027 Dec 2016Nothing published for this version
-
1.0.313 Jul 2016Nothing published for this version
-
1.0.212 Jan 2016Nothing published for this version
-
1.0.111 Nov 2015Nothing published for this version
-
1.0.018 Dec 2014Nothing published for this version