diff --git a/FEATURES/71435 b/FEATURES/71435
new file mode 100644
index 0000000000000000000000000000000000000000..4988b199dbe004ba4f193f946bea0ba0fb7af23a
--- /dev/null
+++ b/FEATURES/71435
@@ -0,0 +1,10 @@
+        '71435' =>
+            ['Label' => $this->_('Piwik est devenu Matomo'),
+             'Desc' => '',
+             'Image' => '',
+             'Video' => '',
+             'Category' => '',
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => '',
+             'Test' => '',
+             'Date' => '2018-09-25'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/71435 b/VERSIONS_WIP/71435
new file mode 100644
index 0000000000000000000000000000000000000000..6ee80d4af8a6106ec498195686414a26cea116af
--- /dev/null
+++ b/VERSIONS_WIP/71435
@@ -0,0 +1 @@
+ - ticket #71435 : Piwik est devenu Matomo
\ No newline at end of file
diff --git a/application/modules/admin/controllers/StatController.php b/application/modules/admin/controllers/StatController.php
index fa7a407d4e6a5b670ad0234a0722c85b94f5a3d0..354192f5bdca0093eebd9c881af2ab5f67926b43 100644
--- a/application/modules/admin/controllers/StatController.php
+++ b/application/modules/admin/controllers/StatController.php
@@ -52,21 +52,21 @@ class Admin_StatController extends ZendAfi_Controller_Action {
   }
 
 
-  public function piwikAction() {
-    $this->view->titre = $this->_('Tableau de bord PIWIK');
-    if(!(new Class_AdminVar_Piwik())->isEnabled())
-      return $this->view->error = $this->_('Veuillez renseigner la variable PIWIK_AUTH_TOKEN et JS_STAT');
+  public function matomoAction() {
+    $this->view->titre = $this->_('Tableau de bord MATOMO');
+    if(!(new Class_AdminVar_Matomo())->isEnabled())
+      return $this->view->error = $this->_('Veuillez renseigner la variable MATOMO_AUTH_TOKEN et JS_STAT');
 
-    $this->view->url = $this->_getPiwikDashboardUrl();
+    $this->view->url = $this->_getMatomoDashboardUrl();
   }
 
 
-  protected function _getPiwikDashboardUrl() {
+  protected function _getMatomoDashboardUrl() {
     $js_stat = (new Class_AdminVar_JsStat());
 
-    $base_url = $js_stat->getPiwikUrl() . 'index.php';
-    $auth_token = ['token_auth' => (new Class_AdminVar_Piwik())->getAuthToken()];
-    $id_site = ['idSite' => $js_stat->getPiwikSiteId()];
+    $base_url = $js_stat->getMatomoUrl() . 'index.php';
+    $auth_token = ['token_auth' => (new Class_AdminVar_Matomo())->getAuthToken()];
+    $id_site = ['idSite' => $js_stat->getMatomoSiteId()];
 
     $dashboard_params = ['module' => 'Widgetize',
                          'action' => 'iframe',
diff --git a/application/modules/admin/views/scripts/stat/matomo.phtml b/application/modules/admin/views/scripts/stat/matomo.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..aa926bd56d99a9c88a752ef4a5685ba392706e63
--- /dev/null
+++ b/application/modules/admin/views/scripts/stat/matomo.phtml
@@ -0,0 +1,19 @@
+<?php
+Class_ScriptLoader::getInstance()
+->addJQueryReady('var title = $(".modules h1");
+                 var container_height = Math.round(window.innerHeight - title.position().top - title.height());
+                 var container = $(".modules");
+                 container.height(container_height);
+                 $("iframe#matomo").height(container_height - title.height() - Math.round(container.css("padding-bottom").replace("px","")))');
+
+if($this->error)
+  echo $this->tag('p', $this->error, ['class' => 'error']);
+
+echo $this->tag('iframe', '', ['src' => $this->url,
+                               'id' => 'matomo',
+                               'frameborder' => '0',
+                               'marginheight' => '0',
+                               'marginwidth' => '0',
+                               'width' => '100%',
+                               'scrolling' => 'yes']);
+?>
diff --git a/application/modules/admin/views/scripts/stat/piwik.phtml b/application/modules/admin/views/scripts/stat/piwik.phtml
index 068751548c7465abc25a0f8ebb7e64ee433546a0..aa926bd56d99a9c88a752ef4a5685ba392706e63 100644
--- a/application/modules/admin/views/scripts/stat/piwik.phtml
+++ b/application/modules/admin/views/scripts/stat/piwik.phtml
@@ -4,13 +4,13 @@ Class_ScriptLoader::getInstance()
                  var container_height = Math.round(window.innerHeight - title.position().top - title.height());
                  var container = $(".modules");
                  container.height(container_height);
-                 $("iframe#piwik").height(container_height - title.height() - Math.round(container.css("padding-bottom").replace("px","")))');
+                 $("iframe#matomo").height(container_height - title.height() - Math.round(container.css("padding-bottom").replace("px","")))');
 
 if($this->error)
   echo $this->tag('p', $this->error, ['class' => 'error']);
 
 echo $this->tag('iframe', '', ['src' => $this->url,
-                               'id' => 'piwik',
+                               'id' => 'matomo',
                                'frameborder' => '0',
                                'marginheight' => '0',
                                'marginwidth' => '0',
diff --git a/cosmogramme/sql/patch/patch_354.php b/cosmogramme/sql/patch/patch_354.php
new file mode 100644
index 0000000000000000000000000000000000000000..ecf2be00d27d426c43a65aba23999cf45dbc87f8
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_354.php
@@ -0,0 +1,10 @@
+<?php
+try {
+  $adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+  if (!$adapter->query('select valeur from bib_admin_var where clef="MATOMO_AUTH_TOKEN" and valeur<>""')->fetch()) {
+    $adapter->query('delete from bib_admin_var where CLEF="MATOMO_AUTH_TOKEN"');
+    $adapter->query('update bib_admin_var set CLEF="MATOMO_AUTH_TOKEN" where CLEF="PIWIK_AUTH_TOKEN"');
+  }
+
+  $adapter->query('update bib_admin_var set VALEUR=replace(VALEUR, "piwik", "matomo") where CLEF="JS_STAT"');
+} catch(Exception $e) {var_dump($e);}
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index c401ec3d770e5428c4f77a8784f83471b034fc94..f5ff50d9ad0262df787040e72392dd5e9e489d27 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -385,7 +385,7 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
   protected function _getStatVars() {
     return ['JS_STAT' => Class_AdminVar_Meta::newRawText($this->_('Javascript code for statistics')),
-            'PIWIK_AUTH_TOKEN' => Class_AdminVar_Meta::newDefault($this->_('PIWIK authentication token for widgets'))];
+            'MATOMO_AUTH_TOKEN' => Class_AdminVar_Meta::newDefault($this->_('MATOMO authentication token for widgets'))];
   }
 
 
diff --git a/library/Class/AdminVar/JsStat.php b/library/Class/AdminVar/JsStat.php
index 111be79302e59164878282e420b2f61ce8472f30..27618ee1533b128710bfc887cb82f4ca19fc850a 100644
--- a/library/Class/AdminVar/JsStat.php
+++ b/library/Class/AdminVar/JsStat.php
@@ -22,7 +22,7 @@
 
 class Class_AdminVar_JsStat {
   public function isTrackerSet() {
-    return $this->isGoogleAnalytics() || $this->isPiwik();
+    return $this->isGoogleAnalytics() || $this->isMatomo();
   }
 
 
@@ -31,8 +31,8 @@ class Class_AdminVar_JsStat {
   }
 
 
-  public function isPiwik() {
-    return ($this->getPiwikSiteId() != '');
+  public function isMatomo() {
+    return ($this->getMatomoSiteId() != '');
   }
 
 
@@ -40,7 +40,7 @@ class Class_AdminVar_JsStat {
     return
       $this->isGoogleAnalytics()
       ? $this->_getGoogleAnalyticsId()
-      : $this->getPiwikSiteId();
+      : $this->getMatomoSiteId();
   }
 
 
@@ -49,7 +49,7 @@ class Class_AdminVar_JsStat {
   }
 
 
-  public function getPiwikUrl() {
+  public function getMatomoUrl() {
     return $this->_extractFromJsStat("/var u=.*(\/\/[^\"]+)\"/i", 1);
   }
 
@@ -70,7 +70,7 @@ class Class_AdminVar_JsStat {
   }
 
 
-  public function getPiwikSiteId() {
+  public function getMatomoSiteId() {
     $script = Class_AdminVar::get('JS_STAT');
     preg_match_all("/setSiteId\',([^\]]+)\]\)/i", $script, $matches);
     return isset($matches[1][0]) ? trim($matches[1][0], " \t\n\r\0\x0B'\"") : '';
diff --git a/library/Class/AdminVar/Piwik.php b/library/Class/AdminVar/Matomo.php
similarity index 86%
rename from library/Class/AdminVar/Piwik.php
rename to library/Class/AdminVar/Matomo.php
index 1fb11f0ad52075a1fb30e50b4b31dee5e27deb42..4161a03d9f4a6eac7d737024dce4297a03375193 100644
--- a/library/Class/AdminVar/Piwik.php
+++ b/library/Class/AdminVar/Matomo.php
@@ -20,16 +20,16 @@
  */
 
 
-class Class_AdminVar_Piwik {
+class Class_AdminVar_Matomo {
 
   public function isEnabled() {
     return (('' != $this->getAuthToken())
-            && ('' != (new Class_AdminVar_JsStat())->getPiwikUrl()));
+            && ('' != (new Class_AdminVar_JsStat())->getMatomoUrl()));
   }
 
 
   public function getAuthToken() {
-    return Class_AdminVar::get('PIWIK_AUTH_TOKEN');
+    return Class_AdminVar::get('MATOMO_AUTH_TOKEN');
   }
 }
 ?>
\ No newline at end of file
diff --git a/library/Class/WebService/Analytics/Client.php b/library/Class/WebService/Analytics/Client.php
index 705c1c1a882f63aa0d4c2d9044330a79989989df..39fb2edfbb9e277c5308c8efcd675505856c9bde 100644
--- a/library/Class/WebService/Analytics/Client.php
+++ b/library/Class/WebService/Analytics/Client.php
@@ -28,7 +28,7 @@ class Class_WebService_Analytics_Client {
 
     return $js_stat->isGoogleAnalytics()
       ? new Class_WebService_Analytics_GoogleTracker($js_stat)
-      : new Class_WebService_Analytics_PiwikTracker($js_stat);
+      : new Class_WebService_Analytics_MatomoTracker($js_stat);
   }
 
 
diff --git a/library/Class/WebService/Analytics/PiwikTracker.php b/library/Class/WebService/Analytics/MatomoTracker.php
similarity index 82%
rename from library/Class/WebService/Analytics/PiwikTracker.php
rename to library/Class/WebService/Analytics/MatomoTracker.php
index fa336782250319ffa70f6e6046d324a45f26fc5c..600ad62456ffb59ba09c88c1e68d5cfee748f38a 100644
--- a/library/Class/WebService/Analytics/PiwikTracker.php
+++ b/library/Class/WebService/Analytics/MatomoTracker.php
@@ -19,14 +19,14 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-class Class_WebService_Analytics_PiwikTracker extends Class_WebService_Analytics_NullTracker {
+class Class_WebService_Analytics_MatomoTracker extends Class_WebService_Analytics_NullTracker {
   protected $_tracker;
 
   public function __construct($config) {
-    require_once('piwik-php-tracker/PiwikTracker.php');
+    require_once('matomo-php-tracker/PiwikTracker.php');
     $this->_config = $config;
     $this->_tracker = new PiwikTracker($config->getTrackerId(),
-                                       $config->getPiwikUrl());
+                                       $config->getMatomoUrl());
   }
 
 
@@ -36,7 +36,7 @@ class Class_WebService_Analytics_PiwikTracker extends Class_WebService_Analytics
 
 
   public function getUrl() {
-    return $this->_config->getPiwikUrl() . 'piwik.php';
+    return $this->_config->getMatomoUrl() . 'matomo.php';
   }
 
 
diff --git a/library/ZendAfi/Acl/AdminControllerGroup.php b/library/ZendAfi/Acl/AdminControllerGroup.php
index 5f83a1d122bb71dd933cd9fdd25f24f3a2e6a89f..9693cfd026d3cd79eba28aa1ba6e2cf38f2f6eab 100644
--- a/library/ZendAfi/Acl/AdminControllerGroup.php
+++ b/library/ZendAfi/Acl/AdminControllerGroup.php
@@ -63,7 +63,7 @@ class ZendAfi_Acl_AdminControllerGroup {
                           'album/dilicom' => Class_AdminVar::isDilicomPNBEnabled(),
                           'premier-chapitre' => Class_AdminVar::isPremierChapitreEnabled(),
                           'i18n' => Class_AdminVar::isTranslationEnabled(),
-                          'stat/piwik' => (new Class_AdminVar_Piwik())->isEnabled(),
+                          'stat/matomo' => (new Class_AdminVar_Matomo())->isEnabled(),
                           'multimedia' => Class_AdminVar::isMultimediaEnabled(),
                           'search-form' => Class_AdminVar::isCustomSearchFormEnabled(),
                           ];
diff --git a/library/ZendAfi/View/Helper/Admin/ContentNav.php b/library/ZendAfi/View/Helper/Admin/ContentNav.php
index d728f63b53aee7e94046b96f5a3e60c86967b457..83b6f08ece978640b4569e9b49b83d8032ecd29b 100644
--- a/library/ZendAfi/View/Helper/Admin/ContentNav.php
+++ b/library/ZendAfi/View/Helper/Admin/ContentNav.php
@@ -109,7 +109,7 @@ class ZendAfi_View_Helper_Admin_ContentNav extends ZendAfi_View_Helper_BaseHelpe
   public function menuStats() {
     return $this
       ->renderBloc($this->_('Statistiques'),
-                   [['piwik_stats',      $this->_('Piwik'),                       '/admin/stat/piwik'],
+                   [['matomo_stats',      $this->_('Matomo'),                       '/admin/stat/matomo'],
                     ['failed_searches',  $this->_('Recherches infructueuses'),    '/admin/stat/rechercheinfructueuse']
                    ]);
   }
diff --git a/library/ZendAfi/View/Helper/Admin/HelpLink.php b/library/ZendAfi/View/Helper/Admin/HelpLink.php
index cb3334fec4225f17b69c9c5658df26ee9c8c741b..c4a9c02fcc7d0eaa52028620cf8712e4468dff1d 100644
--- a/library/ZendAfi/View/Helper/Admin/HelpLink.php
+++ b/library/ZendAfi/View/Helper/Admin/HelpLink.php
@@ -104,7 +104,7 @@ class ZendAfi_View_Helper_Admin_HelpLinkBokehWiki {
      'bib'                    => ['index' => 'Modifier_une_bibliothèque'],
      'index'                  => ['index' => 'Bokeh',
                                   'update-skin' => 'Mettre_à_jour_la_charte_graphique'],
-     'stat'                   => ['piwik' => 'Piwik'],
+     'stat'                   => ['matomo' => 'Matomo'],
      'print'                  => ['index' => 'Imprimer_un_résultat_de_recherche,_une_notice_ou_des_articles'],
      'file-manager'           => ['index' => 'Explorateur_de_fichiers']
     ];
diff --git a/library/matomo-php-tracker/.gitignore b/library/matomo-php-tracker/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..57f1cb2a7a1855e09f3a4d4bbb900ebfc4b23621
--- /dev/null
+++ b/library/matomo-php-tracker/.gitignore
@@ -0,0 +1 @@
+/.idea/
\ No newline at end of file
diff --git a/library/matomo-php-tracker/LICENSE b/library/matomo-php-tracker/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..f7cc808c382e7e791d688f4d2585dc90360e86cc
--- /dev/null
+++ b/library/matomo-php-tracker/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014, Piwik Open Source Analytics
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/library/matomo-php-tracker/PiwikTracker.php b/library/matomo-php-tracker/PiwikTracker.php
new file mode 100644
index 0000000000000000000000000000000000000000..9e40975e3f614567a50ac01b2489a7309e71642c
--- /dev/null
+++ b/library/matomo-php-tracker/PiwikTracker.php
@@ -0,0 +1,2049 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * For more information, see README.md
+ *
+ * @license released under BSD License http://www.opensource.org/licenses/bsd-license.php
+ * @link http://piwik.org/docs/tracking-api/
+ *
+ * @category Piwik
+ * @package PiwikTracker
+ */
+
+/**
+ * PiwikTracker implements the Piwik Tracking Web API.
+ *
+ * For more information, see README.md
+ *
+ * @package PiwikTracker
+ * @api
+ */
+class PiwikTracker
+{
+    /**
+     * Piwik base URL, for example http://example.org/piwik/
+     * Must be set before using the class by calling
+     * PiwikTracker::$URL = 'http://yourwebsite.org/piwik/';
+     *
+     * @var string
+     */
+    static public $URL = '';
+
+    /**
+     * API Version
+     *
+     * @ignore
+     * @var int
+     */
+    const VERSION = 1;
+
+    /**
+     * @ignore
+     */
+    public $DEBUG_APPEND_URL = '';
+
+    /**
+     * Visitor ID length
+     *
+     * @ignore
+     */
+    const LENGTH_VISITOR_ID = 16;
+
+    /**
+     * Charset
+     * @see setPageCharset
+     * @ignore
+     */
+    const DEFAULT_CHARSET_PARAMETER_VALUES = 'utf-8';
+
+    /**
+     * See piwik.js
+     */
+    const FIRST_PARTY_COOKIES_PREFIX = '_pk_';
+
+    /**
+     * Ecommerce item page view tracking stores item's metadata in these Custom Variables slots.
+     */
+    const CVAR_INDEX_ECOMMERCE_ITEM_PRICE = 2;
+    const CVAR_INDEX_ECOMMERCE_ITEM_SKU = 3;
+    const CVAR_INDEX_ECOMMERCE_ITEM_NAME = 4;
+    const CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY = 5;
+
+    /**
+     * Defines how many categories can be used max when calling addEcommerceItem().
+     * @var int
+     */
+    const MAX_NUM_ECOMMERCE_ITEM_CATEGORIES = 5;
+
+    const DEFAULT_COOKIE_PATH = '/';
+
+    /**
+     * Builds a PiwikTracker object, used to track visits, pages and Goal conversions
+     * for a specific website, by using the Piwik Tracking API.
+     *
+     * @param int $idSite Id site to be tracked
+     * @param string $apiUrl "http://example.org/piwik/" or "http://piwik.example.org/"
+     *                         If set, will overwrite PiwikTracker::$URL
+     */
+    public function __construct($idSite, $apiUrl = '')
+    {
+        $this->ecommerceItems = array();
+        $this->attributionInfo = false;
+        $this->eventCustomVar = false;
+        $this->forcedDatetime = false;
+        $this->forcedNewVisit = false;
+        $this->generationTime = false;
+        $this->pageCustomVar = false;
+        $this->customParameters = array();
+        $this->customData = false;
+        $this->hasCookies = false;
+        $this->token_auth = false;
+        $this->userAgent = false;
+        $this->country = false;
+        $this->region = false;
+        $this->city = false;
+        $this->lat = false;
+        $this->long = false;
+        $this->width = false;
+        $this->height = false;
+        $this->plugins = false;
+        $this->localHour = false;
+        $this->localMinute = false;
+        $this->localSecond = false;
+        $this->idPageview = false;
+
+        $this->idSite = $idSite;
+        $this->urlReferrer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : false;
+        $this->pageCharset = self::DEFAULT_CHARSET_PARAMETER_VALUES;
+        $this->pageUrl = self::getCurrentUrl();
+        $this->ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
+        $this->acceptLanguage = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : false;
+        $this->userAgent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : false;
+        if (!empty($apiUrl)) {
+            self::$URL = $apiUrl;
+        }
+
+        // Life of the visitor cookie (in sec)
+        $this->configVisitorCookieTimeout = 33955200; // 13 months (365 + 28 days)
+        // Life of the session cookie (in sec)
+        $this->configSessionCookieTimeout = 1800; // 30 minutes
+        // Life of the session cookie (in sec)
+        $this->configReferralCookieTimeout = 15768000; // 6 months
+
+        // Visitor Ids in order
+        $this->userId = false;
+        $this->forcedVisitorId = false;
+        $this->cookieVisitorId = false;
+        $this->randomVisitorId = false;
+
+        $this->setNewVisitorId();
+
+        $this->configCookiesDisabled = false;
+        $this->configCookiePath = self::DEFAULT_COOKIE_PATH;
+        $this->configCookieDomain = '';
+
+        $this->currentTs = time();
+        $this->createTs = $this->currentTs;
+        $this->visitCount = 0;
+        $this->currentVisitTs = false;
+        $this->lastVisitTs = false;
+        $this->ecommerceLastOrderTimestamp = false;
+
+        // Allow debug while blocking the request
+        $this->requestTimeout = 600;
+        $this->doBulkRequests = false;
+        $this->storedTrackingActions = array();
+
+        $this->sendImageResponse = true;
+
+        $this->visitorCustomVar = $this->getCustomVariablesFromCookie();
+        
+        $this->outgoingTrackerCookies = array();
+        $this->incomingTrackerCookies = array();
+    }
+
+    /**
+     * By default, Piwik expects utf-8 encoded values, for example
+     * for the page URL parameter values, Page Title, etc.
+     * It is recommended to only send UTF-8 data to Piwik.
+     * If required though, you can also specify another charset using this function.
+     *
+     * @param string $charset
+     * @return $this
+     */
+    public function setPageCharset($charset = '')
+    {
+        $this->pageCharset = $charset;
+        return $this;
+    }
+
+    /**
+     * Sets the current URL being tracked
+     *
+     * @param string $url Raw URL (not URL encoded)
+     * @return $this
+     */
+    public function setUrl($url)
+    {
+        $this->pageUrl = $url;
+        return $this;
+    }
+
+    /**
+     * Sets the URL referrer used to track Referrers details for new visits.
+     *
+     * @param string $url Raw URL (not URL encoded)
+     * @return $this
+     */
+    public function setUrlReferrer($url)
+    {
+        $this->urlReferrer = $url;
+        return $this;
+    }
+
+    /**
+     * Sets the time that generating the document on the server side took.
+     *
+     * @param int $timeMs Generation time in ms
+     * @return $this
+     */
+    public function setGenerationTime($timeMs)
+    {
+        $this->generationTime = $timeMs;
+        return $this;
+    }
+
+    /**
+     * @deprecated
+     * @ignore
+     */
+    public function setUrlReferer($url)
+    {
+        $this->setUrlReferrer($url);
+        return $this;
+    }
+
+    /**
+     * Sets the attribution information to the visit, so that subsequent Goal conversions are
+     * properly attributed to the right Referrer URL, timestamp, Campaign Name & Keyword.
+     *
+     * This must be a JSON encoded string that would typically be fetched from the JS API:
+     * piwikTracker.getAttributionInfo() and that you have JSON encoded via JSON2.stringify()
+     *
+     * If you call enableCookies() then these referral attribution values will be set
+     * to the 'ref' first party cookie storing referral information.
+     *
+     * @param string $jsonEncoded JSON encoded array containing Attribution info
+     * @return $this
+     * @throws Exception
+     * @see function getAttributionInfo() in https://github.com/piwik/piwik/blob/master/js/piwik.js
+     */
+    public function setAttributionInfo($jsonEncoded)
+    {
+        $decoded = json_decode($jsonEncoded, $assoc = true);
+        if (!is_array($decoded)) {
+            throw new Exception("setAttributionInfo() is expecting a JSON encoded string, $jsonEncoded given");
+        }
+        $this->attributionInfo = $decoded;
+        return $this;
+    }
+
+    /**
+     * Sets Visit Custom Variable.
+     * See http://piwik.org/docs/custom-variables/
+     *
+     * @param int $id Custom variable slot ID from 1-5
+     * @param string $name Custom variable name
+     * @param string $value Custom variable value
+     * @param string $scope Custom variable scope. Possible values: visit, page, event
+     * @return $this
+     * @throws Exception
+     */
+    public function setCustomVariable($id, $name, $value, $scope = 'visit')
+    {
+        if (!is_int($id)) {
+            throw new Exception("Parameter id to setCustomVariable should be an integer");
+        }
+        if ($scope == 'page') {
+            $this->pageCustomVar[$id] = array($name, $value);
+        } elseif ($scope == 'event') {
+            $this->eventCustomVar[$id] = array($name, $value);
+        } elseif ($scope == 'visit') {
+            $this->visitorCustomVar[$id] = array($name, $value);
+        } else {
+            throw new Exception("Invalid 'scope' parameter value");
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the currently assigned Custom Variable.
+     *
+     * If scope is 'visit', it will attempt to read the value set in the first party cookie created by Piwik Tracker
+     *  ($_COOKIE array).
+     *
+     * @param int $id Custom Variable integer index to fetch from cookie. Should be a value from 1 to 5
+     * @param string $scope Custom variable scope. Possible values: visit, page, event
+     *
+     * @throws Exception
+     * @return mixed An array with this format: array( 0 => CustomVariableName, 1 => CustomVariableValue ) or false
+     * @see Piwik.js getCustomVariable()
+     */
+    public function getCustomVariable($id, $scope = 'visit')
+    {
+        if ($scope == 'page') {
+            return isset($this->pageCustomVar[$id]) ? $this->pageCustomVar[$id] : false;
+        } elseif ($scope == 'event') {
+            return isset($this->eventCustomVar[$id]) ? $this->eventCustomVar[$id] : false;
+        } else {
+            if ($scope != 'visit') {
+                throw new Exception("Invalid 'scope' parameter value");
+            }
+        }
+        if (!empty($this->visitorCustomVar[$id])) {
+            return $this->visitorCustomVar[$id];
+        }
+        $cookieDecoded = $this->getCustomVariablesFromCookie();
+        if (!is_int($id)) {
+            throw new Exception("Parameter to getCustomVariable should be an integer");
+        }
+        if (!is_array($cookieDecoded)
+            || !isset($cookieDecoded[$id])
+            || !is_array($cookieDecoded[$id])
+            || count($cookieDecoded[$id]) != 2
+        ) {
+            return false;
+        }
+
+        return $cookieDecoded[$id];
+    }
+
+    /**
+     * Clears any Custom Variable that may be have been set.
+     *
+     * This can be useful when you have enabled bulk requests,
+     * and you wish to clear Custom Variables of 'visit' scope.
+     */
+    public function clearCustomVariables()
+    {
+        $this->visitorCustomVar = array();
+        $this->pageCustomVar = array();
+        $this->eventCustomVar = array();
+    }
+
+    /**
+     * Sets a custom tracking parameter. This is useful if you need to send any tracking parameters for a 3rd party
+     * plugin that is not shipped with Piwik itself. Please note that custom parameters are cleared after each
+     * tracking request.
+     *
+     * @param string $trackingApiParameter The name of the tracking API parameter, eg 'dimension1'
+     * @param string $value Tracking parameter value that shall be sent for this tracking parameter.
+     * @return $this
+     * @throws Exception
+     */
+    public function setCustomTrackingParameter($trackingApiParameter, $value)
+    {
+        $this->customParameters[$trackingApiParameter] = $value;
+        return $this;
+    }
+
+    /**
+     * Clear / reset all previously set custom tracking parameters.
+     */
+    public function clearCustomTrackingParameters()
+    {
+        $this->customParameters = array();
+    }
+
+    /**
+     * Sets the current visitor ID to a random new one.
+     * @return $this
+     */
+    public function setNewVisitorId()
+    {
+        $this->randomVisitorId = substr(md5(uniqid(rand(), true)), 0, self::LENGTH_VISITOR_ID);
+        $this->userId = false;
+        $this->forcedVisitorId = false;
+        $this->cookieVisitorId = false;
+        return $this;
+    }
+
+    /**
+     * Sets the current site ID.
+     *
+     * @param int $idSite
+     * @return $this
+     */
+    public function setIdSite($idSite)
+    {
+        $this->idSite = $idSite;
+        return $this;
+    }
+
+    /**
+     * Sets the Browser language. Used to guess visitor countries when GeoIP is not enabled
+     *
+     * @param string $acceptLanguage For example "fr-fr"
+     * @return $this
+     */
+    public function setBrowserLanguage($acceptLanguage)
+    {
+        $this->acceptLanguage = $acceptLanguage;
+        return $this;
+    }
+
+    /**
+     * Sets the user agent, used to detect OS and browser.
+     * If this function is not called, the User Agent will default to the current user agent.
+     *
+     * @param string $userAgent
+     * @return $this
+     */
+    public function setUserAgent($userAgent)
+    {
+        $this->userAgent = $userAgent;
+        return $this;
+    }
+
+    /**
+     * Sets the country of the visitor. If not used, Piwik will try to find the country
+     * using either the visitor's IP address or language.
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth().
+     * @param string $country
+     * @return $this
+     */
+    public function setCountry($country)
+    {
+        $this->country = $country;
+        return $this;
+    }
+
+    /**
+     * Sets the region of the visitor. If not used, Piwik may try to find the region
+     * using the visitor's IP address (if configured to do so).
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth().
+     * @param string $region
+     * @return $this
+     */
+    public function setRegion($region)
+    {
+        $this->region = $region;
+        return $this;
+    }
+
+    /**
+     * Sets the city of the visitor. If not used, Piwik may try to find the city
+     * using the visitor's IP address (if configured to do so).
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth().
+     * @param string $city
+     * @return $this
+     */
+    public function setCity($city)
+    {
+        $this->city = $city;
+        return $this;
+    }
+
+    /**
+     * Sets the latitude of the visitor. If not used, Piwik may try to find the visitor's
+     * latitude using the visitor's IP address (if configured to do so).
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth().
+     * @param float $lat
+     * @return $this
+     */
+    public function setLatitude($lat)
+    {
+        $this->lat = $lat;
+        return $this;
+    }
+
+    /**
+     * Sets the longitude of the visitor. If not used, Piwik may try to find the visitor's
+     * longitude using the visitor's IP address (if configured to do so).
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth().
+     * @param float $long
+     * @return $this
+     */
+    public function setLongitude($long)
+    {
+        $this->long = $long;
+        return $this;
+    }
+
+    /**
+     * Enables the bulk request feature. When used, each tracking action is stored until the
+     * doBulkTrack method is called. This method will send all tracking data at once.
+     *
+     */
+    public function enableBulkTracking()
+    {
+        $this->doBulkRequests = true;
+    }
+
+    /**
+     * Enable Cookie Creation - this will cause a first party VisitorId cookie to be set when the VisitorId is set or reset
+     *
+     * @param string $domain (optional) Set first-party cookie domain.
+     *  Accepted values: example.com, *.example.com (same as .example.com) or subdomain.example.com
+     * @param string $path (optional) Set first-party cookie path
+     */
+    public function enableCookies($domain = '', $path = '/')
+    {
+        $this->configCookiesDisabled = false;
+        $this->configCookieDomain = self::domainFixup($domain);
+        $this->configCookiePath = $path;
+    }
+
+    /**
+     * If image response is disabled Piwik will respond with a HTTP 204 header instead of responding with a gif.
+     */
+    public function disableSendImageResponse()
+    {
+        $this->sendImageResponse = false;
+    }
+
+    /**
+     * Fix-up domain
+     */
+    protected static function domainFixup($domain)
+    {
+        if (strlen($domain) > 0) {
+            $dl = strlen($domain) - 1;
+            // remove trailing '.'
+            if ($domain{$dl} === '.') {
+                $domain = substr($domain, 0, $dl);
+            }
+            // remove leading '*'
+            if (substr($domain, 0, 2) === '*.') {
+                $domain = substr($domain, 1);
+            }
+        }
+
+        return $domain;
+    }
+
+    /**
+     * Get cookie name with prefix and domain hash
+     * @param string $cookieName
+     * @return string
+     */
+    protected function getCookieName($cookieName)
+    {
+        // NOTE: If the cookie name is changed, we must also update the method in piwik.js with the same name.
+        $hash = substr(
+            sha1(
+                ($this->configCookieDomain == '' ? self::getCurrentHost() : $this->configCookieDomain) . $this->configCookiePath
+            ),
+            0,
+            4
+        );
+
+        return self::FIRST_PARTY_COOKIES_PREFIX . $cookieName . '.' . $this->idSite . '.' . $hash;
+    }
+
+    /**
+     * Tracks a page view
+     *
+     * @param string $documentTitle Page title as it will appear in the Actions > Page titles report
+     * @return mixed Response string or true if using bulk requests.
+     */
+    public function doTrackPageView($documentTitle)
+    {
+        $this->generateNewPageviewId();
+
+        $url = $this->getUrlTrackPageView($documentTitle);
+
+        return $this->sendRequest($url);
+    }
+
+    private function generateNewPageviewId()
+    {
+        $this->idPageview = substr(md5(uniqid(rand(), true)), 0, 6);
+    }
+
+    /**
+     * Tracks an event
+     *
+     * @param string $category The Event Category (Videos, Music, Games...)
+     * @param string $action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
+     * @param string|bool $name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
+     * @param float|bool $value (optional) The Event's value
+     * @return mixed Response string or true if using bulk requests.
+     */
+    public function doTrackEvent($category, $action, $name = false, $value = false)
+    {
+        $url = $this->getUrlTrackEvent($category, $action, $name, $value);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Tracks a content impression
+     *
+     * @param string $contentName The name of the content. For instance 'Ad Foo Bar'
+     * @param string $contentPiece The actual content. For instance the path to an image, video, audio, any text
+     * @param string|bool $contentTarget (optional) The target of the content. For instance the URL of a landing page.
+     * @return mixed Response string or true if using bulk requests.
+     */
+    public function doTrackContentImpression($contentName, $contentPiece = 'Unknown', $contentTarget = false)
+    {
+        $url = $this->getUrlTrackContentImpression($contentName, $contentPiece, $contentTarget);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Tracks a content interaction. Make sure you have tracked a content impression using the same content name and
+     * content piece, otherwise it will not count. To do so you should call the method doTrackContentImpression();
+     *
+     * @param string $interaction The name of the interaction with the content. For instance a 'click'
+     * @param string $contentName The name of the content. For instance 'Ad Foo Bar'
+     * @param string $contentPiece The actual content. For instance the path to an image, video, audio, any text
+     * @param string|bool $contentTarget (optional) The target the content leading to when an interaction occurs. For instance the URL of a landing page.
+     * @return mixed Response string or true if using bulk requests.
+     */
+    public function doTrackContentInteraction(
+        $interaction,
+        $contentName,
+        $contentPiece = 'Unknown',
+        $contentTarget = false
+    )
+    {
+        $url = $this->getUrlTrackContentInteraction($interaction, $contentName, $contentPiece, $contentTarget);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Tracks an internal Site Search query, and optionally tracks the Search Category, and Search results Count.
+     * These are used to populate reports in Actions > Site Search.
+     *
+     * @param string $keyword Searched query on the site
+     * @param string $category (optional) Search engine category if applicable
+     * @param bool|int $countResults (optional) results displayed on the search result page. Used to track "zero result" keywords.
+     *
+     * @return mixed Response or true if using bulk requests.
+     */
+    public function doTrackSiteSearch($keyword, $category = '', $countResults = false)
+    {
+        $url = $this->getUrlTrackSiteSearch($keyword, $category, $countResults);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Records a Goal conversion
+     *
+     * @param int $idGoal Id Goal to record a conversion
+     * @param float $revenue Revenue for this conversion
+     * @return mixed Response or true if using bulk request
+     */
+    public function doTrackGoal($idGoal, $revenue = 0.0)
+    {
+        $url = $this->getUrlTrackGoal($idGoal, $revenue);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Tracks a download or outlink
+     *
+     * @param string $actionUrl URL of the download or outlink
+     * @param string $actionType Type of the action: 'download' or 'link'
+     * @return mixed Response or true if using bulk request
+     */
+    public function doTrackAction($actionUrl, $actionType)
+    {
+        // Referrer could be udpated to be the current URL temporarily (to mimic JS behavior)
+        $url = $this->getUrlTrackAction($actionUrl, $actionType);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Adds an item in the Ecommerce order.
+     *
+     * This should be called before doTrackEcommerceOrder(), or before doTrackEcommerceCartUpdate().
+     * This function can be called for all individual products in the cart (or order).
+     * SKU parameter is mandatory. Other parameters are optional (set to false if value not known).
+     * Ecommerce items added via this function are automatically cleared when doTrackEcommerceOrder() or getUrlTrackEcommerceOrder() is called.
+     *
+     * @param string $sku (required) SKU, Product identifier
+     * @param string $name (optional) Product name
+     * @param string|array $category (optional) Product category, or array of product categories (up to 5 categories can be specified for a given product)
+     * @param float|int $price (optional) Individual product price (supports integer and decimal prices)
+     * @param int $quantity (optional) Product quantity. If not specified, will default to 1 in the Reports
+     * @throws Exception
+     */
+    public function addEcommerceItem($sku, $name = '', $category = '', $price = 0.0, $quantity = 1)
+    {
+        if (empty($sku)) {
+            throw new Exception("You must specify a SKU for the Ecommerce item");
+        }
+
+        $price = $this->forceDotAsSeparatorForDecimalPoint($price);
+
+        $this->ecommerceItems[] = array($sku, $name, $category, $price, $quantity);
+    }
+
+    /**
+     * Tracks a Cart Update (add item, remove item, update item).
+     *
+     * On every Cart update, you must call addEcommerceItem() for each item (product) in the cart,
+     * including the items that haven't been updated since the last cart update.
+     * Items which were in the previous cart and are not sent in later Cart updates will be deleted from the cart (in the database).
+     *
+     * @param float $grandTotal Cart grandTotal (typically the sum of all items' prices)
+     * @return mixed Response or true if using bulk request
+     */
+    public function doTrackEcommerceCartUpdate($grandTotal)
+    {
+        $url = $this->getUrlTrackEcommerceCartUpdate($grandTotal);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Sends all stored tracking actions at once. Only has an effect if bulk tracking is enabled.
+     *
+     * To enable bulk tracking, call enableBulkTracking().
+     *
+     * @throws Exception
+     * @return string Response
+     */
+    public function doBulkTrack()
+    {
+        if (empty($this->storedTrackingActions)) {
+            throw new Exception(
+                "Error:  you must call the function doTrackPageView or doTrackGoal from this class,
+                 before calling this method doBulkTrack()"
+            );
+        }
+
+        $data = array('requests' => $this->storedTrackingActions);
+
+        // token_auth is not required by default, except if bulk_requests_require_authentication=1
+        if (!empty($this->token_auth)) {
+            $data['token_auth'] = $this->token_auth;
+        }
+
+        $postData = json_encode($data);
+        $response = $this->sendRequest($this->getBaseUrl(), 'POST', $postData, $force = true);
+
+        $this->storedTrackingActions = array();
+
+        return $response;
+    }
+
+    /**
+     * Tracks an Ecommerce order.
+     *
+     * If the Ecommerce order contains items (products), you must call first the addEcommerceItem() for each item in the order.
+     * All revenues (grandTotal, subTotal, tax, shipping, discount) will be individually summed and reported in Piwik reports.
+     * Only the parameters $orderId and $grandTotal are required.
+     *
+     * @param string|int $orderId (required) Unique Order ID.
+     *                This will be used to count this order only once in the event the order page is reloaded several times.
+     *                orderId must be unique for each transaction, even on different days, or the transaction will not be recorded by Piwik.
+     * @param float $grandTotal (required) Grand Total revenue of the transaction (including tax, shipping, etc.)
+     * @param float $subTotal (optional) Sub total amount, typically the sum of items prices for all items in this order (before Tax and Shipping costs are applied)
+     * @param float $tax (optional) Tax amount for this order
+     * @param float $shipping (optional) Shipping amount for this order
+     * @param float $discount (optional) Discounted amount in this order
+     * @return mixed Response or true if using bulk request
+     */
+    public function doTrackEcommerceOrder(
+        $orderId,
+        $grandTotal,
+        $subTotal = 0.0,
+        $tax = 0.0,
+        $shipping = 0.0,
+        $discount = 0.0
+    )
+    {
+        $url = $this->getUrlTrackEcommerceOrder($orderId, $grandTotal, $subTotal, $tax, $shipping, $discount);
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Sends a ping request.
+     *
+     * Ping requests do not track new actions. If they are sent within the standard visit length (see global.ini.php),
+     * they will extend the existing visit and the current last action for the visit. If after the standard visit length,
+     * ping requests will create a new visit using the last action in the last known visit.
+     *
+     * @return mixed Response or true if using bulk request
+     */
+    public function doPing()
+    {
+        $url = $this->getRequest($this->idSite);
+        $url .= '&ping=1';
+
+        return $this->sendRequest($url);
+    }
+
+    /**
+     * Sets the current page view as an item (product) page view, or an Ecommerce Category page view.
+     *
+     * This must be called before doTrackPageView() on this product/category page.
+     * It will set 3 custom variables of scope "page" with the SKU, Name and Category for this page view.
+     * Note: Custom Variables of scope "page" slots 3, 4 and 5 will be used.
+     *
+     * On a category page, you may set the parameter $category only and set the other parameters to false.
+     *
+     * Tracking Product/Category page views will allow Piwik to report on Product & Categories
+     * conversion rates (Conversion rate = Ecommerce orders containing this product or category / Visits to the product or category)
+     *
+     * @param string $sku Product SKU being viewed
+     * @param string $name Product Name being viewed
+     * @param string|array $category Category being viewed. On a Product page, this is the product's category.
+     *                                You can also specify an array of up to 5 categories for a given page view.
+     * @param float $price Specify the price at which the item was displayed
+     * @return $this
+     */
+    public function setEcommerceView($sku = '', $name = '', $category = '', $price = 0.0)
+    {
+        if (!empty($category)) {
+            if (is_array($category)) {
+                $category = json_encode($category);
+            }
+        } else {
+            $category = "";
+        }
+        $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY] = array('_pkc', $category);
+
+        if (!empty($price)) {
+            $price = (float)$price;
+            $price = $this->forceDotAsSeparatorForDecimalPoint($price);
+            $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_PRICE] = array('_pkp', $price);
+        }
+
+        // On a category page, do not record "Product name not defined"
+        if (empty($sku) && empty($name)) {
+            return $this;
+        }
+        if (!empty($sku)) {
+            $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_SKU] = array('_pks', $sku);
+        }
+        if (empty($name)) {
+            $name = "";
+        }
+        $this->pageCustomVar[self::CVAR_INDEX_ECOMMERCE_ITEM_NAME] = array('_pkn', $name);
+        return $this;
+    }
+
+    /**
+     * Force the separator for decimal point to be a dot. See https://github.com/piwik/piwik/issues/6435
+     * If for instance a German locale is used it would be a comma otherwise.
+     *
+     * @param  float|string $value
+     * @return string
+     */
+    private function forceDotAsSeparatorForDecimalPoint($value)
+    {
+        if (null === $value || false === $value) {
+            return $value;
+        }
+
+        return str_replace(',', '.', $value);
+    }
+
+    /**
+     * Returns URL used to track Ecommerce Cart updates
+     * Calling this function will reinitializes the property ecommerceItems to empty array
+     * so items will have to be added again via addEcommerceItem()
+     * @ignore
+     */
+    public function getUrlTrackEcommerceCartUpdate($grandTotal)
+    {
+        $url = $this->getUrlTrackEcommerce($grandTotal);
+
+        return $url;
+    }
+
+    /**
+     * Returns URL used to track Ecommerce Orders
+     * Calling this function will reinitializes the property ecommerceItems to empty array
+     * so items will have to be added again via addEcommerceItem()
+     * @ignore
+     */
+    public function getUrlTrackEcommerceOrder(
+        $orderId,
+        $grandTotal,
+        $subTotal = 0.0,
+        $tax = 0.0,
+        $shipping = 0.0,
+        $discount = 0.0
+    )
+    {
+        if (empty($orderId)) {
+            throw new Exception("You must specifiy an orderId for the Ecommerce order");
+        }
+        $url = $this->getUrlTrackEcommerce($grandTotal, $subTotal, $tax, $shipping, $discount);
+        $url .= '&ec_id=' . urlencode($orderId);
+        $this->ecommerceLastOrderTimestamp = $this->getTimestamp();
+
+        return $url;
+    }
+
+    /**
+     * Returns URL used to track Ecommerce orders
+     *
+     * Calling this function will reinitializes the property ecommerceItems to empty array
+     * so items will have to be added again via addEcommerceItem()
+     *
+     * @ignore
+     */
+    protected function getUrlTrackEcommerce($grandTotal, $subTotal = 0.0, $tax = 0.0, $shipping = 0.0, $discount = 0.0)
+    {
+        if (!is_numeric($grandTotal)) {
+            throw new Exception("You must specifiy a grandTotal for the Ecommerce order (or Cart update)");
+        }
+
+        $url = $this->getRequest($this->idSite);
+        $url .= '&idgoal=0';
+        if (!empty($grandTotal)) {
+            $grandTotal = $this->forceDotAsSeparatorForDecimalPoint($grandTotal);
+            $url .= '&revenue=' . $grandTotal;
+        }
+        if (!empty($subTotal)) {
+            $subTotal = $this->forceDotAsSeparatorForDecimalPoint($subTotal);
+            $url .= '&ec_st=' . $subTotal;
+        }
+        if (!empty($tax)) {
+            $tax = $this->forceDotAsSeparatorForDecimalPoint($tax);
+            $url .= '&ec_tx=' . $tax;
+        }
+        if (!empty($shipping)) {
+            $shipping = $this->forceDotAsSeparatorForDecimalPoint($shipping);
+            $url .= '&ec_sh=' . $shipping;
+        }
+        if (!empty($discount)) {
+            $discount = $this->forceDotAsSeparatorForDecimalPoint($discount);
+            $url .= '&ec_dt=' . $discount;
+        }
+        if (!empty($this->ecommerceItems)) {
+            $url .= '&ec_items=' . urlencode(json_encode($this->ecommerceItems));
+        }
+        $this->ecommerceItems = array();
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a page view.
+     *
+     * @see doTrackPageView()
+     * @param string $documentTitle Page view name as it will appear in Piwik reports
+     * @return string URL to piwik.php with all parameters set to track the pageview
+     */
+    public function getUrlTrackPageView($documentTitle = '')
+    {
+        $url = $this->getRequest($this->idSite);
+        if (strlen($documentTitle) > 0) {
+            $url .= '&action_name=' . urlencode($documentTitle);
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a custom event.
+     *
+     * @see doTrackEvent()
+     * @param string $category The Event Category (Videos, Music, Games...)
+     * @param string $action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
+     * @param string|bool $name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
+     * @param float|bool $value (optional) The Event's value
+     * @return string URL to piwik.php with all parameters set to track the pageview
+     * @throws
+     */
+    public function getUrlTrackEvent($category, $action, $name = false, $value = false)
+    {
+        $url = $this->getRequest($this->idSite);
+        if (strlen($category) == 0) {
+            throw new Exception("You must specify an Event Category name (Music, Videos, Games...).");
+        }
+        if (strlen($action) == 0) {
+            throw new Exception("You must specify an Event action (click, view, add...).");
+        }
+
+        $url .= '&e_c=' . urlencode($category);
+        $url .= '&e_a=' . urlencode($action);
+
+        if (strlen($name) > 0) {
+            $url .= '&e_n=' . urlencode($name);
+        }
+        if (strlen($value) > 0) {
+            $value = $this->forceDotAsSeparatorForDecimalPoint($value);
+            $url .= '&e_v=' . $value;
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a content impression.
+     *
+     * @see doTrackContentImpression()
+     * @param string $contentName The name of the content. For instance 'Ad Foo Bar'
+     * @param string $contentPiece The actual content. For instance the path to an image, video, audio, any text
+     * @param string|false $contentTarget (optional) The target of the content. For instance the URL of a landing page.
+     * @throws Exception In case $contentName is empty
+     * @return string URL to piwik.php with all parameters set to track the pageview
+     */
+    public function getUrlTrackContentImpression($contentName, $contentPiece, $contentTarget)
+    {
+        $url = $this->getRequest($this->idSite);
+
+        if (strlen($contentName) == 0) {
+            throw new Exception("You must specify a content name");
+        }
+
+        $url .= '&c_n=' . urlencode($contentName);
+
+        if (!empty($contentPiece) && strlen($contentPiece) > 0) {
+            $url .= '&c_p=' . urlencode($contentPiece);
+        }
+        if (!empty($contentTarget) && strlen($contentTarget) > 0) {
+            $url .= '&c_t=' . urlencode($contentTarget);
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a content impression.
+     *
+     * @see doTrackContentInteraction()
+     * @param string $interaction The name of the interaction with the content. For instance a 'click'
+     * @param string $contentName The name of the content. For instance 'Ad Foo Bar'
+     * @param string $contentPiece The actual content. For instance the path to an image, video, audio, any text
+     * @param string|false $contentTarget (optional) The target the content leading to when an interaction occurs. For instance the URL of a landing page.
+     * @throws Exception In case $interaction or $contentName is empty
+     * @return string URL to piwik.php with all parameters set to track the pageview
+     */
+    public function getUrlTrackContentInteraction($interaction, $contentName, $contentPiece, $contentTarget)
+    {
+        $url = $this->getRequest($this->idSite);
+
+        if (strlen($interaction) == 0) {
+            throw new Exception("You must specify a name for the interaction");
+        }
+
+        if (strlen($contentName) == 0) {
+            throw new Exception("You must specify a content name");
+        }
+
+        $url .= '&c_i=' . urlencode($interaction);
+        $url .= '&c_n=' . urlencode($contentName);
+
+        if (!empty($contentPiece) && strlen($contentPiece) > 0) {
+            $url .= '&c_p=' . urlencode($contentPiece);
+        }
+        if (!empty($contentTarget) && strlen($contentTarget) > 0) {
+            $url .= '&c_t=' . urlencode($contentTarget);
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a site search.
+     *
+     * @see doTrackSiteSearch()
+     * @param string $keyword
+     * @param string $category
+     * @param int $countResults
+     * @return string
+     */
+    public function getUrlTrackSiteSearch($keyword, $category, $countResults)
+    {
+        $url = $this->getRequest($this->idSite);
+        $url .= '&search=' . urlencode($keyword);
+        if (strlen($category) > 0) {
+            $url .= '&search_cat=' . urlencode($category);
+        }
+        if (!empty($countResults) || $countResults === 0) {
+            $url .= '&search_count=' . (int)$countResults;
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a goal with idGoal and revenue.
+     *
+     * @see doTrackGoal()
+     * @param int $idGoal Id Goal to record a conversion
+     * @param float $revenue Revenue for this conversion
+     * @return string URL to piwik.php with all parameters set to track the goal conversion
+     */
+    public function getUrlTrackGoal($idGoal, $revenue = 0.0)
+    {
+        $url = $this->getRequest($this->idSite);
+        $url .= '&idgoal=' . $idGoal;
+        if (!empty($revenue)) {
+            $revenue = $this->forceDotAsSeparatorForDecimalPoint($revenue);
+            $url .= '&revenue=' . $revenue;
+        }
+
+        return $url;
+    }
+
+    /**
+     * Builds URL to track a new action.
+     *
+     * @see doTrackAction()
+     * @param string $actionUrl URL of the download or outlink
+     * @param string $actionType Type of the action: 'download' or 'link'
+     * @return string URL to piwik.php with all parameters set to track an action
+     */
+    public function getUrlTrackAction($actionUrl, $actionType)
+    {
+        $url = $this->getRequest($this->idSite);
+        $url .= '&' . $actionType . '=' . urlencode($actionUrl);
+
+        return $url;
+    }
+
+    /**
+     * Overrides server date and time for the tracking requests.
+     * By default Piwik will track requests for the "current datetime" but this function allows you
+     * to track visits in the past. All times are in UTC.
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth()
+     * @see setTokenAuth()
+     * @param string $dateTime Date with the format 'Y-m-d H:i:s', or a UNIX timestamp. 
+     *               If the datetime is older than one day (default value for tracking_requests_require_authentication_when_custom_timestamp_newer_than), then you must call setTokenAuth() with a valid Admin/Super user token.
+     * @return $this
+     */
+    public function setForceVisitDateTime($dateTime)
+    {
+        $this->forcedDatetime = $dateTime;
+        return $this;
+    }
+
+    /**
+     * Forces Piwik to create a new visit for the tracking request.
+     *
+     * By default, Piwik will create a new visit if the last request by this user was more than 30 minutes ago.
+     * If you call setForceNewVisit() before calling doTrack*, then a new visit will be created for this request.
+     * @return $this
+     */
+    public function setForceNewVisit()
+    {
+        $this->forcedNewVisit = true;
+        return $this;
+    }
+
+    /**
+     * Overrides IP address
+     *
+     * Allowed only for Admin/Super User, must be used along with setTokenAuth()
+     * @see setTokenAuth()
+     * @param string $ip IP string, eg. 130.54.2.1
+     * @return $this
+     */
+    public function setIp($ip)
+    {
+        $this->ip = $ip;
+        return $this;
+    }
+
+    /**
+     * Force the action to be recorded for a specific User. The User ID is a string representing a given user in your system.
+     *
+     * A User ID can be a username, UUID or an email address, or any number or string that uniquely identifies a user or client.
+     *
+     * @param string $userId Any user ID string (eg. email address, ID, username). Must be non empty. Set to false to de-assign a user id previously set.
+     * @return $this
+     * @throws Exception
+     */
+    public function setUserId($userId)
+    {
+        if ($userId === false) {
+            $this->setNewVisitorId();
+            return $this;
+        }
+        if ($userId === '') {
+            throw new Exception("User ID cannot be empty.");
+        }
+        $this->userId = $userId;
+        return $this;
+    }
+
+    /**
+     * Hash function used internally by Piwik to hash a User ID into the Visitor ID.
+     *
+     * Note: matches implementation of Tracker\Request->getUserIdHashed()
+     *
+     * @param $id
+     * @return string
+     */
+    public static function getUserIdHashed($id)
+    {
+        return substr(sha1($id), 0, 16);
+    }
+
+    /**
+     * Forces the requests to be recorded for the specified Visitor ID.
+     * Note: it is recommended to use ->setUserId($userId); instead.
+     *
+     * Rather than letting Piwik attribute the user with a heuristic based on IP and other user fingeprinting attributes,
+     * force the action to be recorded for a particular visitor.
+     *
+     * If you use both setVisitorId and setUserId, setUserId will take precedence.
+     * If not set, the visitor ID will be fetched from the 1st party cookie, or will be set to a random UUID.
+     *
+     * @deprecated We recommend to use  ->setUserId($userId).
+     * @param string $visitorId 16 hexadecimal characters visitor ID, eg. "33c31e01394bdc63"
+     * @return $this
+     * @throws Exception
+     */
+    public function setVisitorId($visitorId)
+    {
+        $hexChars = '01234567890abcdefABCDEF';
+        if (strlen($visitorId) != self::LENGTH_VISITOR_ID
+            || strspn($visitorId, $hexChars) !== strlen($visitorId)
+        ) {
+            throw new Exception(
+                "setVisitorId() expects a "
+                . self::LENGTH_VISITOR_ID
+                . " characters hexadecimal string (containing only the following: "
+                . $hexChars
+                . ")"
+            );
+        }
+        $this->forcedVisitorId = $visitorId;
+        return $this;
+    }
+
+    /**
+     * If the user initiating the request has the Piwik first party cookie,
+     * this function will try and return the ID parsed from this first party cookie (found in $_COOKIE).
+     *
+     * If you call this function from a server, where the call is triggered by a cron or script
+     * not initiated by the actual visitor being tracked, then it will return
+     * the random Visitor ID that was assigned to this visit object.
+     *
+     * This can be used if you wish to record more visits, actions or goals for this visitor ID later on.
+     *
+     * @return string 16 hex chars visitor ID string
+     */
+    public function getVisitorId()
+    {
+        if (!empty($this->userId)) {
+            return $this->getUserIdHashed($this->userId);
+        }
+        if (!empty($this->forcedVisitorId)) {
+            return $this->forcedVisitorId;
+        }
+        if ($this->loadVisitorIdCookie()) {
+            return $this->cookieVisitorId;
+        }
+
+        return $this->randomVisitorId;
+    }
+
+    /**
+     * Returns the currently set user agent.
+     * @return string
+     */
+    public function getUserAgent()
+    {
+        return $this->userAgent;
+    }
+
+    /**
+     * Returns the currently set IP address.
+     * @return string
+     */
+    public function getIp()
+    {
+        return $this->ip;
+    }
+
+    /**
+     * Returns the User ID string, which may have been set via:
+     *     $v->setUserId('username@example.org');
+     *
+     * @return bool
+     */
+    public function getUserId()
+    {
+        return $this->userId;
+    }
+
+    /**
+     * Loads values from the VisitorId Cookie
+     *
+     * @return bool True if cookie exists and is valid, False otherwise
+     */
+    protected function loadVisitorIdCookie()
+    {
+        $idCookie = $this->getCookieMatchingName('id');
+        if ($idCookie === false) {
+            return false;
+        }
+        $parts = explode('.', $idCookie);
+        if (strlen($parts[0]) != self::LENGTH_VISITOR_ID) {
+            return false;
+        }
+        /* $this->cookieVisitorId provides backward compatibility since getVisitorId()
+        didn't change any existing VisitorId value */
+        $this->cookieVisitorId = $parts[0];
+        $this->createTs = $parts[1];
+        $this->visitCount = (int)$parts[2];
+        $this->currentVisitTs = $parts[3];
+        $this->lastVisitTs = $parts[4];
+        if (isset($parts[5])) {
+            $this->ecommerceLastOrderTimestamp = $parts[5];
+        }
+
+        return true;
+    }
+
+    /**
+     * Deletes all first party cookies from the client
+     */
+    public function deleteCookies()
+    {
+        $cookies = array('id', 'ses', 'cvar', 'ref');
+        foreach ($cookies as $cookie) {
+            $this->setCookie($cookie, '', -86400);
+        }
+    }
+
+    /**
+     * Returns the currently assigned Attribution Information stored in a first party cookie.
+     *
+     * This function will only work if the user is initiating the current request, and his cookies
+     * can be read by PHP from the $_COOKIE array.
+     *
+     * @return string JSON Encoded string containing the Referrer information for Goal conversion attribution.
+     *                Will return false if the cookie could not be found
+     * @see Piwik.js getAttributionInfo()
+     */
+    public function getAttributionInfo()
+    {
+        if (!empty($this->attributionInfo)) {
+            return json_encode($this->attributionInfo);
+        }
+
+        return $this->getCookieMatchingName('ref');
+    }
+
+    /**
+     * Some Tracking API functionality requires express authentication, using either the
+     * Super User token_auth, or a user with 'admin' access to the website.
+     *
+     * The following features require access:
+     * - force the visitor IP
+     * - force the date &  time of the tracking requests rather than track for the current datetime
+     *
+     * @param string $token_auth token_auth 32 chars token_auth string
+     * @return $this
+     */
+    public function setTokenAuth($token_auth)
+    {
+        $this->token_auth = $token_auth;
+        return $this;
+    }
+
+    /**
+     * Sets local visitor time
+     *
+     * @param string $time HH:MM:SS format
+     * @return $this
+     */
+    public function setLocalTime($time)
+    {
+        list($hour, $minute, $second) = explode(':', $time);
+        $this->localHour = (int)$hour;
+        $this->localMinute = (int)$minute;
+        $this->localSecond = (int)$second;
+        return $this;
+    }
+
+    /**
+     * Sets user resolution width and height.
+     *
+     * @param int $width
+     * @param int $height
+     * @return $this
+     */
+    public function setResolution($width, $height)
+    {
+        $this->width = $width;
+        $this->height = $height;
+        return $this;
+    }
+
+    /**
+     * Sets if the browser supports cookies
+     * This is reported in "List of plugins" report in Piwik.
+     *
+     * @param bool $bool
+     * @return $this
+     */
+    public function setBrowserHasCookies($bool)
+    {
+        $this->hasCookies = $bool;
+        return $this;
+    }
+
+    /**
+     * Will append a custom string at the end of the Tracking request.
+     * @param string $string
+     * @return $this
+     */
+    public function setDebugStringAppend($string)
+    {
+        $this->DEBUG_APPEND_URL = '&' . $string;
+        return $this;
+    }
+
+    /**
+     * Sets visitor browser supported plugins
+     *
+     * @param bool $flash
+     * @param bool $java
+     * @param bool $director
+     * @param bool $quickTime
+     * @param bool $realPlayer
+     * @param bool $pdf
+     * @param bool $windowsMedia
+     * @param bool $gears
+     * @param bool $silverlight
+     * @return $this
+     */
+    public function setPlugins(
+        $flash = false,
+        $java = false,
+        $director = false,
+        $quickTime = false,
+        $realPlayer = false,
+        $pdf = false,
+        $windowsMedia = false,
+        $gears = false,
+        $silverlight = false
+    )
+    {
+        $this->plugins =
+            '&fla=' . (int)$flash .
+            '&java=' . (int)$java .
+            '&dir=' . (int)$director .
+            '&qt=' . (int)$quickTime .
+            '&realp=' . (int)$realPlayer .
+            '&pdf=' . (int)$pdf .
+            '&wma=' . (int)$windowsMedia .
+            '&gears=' . (int)$gears .
+            '&ag=' . (int)$silverlight;
+        return $this;
+    }
+
+    /**
+     * By default, PiwikTracker will read first party cookies
+     * from the request and write updated cookies in the response (using setrawcookie).
+     * This can be disabled by calling this function.
+     */
+    public function disableCookieSupport()
+    {
+        $this->configCookiesDisabled = true;
+    }
+
+    /**
+     * Returns the maximum number of seconds the tracker will spend waiting for a response
+     * from Piwik. Defaults to 600 seconds.
+     */
+    public function getRequestTimeout()
+    {
+        return $this->requestTimeout;
+    }
+
+    /**
+     * Sets the maximum number of seconds that the tracker will spend waiting for a response
+     * from Piwik.
+     *
+     * @param int $timeout
+     * @return $this
+     * @throws Exception
+     */
+    public function setRequestTimeout($timeout)
+    {
+        if (!is_int($timeout) || $timeout < 0) {
+            throw new Exception("Invalid value supplied for request timeout: $timeout");
+        }
+
+        $this->requestTimeout = $timeout;
+        return $this;
+    }
+
+    /**
+     * If a proxy is needed to look up the address of the Piwik site, set it with this
+     * @param string $proxy IP as string, for example "173.234.92.107"
+     * @param int $proxyPort
+     */
+    public function setProxy($proxy, $proxyPort = 80)
+    {
+        $this->proxy = $proxy;
+        $this->proxyPort = $proxyPort;
+    }
+
+    /**
+     * If the proxy IP and the proxy port have been set, with the setProxy() function
+     * returns a string, like "173.234.92.107:80"
+     */
+    private function getProxy()
+    {
+        if (isset($this->proxy) && isset($this->proxyPort)) {
+            return $this->proxy.":".$this->proxyPort;
+        }
+        return null;
+    }
+
+    /**
+     * Used in tests to output useful error messages.
+     *
+     * @ignore
+     */
+    static public $DEBUG_LAST_REQUESTED_URL = false;
+
+    /**
+     * @ignore
+     */
+    protected function sendRequest($url, $method = 'GET', $data = null, $force = false)
+    {
+        self::$DEBUG_LAST_REQUESTED_URL = $url;
+
+        // if doing a bulk request, store the url
+        if ($this->doBulkRequests && !$force) {
+            $this->storedTrackingActions[]
+                = $url
+                . (!empty($this->userAgent) ? ('&ua=' . urlencode($this->userAgent)) : '')
+                . (!empty($this->acceptLanguage) ? ('&lang=' . urlencode($this->acceptLanguage)) : '');
+
+            // Clear custom variables so they don't get copied over to other users in the bulk request
+            $this->clearCustomVariables();
+            $this->clearCustomTrackingParameters();
+            $this->userAgent = false;
+            $this->acceptLanguage = false;
+
+            return true;
+        }
+
+        $proxy = $this->getProxy();
+
+        if (function_exists('curl_init') && function_exists('curl_exec')) {
+            $options = array(
+                CURLOPT_URL => $url,
+                CURLOPT_USERAGENT => $this->userAgent,
+                CURLOPT_HEADER => true,
+                CURLOPT_TIMEOUT => $this->requestTimeout,
+                CURLOPT_RETURNTRANSFER => true,
+                CURLOPT_HTTPHEADER => array(
+                    'Accept-Language: ' . $this->acceptLanguage,
+                ),
+            );
+
+            if (defined('PATH_TO_CERTIFICATES_FILE')) {
+                $options[CURLOPT_CAINFO] = PATH_TO_CERTIFICATES_FILE;
+            }
+
+            if (isset($proxy)) {
+                $options[CURLOPT_PROXY] = $proxy;
+            }
+
+            switch ($method) {
+                case 'POST':
+                    $options[CURLOPT_POST] = true;
+                    break;
+                default:
+                    break;
+            }
+
+            // only supports JSON data
+            if (!empty($data)) {
+                $options[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json';
+                $options[CURLOPT_HTTPHEADER][] = 'Expect:';
+                $options[CURLOPT_POSTFIELDS] = $data;
+            }
+
+            if (!empty($this->outgoingTrackerCookies)) {
+                $options[CURLOPT_COOKIE] = http_build_query($this->outgoingTrackerCookies);
+                $this->outgoingTrackerCookies = array();
+            }
+            
+            $ch = curl_init();
+            curl_setopt_array($ch, $options);
+            ob_start();
+            $response = @curl_exec($ch);
+            ob_end_clean();
+            $header = '';
+            $content = '';
+            if (!empty($response)) {
+                list($header, $content) = explode("\r\n\r\n", $response, $limitCount = 2);
+            }
+            
+            $this->parseIncomingCookies(explode("\r\n", $header));
+
+        } elseif (function_exists('stream_context_create')) {
+            $stream_options = array(
+                'http' => array(
+                    'method' => $method,
+                    'user_agent' => $this->userAgent,
+                    'header' => "Accept-Language: " . $this->acceptLanguage . "\r\n",
+                    'timeout' => $this->requestTimeout, // PHP 5.2.1
+                ),
+            );
+
+            if (isset($proxy)) {
+                $stream_options['http']['proxy'] = $proxy;
+            }
+
+            // only supports JSON data
+            if (!empty($data)) {
+                $stream_options['http']['header'] .= "Content-Type: application/json \r\n";
+                $stream_options['http']['content'] = $data;
+            }
+
+            if (!empty($this->outgoingTrackerCookies)) {
+                $stream_options['http']['header'] .= 'Cookie: ' . http_build_query($this->outgoingTrackerCookies) . "\r\n";
+                $this->outgoingTrackerCookies = array();
+            }
+            
+            $ctx = stream_context_create($stream_options);
+            $response = file_get_contents($url, 0, $ctx);
+            $content = $response;
+            
+            $this->parseIncomingCookies($http_response_header);
+        }
+
+        return $content;
+    }
+
+    /**
+     * Returns current timestamp, or forced timestamp/datetime if it was set
+     * @return string|int
+     */
+    protected function getTimestamp()
+    {
+        return !empty($this->forcedDatetime)
+            ? strtotime($this->forcedDatetime)
+            : time();
+    }
+
+    /**
+     * Returns the base URL for the piwik server.
+     */
+    protected function getBaseUrl()
+    {
+        if (empty(self::$URL)) {
+            throw new Exception(
+                'You must first set the Piwik Tracker URL by calling
+                 PiwikTracker::$URL = \'http://your-website.org/piwik/\';'
+            );
+        }
+        if (strpos(self::$URL, '/piwik.php') === false
+            && strpos(self::$URL, '/proxy-piwik.php') === false
+        ) {
+            self::$URL .= '/piwik.php';
+        }
+
+        return self::$URL;
+    }
+
+    /**
+     * @ignore
+     */
+    protected function getRequest($idSite)
+    {
+        $this->setFirstPartyCookies();
+
+        $customFields = '';
+        if (!empty($this->customParameters)) {
+            $customFields = '&' . http_build_query($this->customParameters, '', '&');
+        }
+
+        $url = $this->getBaseUrl() .
+            '?idsite=' . $idSite .
+            '&rec=1' .
+            '&apiv=' . self::VERSION .
+            '&r=' . substr(strval(mt_rand()), 2, 6) .
+
+            // XDEBUG_SESSIONS_START and KEY are related to the PHP Debugger, this can be ignored in other languages
+            (!empty($_GET['XDEBUG_SESSION_START']) ?
+                '&XDEBUG_SESSION_START=' . @urlencode($_GET['XDEBUG_SESSION_START']) : '') .
+            (!empty($_GET['KEY']) ? '&KEY=' . @urlencode($_GET['KEY']) : '') .
+
+            // Only allowed for Admin/Super User, token_auth required,
+            (!empty($this->ip) ? '&cip=' . $this->ip : '') .
+            (!empty($this->userId) ? '&uid=' . urlencode($this->userId) : '') .
+            (!empty($this->forcedDatetime) ? '&cdt=' . urlencode($this->forcedDatetime) : '') .
+            (!empty($this->forcedNewVisit) ? '&new_visit=1' : '') .
+            ((!empty($this->token_auth) && !$this->doBulkRequests) ?
+                '&token_auth=' . urlencode($this->token_auth) : '') .
+
+            // Values collected from cookie
+            '&_idts=' . $this->createTs .
+            '&_idvc=' . $this->visitCount .
+            (!empty($this->lastVisitTs) ? '&_viewts=' . $this->lastVisitTs : '') .
+            (!empty($this->ecommerceLastOrderTimestamp) ?
+                '&_ects=' . urlencode($this->ecommerceLastOrderTimestamp) : '') .
+
+            // These parameters are set by the JS, but optional when using API
+            (!empty($this->plugins) ? $this->plugins : '') .
+            (($this->localHour !== false && $this->localMinute !== false && $this->localSecond !== false) ?
+                '&h=' . $this->localHour . '&m=' . $this->localMinute . '&s=' . $this->localSecond : '') .
+            (!empty($this->width) && !empty($this->height) ? '&res=' . $this->width . 'x' . $this->height : '') .
+            (!empty($this->hasCookies) ? '&cookie=' . $this->hasCookies : '') .
+
+            // Various important attributes
+            (!empty($this->customData) ? '&data=' . $this->customData : '') .
+            (!empty($this->visitorCustomVar) ? '&_cvar=' . urlencode(json_encode($this->visitorCustomVar)) : '') .
+            (!empty($this->pageCustomVar) ? '&cvar=' . urlencode(json_encode($this->pageCustomVar)) : '') .
+            (!empty($this->eventCustomVar) ? '&e_cvar=' . urlencode(json_encode($this->eventCustomVar)) : '') .
+            (!empty($this->generationTime) ? '&gt_ms=' . ((int)$this->generationTime) : '') .
+            (!empty($this->forcedVisitorId) ? '&cid=' . $this->forcedVisitorId : '&_id=' . $this->getVisitorId()) .
+
+            // URL parameters
+            '&url=' . urlencode($this->pageUrl) .
+            '&urlref=' . urlencode($this->urlReferrer) .
+            ((!empty($this->pageCharset) && $this->pageCharset != self::DEFAULT_CHARSET_PARAMETER_VALUES) ?
+                '&cs=' . $this->pageCharset : '') .
+
+            // unique pageview id
+            (!empty($this->idPageview) ? '&pv_id=' . urlencode($this->idPageview) : '') .
+
+            // Attribution information, so that Goal conversions are attributed to the right referrer or campaign
+            // Campaign name
+            (!empty($this->attributionInfo[0]) ? '&_rcn=' . urlencode($this->attributionInfo[0]) : '') .
+            // Campaign keyword
+            (!empty($this->attributionInfo[1]) ? '&_rck=' . urlencode($this->attributionInfo[1]) : '') .
+            // Timestamp at which the referrer was set
+            (!empty($this->attributionInfo[2]) ? '&_refts=' . $this->attributionInfo[2] : '') .
+            // Referrer URL
+            (!empty($this->attributionInfo[3]) ? '&_ref=' . urlencode($this->attributionInfo[3]) : '') .
+
+            // custom location info
+            (!empty($this->country) ? '&country=' . urlencode($this->country) : '') .
+            (!empty($this->region) ? '&region=' . urlencode($this->region) : '') .
+            (!empty($this->city) ? '&city=' . urlencode($this->city) : '') .
+            (!empty($this->lat) ? '&lat=' . urlencode($this->lat) : '') .
+            (!empty($this->long) ? '&long=' . urlencode($this->long) : '') .
+            $customFields .
+            (!$this->sendImageResponse ? '&send_image=0' : '') .
+
+            // DEBUG
+            $this->DEBUG_APPEND_URL;
+
+
+        // Reset page level custom variables after this page view
+        $this->pageCustomVar = array();
+        $this->eventCustomVar = array();
+        $this->clearCustomTrackingParameters();
+
+        // force new visit only once, user must call again setForceNewVisit()
+        $this->forcedNewVisit = false;
+
+        return $url;
+    }
+
+
+    /**
+     * Returns a first party cookie which name contains $name
+     *
+     * @param string $name
+     * @return string String value of cookie, or false if not found
+     * @ignore
+     */
+    protected function getCookieMatchingName($name)
+    {
+        if ($this->configCookiesDisabled) {
+            return false;
+        }
+        if (!is_array($_COOKIE)) {
+            return false;
+        }
+        $name = $this->getCookieName($name);
+
+        // Piwik cookie names use dots separators in piwik.js,
+        // but PHP Replaces . with _ http://www.php.net/manual/en/language.variables.predefined.php#72571
+        $name = str_replace('.', '_', $name);
+        foreach ($_COOKIE as $cookieName => $cookieValue) {
+            if (strpos($cookieName, $name) !== false) {
+                return $cookieValue;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * If current URL is "http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"
+     * will return "/dir1/dir2/index.php"
+     *
+     * @return string
+     * @ignore
+     */
+    protected static function getCurrentScriptName()
+    {
+        $url = '';
+        if (!empty($_SERVER['PATH_INFO'])) {
+            $url = $_SERVER['PATH_INFO'];
+        } else {
+            if (!empty($_SERVER['REQUEST_URI'])) {
+                if (($pos = strpos($_SERVER['REQUEST_URI'], '?')) !== false) {
+                    $url = substr($_SERVER['REQUEST_URI'], 0, $pos);
+                } else {
+                    $url = $_SERVER['REQUEST_URI'];
+                }
+            }
+        }
+        if (empty($url)) {
+            $url = $_SERVER['SCRIPT_NAME'];
+        }
+
+        if ($url[0] !== '/') {
+            $url = '/' . $url;
+        }
+
+        return $url;
+    }
+
+    /**
+     * If the current URL is 'http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"
+     * will return 'http'
+     *
+     * @return string 'https' or 'http'
+     * @ignore
+     */
+    protected static function getCurrentScheme()
+    {
+        if (isset($_SERVER['HTTPS'])
+            && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true)
+        ) {
+            return 'https';
+        }
+
+        return 'http';
+    }
+
+    /**
+     * If current URL is "http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"
+     * will return "http://example.org"
+     *
+     * @return string
+     * @ignore
+     */
+    protected static function getCurrentHost()
+    {
+        if (isset($_SERVER['HTTP_HOST'])) {
+            return $_SERVER['HTTP_HOST'];
+        }
+
+        return 'unknown';
+    }
+
+    /**
+     * If current URL is "http://example.org/dir1/dir2/index.php?param1=value1&param2=value2"
+     * will return "?param1=value1&param2=value2"
+     *
+     * @return string
+     * @ignore
+     */
+    protected static function getCurrentQueryString()
+    {
+        $url = '';
+        if (isset($_SERVER['QUERY_STRING'])
+            && !empty($_SERVER['QUERY_STRING'])
+        ) {
+            $url .= '?' . $_SERVER['QUERY_STRING'];
+        }
+
+        return $url;
+    }
+
+    /**
+     * Returns the current full URL (scheme, host, path and query string.
+     *
+     * @return string
+     * @ignore
+     */
+    protected static function getCurrentUrl()
+    {
+        return self::getCurrentScheme() . '://'
+        . self::getCurrentHost()
+        . self::getCurrentScriptName()
+        . self::getCurrentQueryString();
+    }
+
+    /**
+     * Sets the first party cookies as would the piwik.js
+     * All cookies are supported: 'id' and 'ses' and 'ref' and 'cvar' cookies.
+     * @return $this
+     */
+    protected function setFirstPartyCookies()
+    {
+        if ($this->configCookiesDisabled) {
+            return $this;
+        }
+
+        if (empty($this->cookieVisitorId)) {
+            $this->loadVisitorIdCookie();
+        }
+
+        // Set the 'ref' cookie
+        $attributionInfo = $this->getAttributionInfo();
+        if (!empty($attributionInfo)) {
+            $this->setCookie('ref', $attributionInfo, $this->configReferralCookieTimeout);
+        }
+
+        // Set the 'ses' cookie
+        $this->setCookie('ses', '*', $this->configSessionCookieTimeout);
+
+        // Set the 'id' cookie
+        $visitCount = $this->visitCount + 1;
+        $cookieValue = $this->getVisitorId() . '.' . $this->createTs . '.' . $visitCount . '.' . $this->currentTs .
+            '.' . $this->lastVisitTs . '.' . $this->ecommerceLastOrderTimestamp;
+        $this->setCookie('id', $cookieValue, $this->configVisitorCookieTimeout);
+
+        // Set the 'cvar' cookie
+        $this->setCookie('cvar', json_encode($this->visitorCustomVar), $this->configSessionCookieTimeout);
+        return $this;
+    }
+
+    /**
+     * Sets a first party cookie to the client to improve dual JS-PHP tracking.
+     *
+     * This replicates the piwik.js tracker algorithms for consistency and better accuracy.
+     *
+     * @param $cookieName
+     * @param $cookieValue
+     * @param $cookieTTL
+     * @return $this
+     */
+    protected function setCookie($cookieName, $cookieValue, $cookieTTL)
+    {
+        $cookieExpire = $this->currentTs + $cookieTTL;
+        if (!headers_sent()) {
+            setcookie(
+                $this->getCookieName($cookieName),
+                $cookieValue,
+                $cookieExpire,
+                $this->configCookiePath,
+                $this->configCookieDomain
+            );
+        }
+        return $this;
+    }
+
+    /**
+     * @return bool|mixed
+     */
+    protected function getCustomVariablesFromCookie()
+    {
+        $cookie = $this->getCookieMatchingName('cvar');
+        if (!$cookie) {
+            return false;
+        }
+
+        return json_decode($cookie, $assoc = true);
+    }
+
+    /**
+     * Sets a cookie to be sent to the tracking server.
+     *
+     * @param $name
+     * @param $value
+     */
+    public function setOutgoingTrackerCookie($name, $value)
+    {
+        if ($value === null) {
+            unset($this->outgoingTrackerCookies[$name]);
+        }
+        else {
+            $this->outgoingTrackerCookies[$name] = $value;
+        }
+    }
+  
+    /**
+     * Gets a cookie which was set by the tracking server.
+     *
+     * @param $name
+     *
+     * @return bool|string
+     */
+    public function getIncomingTrackerCookie($name)
+    {
+        if (isset($this->incomingTrackerCookies[$name])) {
+            return $this->incomingTrackerCookies[$name];
+        }
+        
+        return false;
+    }
+
+    /**
+     * Reads incoming tracking server cookies.
+     *
+     * @param $headers Array with HTTP response headers as values
+     */
+    protected function parseIncomingCookies($headers)
+    {
+        $this->incomingTrackerCookies = array();
+        
+        if (!empty($headers)) {
+            $headerName = 'set-cookie:';
+            $headerNameLength = strlen($headerName);
+            
+            foreach($headers as $header) {
+                if (strpos(strtolower($header), $headerName) !== 0) {
+                    continue;
+                }
+                $cookies = trim(substr($header, $headerNameLength));
+                $posEnd = strpos($cookies, ';');
+                if ($posEnd !== false) {
+                    $cookies = substr($cookies, 0, $posEnd);
+                }
+                parse_str($cookies, $this->incomingTrackerCookies);
+            }
+        }   
+    }
+}
+
+/**
+ * Helper function to quickly generate the URL to track a page view.
+ *
+ * @param $idSite
+ * @param string $documentTitle
+ * @return string
+ */
+function Piwik_getUrlTrackPageView($idSite, $documentTitle = '')
+{
+    $tracker = new PiwikTracker($idSite);
+
+    return $tracker->getUrlTrackPageView($documentTitle);
+}
+
+/**
+ * Helper function to quickly generate the URL to track a goal.
+ *
+ * @param $idSite
+ * @param $idGoal
+ * @param float $revenue
+ * @return string
+ */
+function Piwik_getUrlTrackGoal($idSite, $idGoal, $revenue = 0.0)
+{
+    $tracker = new PiwikTracker($idSite);
+
+    return $tracker->getUrlTrackGoal($idGoal, $revenue);
+}
diff --git a/library/matomo-php-tracker/README.md b/library/matomo-php-tracker/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e8447f0853f9c575ddf950bdf89c32eeaa14e52d
--- /dev/null
+++ b/library/matomo-php-tracker/README.md
@@ -0,0 +1,16 @@
+# PHP Client for Piwik Analytics Tracking API
+
+The PHP Tracker Client provides all features of the [Piwik Javascript Tracker](http://developer.piwik.org/api-reference/tracking-javascript), 
+such as Ecommerce Tracking, Custom Variable, Event tracking and more. 
+
+## Documentation and examples 
+Check out our [Piwik-PHP-Tracker developer documentation](http://developer.piwik.org/api-reference/PHP-Piwik-Tracker) and 
+[Piwik Tracking API guide](http://piwik.org/docs/tracking-api/).
+
+## Requirements:
+* json extension (json_decode, json_encode)
+* CURL or STREAM extensions (to issue the HTTP request to Piwik)
+
+## License
+
+Released under the [BSD License](http://www.opensource.org/licenses/bsd-license.php)
\ No newline at end of file
diff --git a/library/matomo-php-tracker/composer.json b/library/matomo-php-tracker/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..4b7babd14bf607087d911de9deece79543138f21
--- /dev/null
+++ b/library/matomo-php-tracker/composer.json
@@ -0,0 +1,22 @@
+{
+    "name": "piwik/piwik-php-tracker",
+    "description": "PHP Client for Piwik Analytics Tracking API",
+    "keywords": ["piwik","tracker","analytics"],
+    "homepage": "http://piwik.org",
+    "license": "BSD-2-Clause",
+    "authors": [
+        {
+            "name": "The Piwik Team",
+            "email": "hello@piwik.org",
+            "homepage": "http://piwik.org/the-piwik-team/"
+        }
+    ],
+    "support": {
+        "forum": "http://forum.piwik.org/",
+        "issues": "https://github.com/piwik/piwik-php-tracker/issues",
+        "source": "https://github.com/piwik/piwik-php-tracker"
+    },
+    "autoload": {
+        "classmap": ["."]
+    }
+}
diff --git a/library/piwik-php-tracker b/library/piwik-php-tracker
deleted file mode 160000
index f026613f8137c014030c96a22491ede5f5f1676b..0000000000000000000000000000000000000000
--- a/library/piwik-php-tracker
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f026613f8137c014030c96a22491ede5f5f1676b
diff --git a/public/admin/skins/bokeh74/config.json b/public/admin/skins/bokeh74/config.json
index 4f9b981dfd4b14f5a741b914156bac681516e478..da63d9d5db6b9a0f175e45cf4be6e33c8b395746 100644
--- a/public/admin/skins/bokeh74/config.json
+++ b/public/admin/skins/bokeh74/config.json
@@ -24,6 +24,7 @@
     "translations": "icons/menu/traductions_24.png",
     "failed_searches": "icons/menu/infructueux_24.png",
     "piwik_stats": "icons/menu/piwik_24.png",
+    "matomo_stats": "icons/menu/matomo_24.png",
     "record_views": "icons/menu/stats_visu_24.png",
     "top_record_views": "icons/menu/stats_palmares_24.png",
     "territories": "icons/menu/territoire_24.png",
diff --git a/public/admin/skins/bokeh74/icons/menu/matomo_24.png b/public/admin/skins/bokeh74/icons/menu/matomo_24.png
new file mode 100644
index 0000000000000000000000000000000000000000..354eae7d2cf769a330ddd0b662026b80d184f674
Binary files /dev/null and b/public/admin/skins/bokeh74/icons/menu/matomo_24.png differ
diff --git a/public/admin/skins/bokeh74/icons/menu/matomo_48.png b/public/admin/skins/bokeh74/icons/menu/matomo_48.png
new file mode 100644
index 0000000000000000000000000000000000000000..da69bbd295acd59a363029a8a162360947b1b043
Binary files /dev/null and b/public/admin/skins/bokeh74/icons/menu/matomo_48.png differ
diff --git a/public/admin/skins/retro/config.json b/public/admin/skins/retro/config.json
index 3e4d472326e4e9e09f500a3719f141cfc625b5b4..d521cdc16b76febde15e4b4b1a0a48e3473cd7a9 100644
--- a/public/admin/skins/retro/config.json
+++ b/public/admin/skins/retro/config.json
@@ -24,6 +24,7 @@
     "translations": "icons/menu/traductions_24.png",
     "failed_searches": "icons/menu/infructueux_24.png",
     "piwik_stats": "icons/menu/piwik_24.png",
+    "matomo_stats": "icons/menu/matomo_24.png",
     "record_views": "icons/menu/stats_visu_24.png",
     "top_record_views": "icons/menu/stats_palmares_24.png",
     "territories": "icons/menu/territoire_24.png",
diff --git a/tests/application/modules/admin/controllers/StatControllerTest.php b/tests/application/modules/admin/controllers/StatControllerTest.php
index a6d94762f7d39d6e0db9d97d32a7bbf734606ad3..acd4c5e171b17ab82404458038fab4419c49c4e4 100644
--- a/tests/application/modules/admin/controllers/StatControllerTest.php
+++ b/tests/application/modules/admin/controllers/StatControllerTest.php
@@ -68,7 +68,7 @@ class Admin_StatControllerRecherchesInfructueusesTest
 
 
 
-class Admin_StatControllerPiwikActionTest
+class Admin_StatControllerMatomoActionTest
   extends Admin_AbstractControllerTestCase {
 
   protected $_storm_default_to_volatile = true;
@@ -76,8 +76,8 @@ class Admin_StatControllerPiwikActionTest
   public function setUp() {
     parent::setUp();
 
-    Class_AdminVar::set('PIWIK_AUTH_TOKEN', 'anierstauie-ua/ive');
-    Class_AdminVar::set('JS_STAT', '<!-- Piwik -->
+    Class_AdminVar::set('MATOMO_AUTH_TOKEN', 'anierstauie-ua/ive');
+    Class_AdminVar::set('JS_STAT', '<!-- Matomo -->
 <script type="text/javascript">
 try {
 var url = window.location.href ;
@@ -142,24 +142,24 @@ if ( (url.match ( new RegExp ( "/recherche/" ) )) && ($(\'.resultats_page\').len
 _paq.push([\'trackPageView\']);
 _paq.push([\'enableLinkTracking\']);
 (function() {
-    var u=(("https:" == document.location.protocol) ? "https" : "http") + "://piwik.server.st/";
-    _paq.push([\'setTrackerUrl\', u+\'piwik.php\']);
+    var u=(("https:" == document.location.protocol) ? "https" : "http") + "://matomo.server.st/";
+    _paq.push([\'setTrackerUrl\', u+\'matomo.php\']);
     _paq.push([\'setSiteId\', 9999]);
     var d=document, g=d.createElement(\'script\'), s=d.getElementsByTagName(\'script\')[0]; g.type=\'text/javascript\';
-    g.defer=true; g.async=true; g.src=u+\'piwik.js\'; s.parentNode.insertBefore(g,s);
+    g.defer=true; g.async=true; g.src=u+\'matomo.js\'; s.parentNode.insertBefore(g,s);
 })();
 } catch ( err ) {}
 </script>
-<noscript><p><img src="http://piwik.server.st/piwik.php?idsite=9999" style="border:0;" alt="" /></p></noscript>
-<!-- End Piwik Code -->');
+<noscript><p><img src="http://matomo.server.st/matomo.php?idsite=9999" style="border:0;" alt="" /></p></noscript>
+<!-- End Matomo Code -->');
 
-    $this->dispatch('/admin/stat/piwik', true);
+    $this->dispatch('/admin/stat/matomo', true);
   }
 
 
   /** @test */
   public function iframeSrcShouldNotContainsProtocol() {
-    $this->assertXPath('//iframe[starts-with(@src, "//piwik.server.st")]',
+    $this->assertXPath('//iframe[starts-with(@src, "//matomo.server.st")]',
                        $this->_response->getBody());
   }
 }
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/enssib.fr.html b/tests/application/modules/admin/controllers/enssib.fr.html
index 8a7e6f8d60f740db24bfb9da75dd87b4a0350d44..dff394c34f2bc8c111eb0fb994e5935528da8283 100644
--- a/tests/application/modules/admin/controllers/enssib.fr.html
+++ b/tests/application/modules/admin/controllers/enssib.fr.html
@@ -576,7 +576,7 @@
 </script>
  <script type="text/javascript">
 <!--//--><![CDATA[//><!--
-var _paq = _paq || [];(function(){var u=(("https:" == document.location.protocol) ? "" : "http://www.enssib.fr/piwik/");_paq.push(["setSiteId", "1"]);_paq.push(["setTrackerUrl", u+"piwik.php"]);_paq.push(["setDoNotTrack", 1]);_paq.push(["trackPageView"]);_paq.push(["setIgnoreClasses", ["no-tracking","colorbox"]]);_paq.push(["enableLinkTracking"]);var d=document,g=d.createElement("script"),s=d.getElementsByTagName("script")[0];g.type="text/javascript";g.defer=true;g.async=true;g.src=u+"piwik.js";s.parentNode.insertBefore(g,s);})();
+var _paq = _paq || [];(function(){var u=(("https:" == document.location.protocol) ? "" : "http://www.enssib.fr/matomo/");_paq.push(["setSiteId", "1"]);_paq.push(["setTrackerUrl", u+"matomo.php"]);_paq.push(["setDoNotTrack", 1]);_paq.push(["trackPageView"]);_paq.push(["setIgnoreClasses", ["no-tracking","colorbox"]]);_paq.push(["enableLinkTracking"]);var d=document,g=d.createElement("script"),s=d.getElementsByTagName("script")[0];g.type="text/javascript";g.defer=true;g.async=true;g.src=u+"matomo.js";s.parentNode.insertBefore(g,s);})();
 //--><!]]>
 </script>
  <script type="text/javascript" src="http://www.enssib.fr/sites/www/files/js/js_MpKfe1sTh5JIVGCZ17DsAuT1rqAC38MLLlkjqjQ1X_k.js"></script>
@@ -586,7 +586,7 @@ var _paq = _paq || [];(function(){var u=(("https:" == document.location.protocol
 <script type="text/javascript" src="http://www.enssib.fr/sites/www/files/js/js_ZCgiO0pXCwurcKLOtv0FP6xmULSWKvKgKtn15MtAle4.js"></script>
 <script type="text/javascript">
 <!--//--><![CDATA[//><!--
-jQuery.extend(Drupal.settings, {"basePath":"\/","pathPrefix":"","ajaxPageState":{"theme":"enssib","theme_token":"XhojEjuKoEDBQMH40fF83wbaojQn4mOO7i5VW5B9V8c","jquery_version":"1.10","js":{"0":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/jquery\/1.10\/jquery.min.js":1,"misc\/jquery.once.js":1,"misc\/drupal.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.core.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.widget.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/external\/jquery.cookie.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/misc\/jquery.form.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.mouse.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.draggable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.droppable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.sortable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.button.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.position.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.resizable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.dialog.min.js":1,"misc\/ajax.js":1,"sites\/all\/modules\/contrib\/jquery_update\/js\/jquery_update.js":1,"sites\/all\/modules\/contrib\/admin_menu\/admin_devel\/admin_devel.js":1,"sites\/all\/modules\/contrib\/button_field\/js\/button_field.ajax.js":1,"public:\/\/languages\/fr_Np55hzn09APffb7Qx6JAhdazIXdVfByTCyRDBe-F_GI.js":1,"sites\/all\/modules\/contrib\/views_slideshow\/js\/views_slideshow.js":1,"sites\/all\/modules\/contrib\/views\/js\/base.js":1,"misc\/progress.js":1,"sites\/all\/modules\/contrib\/homebox\/homebox.js":1,"sites\/all\/modules\/contrib\/homebox\/includes\/tipsy\/jquery.tipsy.js":1,"sites\/all\/libraries\/jquery.cycle\/jquery.cycle.all.min.js":1,"sites\/all\/modules\/contrib\/views_slideshow\/contrib\/views_slideshow_cycle\/js\/views_slideshow_cycle.js":1,"sites\/all\/modules\/contrib\/piwik\/piwik.js":1,"sites\/all\/modules\/contrib\/views\/js\/ajax_view.js":1,"sites\/all\/modules\/features\/enssib_emploi\/js\/emploi.js":1,"sites\/all\/modules\/features\/enssib_suivi_candidatures\/js\/webform_validator.js":1,"sites\/all\/themes\/enssib\/js\/variables.js":1,"sites\/all\/themes\/enssib\/js\/behaviours.js":1,"sites\/all\/themes\/enssib\/js\/enssib.js":1,"sites\/all\/themes\/enssib\/js\/jquery.colorbox-min.js":1,"sites\/all\/themes\/enssib\/js\/jquery.flexslider-min.js":1,"sites\/all\/themes\/enssib\/js\/spamspan.js":1},"css":{"modules\/system\/system.base.css":1,"modules\/system\/system.menus.css":1,"modules\/system\/system.messages.css":1,"modules\/system\/system.theme.css":1,"misc\/ui\/jquery.ui.button.css":1,"misc\/ui\/jquery.ui.resizable.css":1,"misc\/ui\/jquery.ui.dialog.css":1,"sites\/all\/modules\/contrib\/simplenews\/simplenews.css":1,"modules\/aggregator\/aggregator.css":1,"modules\/comment\/comment.css":1,"sites\/all\/modules\/contrib\/date\/date_api\/date.css":1,"modules\/field\/theme\/field.css":1,"modules\/node\/node.css":1,"modules\/search\/search.css":1,"modules\/user\/user.css":1,"sites\/all\/modules\/contrib\/workflow\/workflow_admin_ui\/workflow_admin_ui.css":1,"modules\/forum\/forum.css":1,"sites\/all\/modules\/contrib\/views\/css\/views.css":1,"sites\/all\/modules\/contrib\/ctools\/css\/ctools.css":1,"sites\/all\/modules\/contrib\/tagclouds\/tagclouds.css":1,"sites\/all\/modules\/contrib\/views_slideshow\/views_slideshow.css":1,"sites\/all\/modules\/contrib\/homebox\/includes\/tipsy\/tipsy.css":1,"sites\/all\/modules\/contrib\/commerce\/modules\/cart\/theme\/commerce_cart.theme.css":1,"sites\/all\/modules\/contrib\/views_slideshow\/contrib\/views_slideshow_cycle\/views_slideshow_cycle.css":1,"sites\/all\/themes\/enssib\/css\/styles.css":1,"sites\/all\/themes\/enssib\/css\/enssib.css":1,"sites\/all\/themes\/enssib\/css\/print.css":1}},"urlIsAjaxTrusted":{"\/offres-d-emploi":true,"\/":true},"views":{"ajax_path":"\/views\/ajax","ajaxViews":{"views_dom_id:f92469cd31adf7d758711fa42a3eef13":{"view_name":"offres_d_emploi","view_display_id":"block_2","view_args":"","view_path":"home","view_base_path":"offres-d-emploi","view_dom_id":"f92469cd31adf7d758711fa42a3eef13","pager_element":0},"views_dom_id:a63d63bdbb9ae5fb822a145ec4a1f25b":{"view_name":"actualites_news","view_display_id":"block_caroussel","view_args":"","view_path":"home","view_base_path":"actualites","view_dom_id":"a63d63bdbb9ae5fb822a145ec4a1f25b","pager_element":0}}},"viewsSlideshow":{"actualites_news-block_caroussel":{"methods":{"goToSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"nextSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"pause":["viewsSlideshowControls","viewsSlideshowCycle"],"play":["viewsSlideshowControls","viewsSlideshowCycle"],"previousSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"transitionBegin":["viewsSlideshowPager","viewsSlideshowSlideCounter"],"transitionEnd":[]},"paused":0}},"viewsSlideshowPager":{"actualites_news-block_caroussel":{"bottom":{"type":"viewsSlideshowPagerFields"}}},"viewsSlideshowPagerFields":{"actualites_news-block_caroussel":{"bottom":{"activatePauseOnHover":0}}},"viewsSlideshowCycle":{"#views_slideshow_cycle_main_actualites_news-block_caroussel":{"num_divs":12,"id_prefix":"#views_slideshow_cycle_main_","div_prefix":"#views_slideshow_cycle_div_","vss_id":"actualites_news-block_caroussel","effect":"scrollUp","transition_advanced":1,"timeout":5000,"speed":700,"delay":0,"sync":1,"random":0,"pause":1,"pause_on_click":0,"action_advanced":1,"start_paused":0,"remember_slide":0,"remember_slide_days":1,"pause_when_hidden":0,"pause_when_hidden_type":"full","amount_allowed_visible":"","nowrap":0,"fixed_height":1,"items_per_slide":3,"wait_for_image_load":1,"wait_for_image_load_timeout":3000,"cleartype":0,"cleartypenobg":0,"advanced_options":"{}"}},"piwik":{"trackMailto":1}});
+jQuery.extend(Drupal.settings, {"basePath":"\/","pathPrefix":"","ajaxPageState":{"theme":"enssib","theme_token":"XhojEjuKoEDBQMH40fF83wbaojQn4mOO7i5VW5B9V8c","jquery_version":"1.10","js":{"0":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/jquery\/1.10\/jquery.min.js":1,"misc\/jquery.once.js":1,"misc\/drupal.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.core.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.widget.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/external\/jquery.cookie.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/misc\/jquery.form.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.mouse.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.draggable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.droppable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.sortable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.button.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.position.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.resizable.min.js":1,"sites\/all\/modules\/contrib\/jquery_update\/replace\/ui\/ui\/minified\/jquery.ui.dialog.min.js":1,"misc\/ajax.js":1,"sites\/all\/modules\/contrib\/jquery_update\/js\/jquery_update.js":1,"sites\/all\/modules\/contrib\/admin_menu\/admin_devel\/admin_devel.js":1,"sites\/all\/modules\/contrib\/button_field\/js\/button_field.ajax.js":1,"public:\/\/languages\/fr_Np55hzn09APffb7Qx6JAhdazIXdVfByTCyRDBe-F_GI.js":1,"sites\/all\/modules\/contrib\/views_slideshow\/js\/views_slideshow.js":1,"sites\/all\/modules\/contrib\/views\/js\/base.js":1,"misc\/progress.js":1,"sites\/all\/modules\/contrib\/homebox\/homebox.js":1,"sites\/all\/modules\/contrib\/homebox\/includes\/tipsy\/jquery.tipsy.js":1,"sites\/all\/libraries\/jquery.cycle\/jquery.cycle.all.min.js":1,"sites\/all\/modules\/contrib\/views_slideshow\/contrib\/views_slideshow_cycle\/js\/views_slideshow_cycle.js":1,"sites\/all\/modules\/contrib\/matomo\/matomo.js":1,"sites\/all\/modules\/contrib\/views\/js\/ajax_view.js":1,"sites\/all\/modules\/features\/enssib_emploi\/js\/emploi.js":1,"sites\/all\/modules\/features\/enssib_suivi_candidatures\/js\/webform_validator.js":1,"sites\/all\/themes\/enssib\/js\/variables.js":1,"sites\/all\/themes\/enssib\/js\/behaviours.js":1,"sites\/all\/themes\/enssib\/js\/enssib.js":1,"sites\/all\/themes\/enssib\/js\/jquery.colorbox-min.js":1,"sites\/all\/themes\/enssib\/js\/jquery.flexslider-min.js":1,"sites\/all\/themes\/enssib\/js\/spamspan.js":1},"css":{"modules\/system\/system.base.css":1,"modules\/system\/system.menus.css":1,"modules\/system\/system.messages.css":1,"modules\/system\/system.theme.css":1,"misc\/ui\/jquery.ui.button.css":1,"misc\/ui\/jquery.ui.resizable.css":1,"misc\/ui\/jquery.ui.dialog.css":1,"sites\/all\/modules\/contrib\/simplenews\/simplenews.css":1,"modules\/aggregator\/aggregator.css":1,"modules\/comment\/comment.css":1,"sites\/all\/modules\/contrib\/date\/date_api\/date.css":1,"modules\/field\/theme\/field.css":1,"modules\/node\/node.css":1,"modules\/search\/search.css":1,"modules\/user\/user.css":1,"sites\/all\/modules\/contrib\/workflow\/workflow_admin_ui\/workflow_admin_ui.css":1,"modules\/forum\/forum.css":1,"sites\/all\/modules\/contrib\/views\/css\/views.css":1,"sites\/all\/modules\/contrib\/ctools\/css\/ctools.css":1,"sites\/all\/modules\/contrib\/tagclouds\/tagclouds.css":1,"sites\/all\/modules\/contrib\/views_slideshow\/views_slideshow.css":1,"sites\/all\/modules\/contrib\/homebox\/includes\/tipsy\/tipsy.css":1,"sites\/all\/modules\/contrib\/commerce\/modules\/cart\/theme\/commerce_cart.theme.css":1,"sites\/all\/modules\/contrib\/views_slideshow\/contrib\/views_slideshow_cycle\/views_slideshow_cycle.css":1,"sites\/all\/themes\/enssib\/css\/styles.css":1,"sites\/all\/themes\/enssib\/css\/enssib.css":1,"sites\/all\/themes\/enssib\/css\/print.css":1}},"urlIsAjaxTrusted":{"\/offres-d-emploi":true,"\/":true},"views":{"ajax_path":"\/views\/ajax","ajaxViews":{"views_dom_id:f92469cd31adf7d758711fa42a3eef13":{"view_name":"offres_d_emploi","view_display_id":"block_2","view_args":"","view_path":"home","view_base_path":"offres-d-emploi","view_dom_id":"f92469cd31adf7d758711fa42a3eef13","pager_element":0},"views_dom_id:a63d63bdbb9ae5fb822a145ec4a1f25b":{"view_name":"actualites_news","view_display_id":"block_caroussel","view_args":"","view_path":"home","view_base_path":"actualites","view_dom_id":"a63d63bdbb9ae5fb822a145ec4a1f25b","pager_element":0}}},"viewsSlideshow":{"actualites_news-block_caroussel":{"methods":{"goToSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"nextSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"pause":["viewsSlideshowControls","viewsSlideshowCycle"],"play":["viewsSlideshowControls","viewsSlideshowCycle"],"previousSlide":["viewsSlideshowPager","viewsSlideshowSlideCounter","viewsSlideshowCycle"],"transitionBegin":["viewsSlideshowPager","viewsSlideshowSlideCounter"],"transitionEnd":[]},"paused":0}},"viewsSlideshowPager":{"actualites_news-block_caroussel":{"bottom":{"type":"viewsSlideshowPagerFields"}}},"viewsSlideshowPagerFields":{"actualites_news-block_caroussel":{"bottom":{"activatePauseOnHover":0}}},"viewsSlideshowCycle":{"#views_slideshow_cycle_main_actualites_news-block_caroussel":{"num_divs":12,"id_prefix":"#views_slideshow_cycle_main_","div_prefix":"#views_slideshow_cycle_div_","vss_id":"actualites_news-block_caroussel","effect":"scrollUp","transition_advanced":1,"timeout":5000,"speed":700,"delay":0,"sync":1,"random":0,"pause":1,"pause_on_click":0,"action_advanced":1,"start_paused":0,"remember_slide":0,"remember_slide_days":1,"pause_when_hidden":0,"pause_when_hidden_type":"full","amount_allowed_visible":"","nowrap":0,"fixed_height":1,"items_per_slide":3,"wait_for_image_load":1,"wait_for_image_load_timeout":3000,"cleartype":0,"cleartypenobg":0,"advanced_options":"{}"}},"matomo":{"trackMailto":1}});
 //--><!]]>
 </script>
  </body>
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index 61882f565544798dfa32cea51bb4c2d6ac9987f5..d8b624e601f963432407013cac4a7c4c6a6b73fb 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -2216,4 +2216,30 @@ class UpgradeDB_353_Test extends UpgradeDBTestCase {
 
   /** @test */
   public function placeholderFor1dTouchMigrationPatch() {}
+}
+
+
+
+
+class UpgradeDB_354_Test extends UpgradeDBTestCase {
+  public function prepare() {
+    if (!$this->query('select valeur from bib_admin_var where clef="PIWIK_AUTH_TOKEN"'))
+      $this->query('update bib_admin_var set CLEF="PIWIK_AUTH_TOKEN" where CLEF="MATOMO_AUTH_TOKEN" ');
+    $this->query('update bib_admin_var set Valeur=replace(VALEUR,"matomo","piwik")  where CLEF="JS_STAT"');
+
+
+  }
+
+  /** @test */
+  public function piwikBecomeMatomo() {
+    $this->assertNotNull($this->query('select valeur from bib_admin_var where clef = "MATOMO_AUTH_TOKEN"')->fetch()['valeur']);
+
+  }
+
+    /** @test */
+  public function piwikBecomeJsMatomo() {
+    $data =$this->query('select valeur from bib_admin_var where clef = "JS_STAT"')->fetch();
+    $this->assertContains('matomo.biblibre.com',$data['valeur']);
+  }
+
 }
\ No newline at end of file
diff --git a/tests/library/Class/WebService/WebAnalyticsClientTest.php b/tests/library/Class/WebService/WebAnalyticsClientTest.php
index ccfb737a6cdb312cf56c5d1aeb60322f54f8173f..7a51fa26f286a22ed139553fde38e84cc4a9a1bf 100644
--- a/tests/library/Class/WebService/WebAnalyticsClientTest.php
+++ b/tests/library/Class/WebService/WebAnalyticsClientTest.php
@@ -144,24 +144,24 @@ class Class_WebService_WebAnalyticsClientInstanciationWithWrongGoogleAnalyticsAn
 
 
 
-class Class_WebService_WebAnalyticsClientInstanciationWithVarPiwikAndNoDomainNameTest extends Storm_Test_ModelTestCase {
+class Class_WebService_WebAnalyticsClientInstanciationWithVarMatomoAndNoDomainNameTest extends Storm_Test_ModelTestCase {
   public function setUp() {
     parent::setUp();
 
     Class_AdminVar::newInstanceWithId('JS_STAT', ['valeur' => "<script type=\"text/javascript\">
   var _paq = _paq || [];
-  _paq.push([\"setDomains\", [\"*.sandbox.pergame.net/piwik/piwik.php\"]]);
+  _paq.push([\"setDomains\", [\"*.sandbox.pergame.net/matomo/matomo.php\"]]);
   _paq.push(['trackPageView']);
   _paq.push(['enableLinkTracking']);
   (function() {
-    var u=\"//sandbox.pergame.net/piwik/\";
-    _paq.push(['setTrackerUrl', u+'piwik.php']);
+    var u=\"//sandbox.pergame.net/matomo/\";
+    _paq.push(['setTrackerUrl', u+'matomo.php']);
     _paq.push(['setSiteId', 8]);
     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);
+    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
    })();
 </script>
-<noscript><p><img src=\"//sandbox.pergame.net/piwik/piwik.php?idsite=1\" style=\"border:0;\" alt=\"\" /></p></noscript>"]);
+<noscript><p><img src=\"//sandbox.pergame.net/matomo/matomo.php?idsite=1\" style=\"border:0;\" alt=\"\" /></p></noscript>"]);
 
       $this->_web_analytics_client = new Class_WebService_Analytics_Client();
   }
@@ -174,8 +174,8 @@ class Class_WebService_WebAnalyticsClientInstanciationWithVarPiwikAndNoDomainNam
 
 
   /** @test */
-  public function trackerUrlShouldBeSandboxPiwik() {
-    $this->assertEquals('//sandbox.pergame.net/piwik/piwik.php',
+  public function trackerUrlShouldBeSandboxMatomo() {
+    $this->assertEquals('//sandbox.pergame.net/matomo/matomo.php',
                         $this->_web_analytics_client->getTrackerUrl());
   }
 }
diff --git a/tests/scenarios/piwik/PiwikTest.php b/tests/scenarios/matomo/MatomoTest.php
similarity index 76%
rename from tests/scenarios/piwik/PiwikTest.php
rename to tests/scenarios/matomo/MatomoTest.php
index 358bdbff8c8b9e19b0b3c1840e2a338692a5b97f..c0ea0bd8d8e0d630dcf999bbb0be987f94ba34d3 100644
--- a/tests/scenarios/piwik/PiwikTest.php
+++ b/tests/scenarios/matomo/MatomoTest.php
@@ -18,11 +18,11 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-class PiwikFixtures {
+class MatomoFixtures {
 	use Storm_Test_THelpers;
 
 
-  public function enablePiwik() {
+  public function enableMatomo() {
     $this->authToken();
     $this->jsStat();
   }
@@ -30,7 +30,7 @@ class PiwikFixtures {
 
   public function authToken() {
     $this->fixture('Class_AdminVar',
-                   ['id' => 'PIWIK_AUTH_TOKEN',
+                   ['id' => 'MATOMO_AUTH_TOKEN',
                     'valeur' => '789456123456789']);
   }
 
@@ -40,25 +40,25 @@ class PiwikFixtures {
                    ['id' => 'JS_STAT',
                     'valeur' => "<script type=\"text/javascript\">
   var _paq = _paq || [];
-  _paq.push([\"setDomains\", [\"*.sandbox.pergame.net/piwik/piwik.php\"]]);
+  _paq.push([\"setDomains\", [\"*.sandbox.pergame.net/matomo/matomo.php\"]]);
   _paq.push(['trackPageView']);
   _paq.push(['enableLinkTracking']);
   (function() {
-    var u=\"//sandbox.pergame.net/piwik/\";
-    _paq.push(['setTrackerUrl', u+'piwik.php']);
+    var u=\"//sandbox.pergame.net/matomo/\";
+    _paq.push(['setTrackerUrl', u+'matomo.php']);
     _paq.push(['setSiteId', '8']);
     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);
+    g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
    })();
 </script>
-<noscript><p><img src=\"//sandbox.pergame.net/piwik/piwik.php?idsite=1\" style=\"border:0;\" alt=\"\" /></p></noscript>"]);
+<noscript><p><img src=\"//sandbox.pergame.net/matomo/matomo.php?idsite=1\" style=\"border:0;\" alt=\"\" /></p></noscript>"]);
   }
 
 
   public function customJsStat() {
     $this->fixture('Class_AdminVar',
                    ['id' => 'JS_STAT',
-                   'valeur' => "<!-- Piwik -->
+                   'valeur' => "<!-- Matomo -->
 <script type=\"text/javascript\">
 try {
 var url = window.location.href ;
@@ -123,26 +123,26 @@ if ( (url.match ( new RegExp ( \"/recherche/\" ) )) && ($('.resultats_page').len
 _paq.push(['trackPageView']);
 _paq.push(['enableLinkTracking']);
 (function() {
-    var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://piwik.mabib.fr/\";
-                    _paq.push(['setTrackerUrl', u+'piwik.php']);
+    var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://matomo.mabib.fr/\";
+                    _paq.push(['setTrackerUrl', u+'matomo.php']);
                     _paq.push(['setSiteId', 13]);
                     var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
-                    g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
+                    g.defer=true; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
                     })();
   } catch ( err ) {}
 </script>
-<noscript><p><img src=\"http://piwik.mabib.fr/piwik.php?idsite=13\" style=\"border:0;\" alt=\"\" /></p></noscript>
-<!-- End Piwik Code -->"]);
+<noscript><p><img src=\"http://matomo.mabib.fr/matomo.php?idsite=13\" style=\"border:0;\" alt=\"\" /></p></noscript>
+<!-- End Matomo Code -->"]);
   }
 }
 
 
 
-class PiwikJsStatConfigurationParsingTest extends ModelTestCase {
+class MatomoJsStatConfigurationParsingTest extends ModelTestCase {
   public function setUp() {
     parent::setUp();
 
-    (new PiwikFixtures())->jsStat();
+    (new MatomoFixtures())->jsStat();
     $this->_web_analytics_client = new Class_WebService_Analytics_Client();
   }
 
@@ -154,8 +154,8 @@ class PiwikJsStatConfigurationParsingTest extends ModelTestCase {
 
 
   /** @test */
-  public function trackerUrlShouldBeSandboxPiwik() {
-    $this->assertEquals('//sandbox.pergame.net/piwik/piwik.php',
+  public function trackerUrlShouldBeSandboxMatomo() {
+    $this->assertEquals('//sandbox.pergame.net/matomo/matomo.php',
                         $this->_web_analytics_client->getTrackerUrl());
   }
 }
@@ -163,11 +163,11 @@ class PiwikJsStatConfigurationParsingTest extends ModelTestCase {
 
 
 
-class PiwikAlternateJsStatConfigurationParsingTest extends ModelTestCase {
+class MatomoAlternateJsStatConfigurationParsingTest extends ModelTestCase {
   public function setUp() {
     parent::setUp();
 
-    (new PiwikFixtures())->customJsStat();
+    (new MatomoFixtures())->customJsStat();
     $this->_web_analytics_client = new Class_WebService_Analytics_Client();
   }
 
@@ -179,8 +179,8 @@ class PiwikAlternateJsStatConfigurationParsingTest extends ModelTestCase {
 
 
   /** @test */
-  public function trackerUrlShouldBeMaBibPiwik() {
-    $this->assertEquals('//piwik.mabib.fr/piwik.php',
+  public function trackerUrlShouldBeMaBibMatomo() {
+    $this->assertEquals('//matomo.mabib.fr/matomo.php',
                         $this->_web_analytics_client->getTrackerUrl());
   }
 }
@@ -188,7 +188,7 @@ class PiwikAlternateJsStatConfigurationParsingTest extends ModelTestCase {
 
 
 
-abstract class PiwikLeftMenuTestCase extends ViewHelperTestCase {
+abstract class MatomoLeftMenuTestCase extends ViewHelperTestCase {
   protected
     $_storm_default_to_volatile = true,
     $html;
@@ -215,7 +215,7 @@ abstract class PiwikLeftMenuTestCase extends ViewHelperTestCase {
 
 
 
-class PiwikAdminLeftMenuWithOutPiwikTokenTest extends PiwikLeftMenuTestCase {
+class MatomoAdminLeftMenuWithOutMatomoTokenTest extends MatomoLeftMenuTestCase {
 
   public function setUp() {
     parent::setUp();
@@ -224,43 +224,43 @@ class PiwikAdminLeftMenuWithOutPiwikTokenTest extends PiwikLeftMenuTestCase {
 
 
   /** @test */
-  public function piwikStatsLinkShouldNotBePresent() {
-    $this->assertNotXPath($this->html, '//a[contains(@href, "admin/stat/piwik")]');
+  public function matomoStatsLinkShouldNotBePresent() {
+    $this->assertNotXPath($this->html, '//a[contains(@href, "admin/stat/matomo")]');
   }
 }
 
 
 
-class PiwikAdminLeftMenuWithPiwikTokenTest extends PiwikLeftMenuTestCase {
+class MatomoAdminLeftMenuWithMatomoTokenTest extends MatomoLeftMenuTestCase {
   public function setUp() {
     parent::setUp();
 
-    (new PiwikFixtures())->enablePiwik();
+    (new MatomoFixtures())->enableMatomo();
     $this->html = $this->helper->Admin_ContentNav();
   }
 
 
   /** @test */
-  public function piwikStatsLinkShouldBePresent() {
-    $this->assertXPathContentContains($this->html, '//a[contains(@href, "admin/stat/piwik")]', 'Piwik');
+  public function matomoStatsLinkShouldBePresent() {
+    $this->assertXPathContentContains($this->html, '//a[contains(@href, "admin/stat/matomo")]', 'Matomo');
   }
 
 
   /** @test */
-  public function piwikIcoShouldBePresent() {
-    $this->assertXPath($this->html, '//img[contains(@src, "/icons/menu/piwik_24.png")]');
+  public function matomoIcoShouldBePresent() {
+    $this->assertXPath($this->html, '//img[contains(@src, "/icons/menu/matomo_24.png")]');
   }
 }
 
 
 
-class PiwikStatControllerPiwikActionTest extends Admin_AbstractControllerTestCase {
+class MatomoStatControllerMatomoActionTest extends Admin_AbstractControllerTestCase {
   public function setUp() {
     parent::setUp();
 
-    (new PiwikFixtures())->enablePiwik();
+    (new MatomoFixtures())->enableMatomo();
 
-    $this->dispatch('/admin/stat/piwik', true);
+    $this->dispatch('/admin/stat/matomo', true);
   }
 
 
@@ -272,7 +272,7 @@ class PiwikStatControllerPiwikActionTest extends Admin_AbstractControllerTestCas
 
   /** @test */
   public function pageShouldContainsDashboardFrame() {
-    $this->assertXPath('//iframe[@src="//sandbox.pergame.net/piwik/index.php?module=Widgetize&action=iframe&moduleToWidgetize=Dashboard&actionToWidgetize=index&period=week&date=today&idSite=8&token_auth=789456123456789"]', $this->_response->getBody());
+    $this->assertXPath('//iframe[@src="//sandbox.pergame.net/matomo/index.php?module=Widgetize&action=iframe&moduleToWidgetize=Dashboard&actionToWidgetize=index&period=week&date=today&idSite=8&token_auth=789456123456789"]', $this->_response->getBody());
   }
 }
 
@@ -281,14 +281,14 @@ class PiwikStatControllerPiwikActionTest extends Admin_AbstractControllerTestCas
 /**
  * @see http://forge.afi-sa.fr/issues/52810
  */
-class PiwikStatControllerPiwikActionWithBothPiwikAndGoogleAnalyticsTest
+class MatomoStatControllerMatomoActionWithBothMatomoAndGoogleAnalyticsTest
   extends Admin_AbstractControllerTestCase {
   protected $_storm_default_to_volatile = true;
 
   public function setUp() {
     parent::setUp();
 
-    (new PiwikFixtures())->enablePiwik();
+    (new MatomoFixtures())->enableMatomo();
     $this->fixture('Class_AdminVar',
                    ['id' => 'JS_STAT',
                     'valeur' => '<script type="text/javascript">
@@ -298,16 +298,16 @@ var _paq = _paq || [];
 _paq.push([\'trackPageView\']);
 _paq.push([\'enableLinkTracking\']);
 (function() {
-    var u=(("https:" == document.location.protocol) ? "https" : "http") + "://piwik.myserver.com/";
-    _paq.push([\'setTrackerUrl\', u+\'piwik.php\']);
+    var u=(("https:" == document.location.protocol) ? "https" : "http") + "://matomo.myserver.com/";
+    _paq.push([\'setTrackerUrl\', u+\'matomo.php\']);
     _paq.push([\'setSiteId\', 9999]);
     var d=document, g=d.createElement(\'script\'), s=d.getElementsByTagName(\'script\')[0]; g.type=\'text/javascript\';
-    g.defer=true; g.async=true; g.src=u+\'piwik.js\'; s.parentNode.insertBefore(g,s);
+    g.defer=true; g.async=true; g.src=u+\'matomo.js\'; s.parentNode.insertBefore(g,s);
 })();
 } catch ( err ) {}
 </script>
-<noscript><p><img src="http://piwik.myserver.com/piwik.php?idsite=9999" style="border:0;" alt="" /></p></noscript>
-<!-- End Piwik Code -->
+<noscript><p><img src="http://matomo.myserver.com/matomo.php?idsite=9999" style="border:0;" alt="" /></p></noscript>
+<!-- End Matomo Code -->
 <script>
   (function(i,s,o,g,r,a,m){i[\'GoogleAnalyticsObject\']=r;i[r]=i[r]||function(){
   (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
@@ -320,7 +320,7 @@ _paq.push([\'enableLinkTracking\']);
 </script>']);
 
 
-    $this->dispatch('/admin/stat/piwik', true);
+    $this->dispatch('/admin/stat/matomo', true);
   }