Guides

Installing Tracking code

Using Tag Manager’s snippet is the recommended and also the easiest way of installing tracking code on your website. When Tag Manager is added to the site, it automatically starts tracking actions using “Piwik PRO Analytics template”.

If you do not have Tag Manager on your website yet, follow Install a container article to install it. In short, you will need to:

  1. Sign in to your PPAS with your admin or Super User account.
  2. Click on the menu button on the top left.
  3. Click on the “Websites” position.
  4. Choose the website for which you want to implement a tracking code.
  5. Select the “Installation” tab.
  6. The Tag Manager’s snippet for your website is displayed under the “Website code for asynchronous tags” or “Website code for synchronous tags”.

In case you do not want to install Tag Manager on your website, you can install tracking code via JavaScript Tracking Snippet. Guide how to do it is available here: Installing tracking code via code snippet.

Page views

Page view is the most basic type of the tracked event. It represents a single page viewing action. By default it’s triggered only once as soon as the HTML content is loaded to the browser with the trackPageView function.

_paq.push(["trackPageView"]);

Note

It’s not required for the session to start with the page view or even involve them in any other way.

Note

We recommend to trigger this function more than once for Singe Page Applications (SPA). That way you’ll create additional “virtual” page view as the visitor travels across your app.

User ID

User ID is an additional parameter that allows you to aggregate data. When set you will be able to search through sessions by this parameter, filter reports through it or create Multi attribution reports using User ID. You can learn more about User ID here. To set up User ID with your JavaScript Tracking snippet follow this guide.

To set up User ID parameter add a call to setUserId to your tracking code:

_paq.push(["setUserId", "user-name@example.com"]);

Note

  1. Invoking setUserId won’t send any tracking request. To add User ID to tracked data, you have to call setUserId before trackPageView. It does not have to be the first one. Another way is to send ping request with ping, after setting the User ID.
  2. User ID can’t be longer than 1024 bytes. It will be 1024 characters if you use only ASCII characters, but Unicode characters may require more bytes per character, so you should make sure that Unicode identifier cut down to 1024 bytes is still unique.
  3. User ID should be a unique value for each user. Otherwise metrics for different users might be merged in the reports.
  4. Usually a User ID value is an user email, because this is the identifier that users use to log in to a website and it fulfils above requirements.

It is a good practice to remove value of User ID, when the user logs out. Otherwise User ID value might affect session of other users, if they share the same device. To remove User ID value call resetUserId.

_paq.push(["resetUserId"]);

Full abstract example, might look like this:

var user = getUserData();
if (user.isLogged) {
  _paq.push(["setUserId", user.login]);
} else {
  _paq.push(["resetUserId"]);
}

Warning

Do not clear User ID by setting it to some seemingly empty value, like _paq.push(["setUserId", " "]); or _paq.push(["setUserId", ""]);. This way some value might be still send to Collecting & Processing Pipeline. What seems to be an empty value to a human, might not be to a machine. Only using resetUserId will properly clear the User ID value.

Note

Use of resetUserId is necessary only when clicking on log out button does not result in a page reload. For example, when your page is a Single Page Application, or user logout is initiated by a widget and the widget does not cause the webpage to reload, then you have to call resetUserId. Otherwise, when page reloads on logout, then a call to resetUserId is not a necessity, but sill, a good practice.

Note

Set up a user ID article shows an easy way to get User ID without modifying the source code of your website.

Custom Events

Custom events enable tracking visitor actions that are not predefined in the existing JavaScript Tracking Client API, allowing web analysts to accurately measure and analyze any domain. Many integrations, including those offered by Tag Manager, use custom events for tracking actions detectable only on client-side, e.g. scrolling a page, interacting with a video player, filling forms, etc.

A custom event consists of the following properties:

  • category - Describes the category of an event, e.g. video, form, scroll
  • action - Describes what action happened on a website, e.g. video-play, video-pause, form-focus, scroll-progress
  • name (optional) - Usually contains the name of an action target, e.g. the name of a video, label of a form field, name of the scrolled article
  • value (optional) - Additional numeric value carried with an event, e.g. number of seconds a video has been watched for, how far (in percentages) an article has been scrolled

Warning

Consider designing categories and actions upfront and documenting them at start and as they change. Follow one naming convention, e.g. snake_case, kebab-case, camelCase. This will minimize the risk of making mistakes and having to debug the tracking implementation.

Tracking a custom event together with a page view is straightforward - simply call trackEvent function after the page view.

_paq.push(["trackPageView"]);
_paq.push(["trackEvent", "assignment", "assignment-submitted", "Math - Trigonometry - assignment 4", 10]);

The snippet above tracks a custom event with category assignment, action assignment-submitted, name Math - Trigonometry - assignment 4 and value 10 (which might indicate the number of pages in a submitted document).

Custom event name and custom event value are optional. You can skip them if they are not meaningful in your use case.

_paq.push(["trackEvent", "category", "action"]); // skip both name and value
_paq.push(["trackEvent", "category", "action", "name"]); // skip only value
_paq.push(["trackEvent", "category", "action", undefined, 10.0]); // skip only name

Often we want to track events triggered by visitor’s actions, sometime after the page has loaded. One way to do that is to add tracking code to event handling attributes of HTML elements, e.g. onclick attribute of button element.

<button onclick="likePost(); _paq.push(['trackEvent', 'social', 'like-post', 'top-10-attractions-in-london'])">Like</button>

Warning

When tracking custom events this way, make sure HTML events trigger both the intended action and tracking code.

Note

Notice the change in string quotation style. Because onclick attribute content is quoted with double quotes, to avoid conflicts, strings in _paq.push have been surrounded with single quotes.

Tracking more sophisticated events might require attaching listeners to the DOM elements in a script and using trackEvent inside, for example:

<script>
    var maxScroll = 0.0;
    window.addEventListener("scroll", function (event) {
        var currentScroll = calculateScrollBetween0And1(event);
        if (currentScroll >= maxScroll + 0.1) {
            _paq.push(["trackEvent", "scroll", "page-scroll", document.title, currentScroll]);
            maxScroll = currentScroll;
        }
    });
</script>

Note

Analytics for advanced analysts is a series of guides explaining how to track many different actions with custom events in Tag Manager. Check it out if you’re looking for some inspiration!

E-commerce

JavaScript API supports 3 types of e-commerce interactions: Category and product views, Cart updates and Orders.

Tracking category and product views

Usually, the first e-commerce-related action a visitor performs on a website is browsing products. setEcommerceView function allows us to track both category views and product views.

To track a category view, use setEcommerceView function before tracking the page view, like this:

// set category to "Smartphones"
_paq.push(["setEcommerceView", undefined, undefined, "Smartphones"]);

// track page view
_paq.push(["trackPageView"]);

The same function can be used for tracking product views. Again, it must be called before tracking a page view. Example:

// set product with...
_paq.push(["setEcommerceView",
    "71253029",              // SKU (stock-keeping unit)
    "SUPER Phone A40 White", // name
    "Smartphones",           // category
    1499.99                  // price
]);

// track page view
_paq.push(["trackPageView"]);

category parameter of the setEcommerceView function accepts not only string values, but also arrays of strings. This is useful for tracking products that belong to more than one category, or tracking pages that list products from multiple categories.

// set product with...
_paq.push(["setEcommerceView",
    "00492710",                    // SKU (stock-keeping unit)
    "SUPER Watch B20 Silver",      // name
    ["New offer", "Smartwatches"], // categories
    700.00                         // price
]);

// track page view
_paq.push(["trackPageView"]);

Tracking cart updates

Another type of e-commerce activity you can track is an update of a shopping cart. With it, we are able to measure how often visitors don’t complete the ordering process and what products stay in abandoned carts.

Tracking a cart update has two steps: registering items from the cart and sending them. The following example uses two functions - addEcommerceItem and trackEcommerceCartUpdate - to achieve exactly that.

// visitor added one chocolate bar to an empty shopping cart

// register chocolate bar with...
_paq.push(["addEcommerceItem",
    "82775027",                 // SKU (stock-keeping unit)
    "MEGA Milk Chocolate 200g", // name
    "Candy",                    // category
    6.00,                       // price
    1                           // quantity
]);

// track cart update with a total value of 6.00
_paq.push(["trackEcommerceCartUpdate", 6.00]);

This code snippet sends a cart update event with a cart containing one item (SKU candy-12837, name MEGA Milk Chocolate 200g, category Candy, price 6.00) and having total value of 6.00.

The list of registered items is stored only in memory. Reloading the page will clear the list and the previously registered items will have to be added again.

// visitor added one mango fruit to a shopping cart with one chocolate bar

// register previously added items
_paq.push(["addEcommerceItem", "82775027", "MEGA Milk Chocolate 200g", "Candy", 6.00, 1]);

// register the new item
_paq.push(["addEcommerceItem", "01809926", "FRUTASTIC Mango", "Fruits & vegetables", 4.00, 1]);

// track cart update with a total value of 10.00
_paq.push(["trackEcommerceCartUpdate", 10.00]);

Note

If you are not sure what items have been registered, use getEcommerceCart function.

_paq.push([function() { console.log(this.getEcommerceItems()); }]);

Because single page applications do not refresh the page when a visitor manipulates the cart, an e-commerce implementation in SPAs must either:

  1. Clear the cart using clearEcommerceCart and register all items from the cart before tracking cart update, e.g.
// visitor added one chocolate bar to an empty shopping cart
_paq.push(["clearEcommerceCart"]);
_paq.push(["addEcommerceItem", "82775027", "MEGA Milk Chocolate 200g", "Candy", 6.00, 1]);
_paq.push(["trackEcommerceCartUpdate", 6.00]);

// visitor added one mango fruit to a shopping cart with one chocolate bar
_paq.push(["clearEcommerceCart"]);
_paq.push(["addEcommerceItem", "82775027", "MEGA Milk Chocolate 200g", "Candy", 6.00, 1]);
_paq.push(["addEcommerceItem", "01809926", "FRUTASTIC Mango", "Fruits & vegetables", 4.00, 1]);
_paq.push(["trackEcommerceCartUpdate", 10.00]);

// visitor removed one chocolate from a shopping cart with one chocolate bar and one mango
_paq.push(["clearEcommerceCart"]);
_paq.push(["addEcommerceItem", "01809926", "FRUTASTIC Mango", "Fruits & vegetables", 4.00, 1]);
_paq.push(["trackEcommerceCartUpdate", 4.00]);
  1. Replicate visitor’s interactions with the cart using functions addEcommerceItem, removeEcommerceItem, clearEcommerceCart.
// visitor added one chocolate bar to an empty shopping cart
_paq.push(["addEcommerceItem", "82775027", "MEGA Milk Chocolate 200g", "Candy", 6.00, 1]);
_paq.push(["trackEcommerceCartUpdate", 6.00]);

// visitor added one mango fruit to a shopping cart with one chocolate bar
_paq.push(["addEcommerceItem", "01809926", "FRUTASTIC Mango", "Fruits & vegetables", 4.00, 1]);
_paq.push(["trackEcommerceCartUpdate", 10.00]);

// visitor removed one chocolate bar from a shopping cart with one chocolate bar and one mango
_paq.push(["removeEcommerceItem", "82775027"]);
_paq.push(["trackEcommerceCartUpdate", 4.00]);

Tracking orders

Perhaps the most important element of an e-commerce implementation is tracking orders. Just like with cart updates, tracking orders has two steps: registering items that have been purchased and tracking the order. Registering items looks exactly the same - we use addEcommerceItem, removeEcommerceItem and clearEcommerceCart. The actual tracking of an order is done with a call to trackEcommerceOrder function.

// register all purchased items

_paq.push(["addEcommerceItem",
    "66251929",               // SKU
    "Red Unicorn Coffee Mug", // name
    "Tableware",              // category
    8.00,                     // price
    1                         // quantity
]);

_paq.push(["addEcommerceItem",
    "08273511",               // SKU
    "SUPER Blue Ink Pen 0.2", // name
    "Office products",        // category
    2.00,                     // price
    2                         // quantity
]);

// track order
_paq.push(["trackEcommerceOrder",
    "online-5289",            // ID
    16.00,                    // grand total (value + tax + discount + shipping)
    10.00,                    // sub total (value + tax + discount)
    1.00,                     // tax
    6.00,                     // shipping
    2.00                      // discount
]);

Warning

trackEcommerceOrder function clears the list with registered e-commerce items.

Content tracking

What is content tracking

Let’s talk about a scenario in which simple page view tracking is not enough. It will just tell you which page was loaded, but it won’t point out how visitors interact with the content on that particular page. Content impression and content interaction tracking feature fills that gap.

Content impression allows you to track what content is visible to the visitor. On the bigger pages it may tell what particular parts/blocks of it the visitor has reached. When they keep scrolling and new content is presented on the screen it will be tracked automatically. This is useful for ads and banners, but may be also attached to a image carousel or other forms of image galleries.

Now we know what block became visible on the screen, but we would also like to know how the visitor interacted with them. Content interaction tracking completes this feature. After particular block became visible on the viewport JavaScript Tracking Client will automatically record visitor clicks related to it.

JavaScript Tracking Client distinguishes three parts of the content structure: content name, content piece and content target. All together they are called content block.

  • Content name - this is the title describing the content block, tracked data will be visible as an entry in the reports under that name
  • Content piece - gives us the specific piece that was reached on the page (typically an image or other media)
  • Content target - if the content block you want to track is an anchor, content target will contain the url this anchor links to

Enabling automatic content tracking

To enable automatic content tracking, call one of the following tracking functions:

For more details visit the Content tracking section of the JavaScript Tracking Client API documentation.

Note

Automatic content tracking can be enabled in Tag Manager, as shown in Set up content tracking article.

But how does JavaScript Tracking Client know what blocks you would like to track?

There are two ways of marking HTML elements as content blocks: you must either add a special attribute data-track-content or class piwikTrackContent. Example:

1
2
3
4
5
6
<a href="http://example.com/image/abc.png" title="abc" data-track-content>
    first content block
</a>
<a href="http://example.com/image/def.png" title="def" class="piwikTrackContent">
    second content block
</a>

Content properties will be taken from HTML attributes of the content block element or any of its descendants:

  • name comes from data-content-name attribute
  • piece comes from data-content-piece attribute
  • target comes from data-content-target attribute

If any of these attributes is missing, JavaScript Tracking Client will try extracting the value from other sources, using the following logic:

  • piece will be taken from src attribute of an element with piwikContentPiece class or block element
  • target will be taken from href attribute of an element with piwikContentTarget class, block element or piece element
  • name will try to use piece value if present, otherwise it’ll be taken from title attribute of block element, piece element or target element

However, these sources are sometimes unreliable and we recommend providing name, piece and target values in dedicated HTML attributes.

Note

src attribute is read when extracting content piece from common media elements: img, embed, video, audio. Other elements, like object, use more complex extraction logic.

Manual content tracking

If for some reason automatic content tracking does not suit your needs, you may still trigger trackContentImpression and trackContentInteraction JavaScript Tracking Client functions manually.

Example:

1
2
3
4
5
 _paq.push(["trackContentImpression", "Ads", "Partner banner", "http://some-company.tld"]);

 some_dom_node.addEventListener("click", function () {
     _paq.push(["trackContentInteraction", "bannerClicked", "Ads", "Partner banner", "http://some-company.tld"]);
 });

Custom interaction tracking

There is also a third way to track content in more complicated situations. Automatic scenario will track clicks as a visitor interaction, but sometimes other activity may interest you more (e.g. hovering the mouse over a submit button of a form). In such scenarios you would like to enable automatic content impression tracking but trigger interaction tracking manually. Function trackContentInteractionNode lets you do that without the need to provide content name, piece and target in the call (it generates those values in the same way as the automatic method).

Example:

1
2
3
 some_image_node.addEventListener("hover", function () {
     _paq.push(["trackContentInteractionNode", this, "submit-hover"]);
 });

Note

It may be important that your “custom” interaction tracking is not later on doubled by the automatic one. To disable automatic content interaction tracking you should either apply piwikContentIgnoreInteraction CSS class or data-content-ignoreinteraction HTML attribute to the given element.

Examples

Simple HTML content block may look like this:

1
2
3
4
5
6
7
 <a href="http://some-company.tld" title="Our business partner ad" data-track-content>
     Click here to see the website
 </a>

 // content name   = Our business partner ad
 // content piece  = Unknown
 // content target = http://some-company.tld

More advanced HTML content block with all attributes prepared (leaving nothing to chance) may look like this:

1
2
3
4
5
6
7
 <a href="http://some-company.tld" title="Click here" data-track-content data-content-name="Our business partner ad">
     <img src="/images/business-partners/banners/some-company.png" data-content-piece />
 </a>

 // content name   = Our business partner ad
 // content piece  = /images/business-partners/banners/some-company.png
 // content target = http://some-company.tld

Form submission:

1
2
3
4
5
6
7
 <form data-track-content data-content-name="Survey form">
     <input type="submit" data-content-target="http://our-company.tld/form-handler" />
 </form>

 // content name   = Survey form
 // content piece  = Unknown
 // content target = http://our-company.tld/form-handler

Goal tracking

At this point we have tracked many different types of events. We have regular page views, downloads, outlinks, custom events and others. Above them all there’s one more event type we can track: a conversion. And goal tracking is about tracking conversions. If you can point out parts of your website/application more important from your business perspective, you could define those parts as goals. Visiting a specific landing page, submitting a contact form, downloading a PDF file with your product manual - these are popular examples of goal definitions. You can even define a goal based on the custom event you are tracking.

If a goal with automatic tracking is defined in Analytics, every time an events matching the goal’s definition is tracked, we create an additional conversion event and save it along the original event. We call this procedure an “automatic conversion”.

Note

Set up goals article shows how to define a goal triggered by visiting a specific page.

Alternatively, you can trigger a goal manually with the use of trackGoal function

// force conversion of the goal with ID 17
_paq.push(["trackGoal", 17]);

We call this procedure a “manual conversion”. Manual conversion will send a standalone conversion event immediately and is not tied to any other event sent by tracker like automatic conversions.

Anonymous tracking

You can set JavaScript Tracking Client to mark requests to be anonymized. This feature can be useful when you want to use a consent manager on your website and collect full data only from those visitors who gave consent to be tracked.

To set JavaScript Tracking client to mark requests as anonymized call setUserIsAnonymous

_paq.push(["setUserIsAnonymous"]);

From now on all following requests sent by trackPageView or any other function that sends requests to Collecting and Processing Pipeline (CPP), will be marked as a request that should be anonymized. Learn more how Piwik PRO anonymizes visitors data.

Note

If your webpage reloads with each action performed by a visitor, eg. when visitor clicks a link or submits a form, then you have to call setUserIsAnonymous before first trackPageView on each page load. By default, JavaScript Tracking Client does not mark requests as anonymous.

When a visitor gives consent for tracking or you want to enrich anonymous data that is already sent for current visitor, call deanonymizeUser

_paq.push(["deanonymizeUser"]);

This will send special deanonymization request to CPP, that will enrich visitor’s data with all the information that was stripped from previous requests.

To sum up:

  1. You have to set JavaScript Tracking Client to anonymous mode with calling setUserIsAnonymous, at very start of your tracking code for all visitors, that you want to track anonymously (e.g. visitors that did not gave consent for tracking)
  2. Prevent the call of setUserIsAnonymous for all of visitors that should not be anonymized (e.g. visitors that already gave consent)
  3. To enrich already collected anonymous data of a visitor, you have to add a handler that will call deanonymizeUser when you want to denonymize the visitor (e.g. visitor clicked on a button to agree on tracking)