Single-page websites and web applications have become a standard over the last years. Getting the tracking of such websites and apps right is crucial to your success as you need to ensure the measured data is meaningful and correct. That’s why we, at InnoCraft, help our clients setting up their web tracking and measurement strategy. Some challenges our clients face are the tracking of single-page websites and web applications. We will cover this challenge in this post with a complete example at the bottom.

Embedding the Tracking Code

First you need to embed your JavaScript tracking code into your single-page website or web application as usual. To do this go to “Administration” in the top right in your Piwik, click on “Tracking Code” and adjust the tracking code to your needs.

Tracking a New Page View

The challenge begins when you need to track a new page view. A single-page app is different from a usual website as there is no regular new page load and Piwik cannot detect automatically when a new page is viewed. This means you need to let Piwik know whenever the URL and the page title changes. You can do this using the methods setCustomUrl and setDocumentTitle like this:

window.addEventListener('hashchange', function() {
        _paq.push(['setCustomUrl', '/' + window.location.hash.substr(1)']);
        _paq.push(['setDocumentTitle', 'My New Title']);

Resetting previously set custom variables

If you have set any Custom Variables in scope “page”, you need to make sure to delete these custom variables again as they would be attributed to the new page view as well otherwise. The following code requires Piwik 3.0.2:

_paq.push(['deleteCustomVariables', 'page']);      

Updating the generation time

Next you need to update the generation time before tracking a new page view. Otherwise, the initial page generation time will be attributed to all of your subsequent pageviews.

If you don’t load new content from the server when the page changes, simply set the value to zero:

_paq.push(['setGenerationTimeMs', 0]);

In case you load new content from the server, we recommend to measure the time it took to load this content (in milliseconds) and set the needed time:

_paq.push(['setGenerationTimeMs', timeItTookToLoadPage]);

Updating the referrer

Depending on whether you want to track the previous page as a referrer for the new page view, you should update the referrer URL by setting it to the previous page URL:

_paq.push(['setReferrerUrl', previousPageUrl]);

Making Piwik Aware of New Content

When you show a new page, your single-page DOM might change as well. For example, you might replace parts of your page with new content that you loaded from your server via Ajax. This means you need to instruct Piwik to scan the DOM for new content. We’ll now go over various content types (Videos & Audio, Forms, Links and Downloads, Content tracking).

Video and Audio tracking

If you use the Media Analytics feature to track your videos and audios, whenever a new page is displayed you need to call the following method:

_paq.push(['MediaAnalytics::scanForMedia', documentOrElement]);

When you don’t pass any parameter, it will scan the entire DOM for new media. Alternatively, you can pass an element to scan only a certain area of your website or app for new media.

Form tracking

If you use the Form Analytics feature to measure the performance of your online forms, whenever a new page is displayed you need to call the following method:

_paq.push(['FormAnalytics::scanForForms', docuemntOrElement]);

Where documentOrElement points either to document to re-scan the entire DOM (the default when no parameter is set) or you can pass an element to restrict the re-scan to a specific area.

Link tracking

Supposing that you use the link tracking feature to measure outlinks and downloads, Piwik needs to re-scan the entire DOM for newly added links whenever your DOM changes. To make sure Piwik will track such links, call this method:


Content tracking

If you use the Content Tracking feature, whenever a new page is displayed and some parts of your DOM changes, you need to call this method :

_paq.push(['trackContentImpressionsWithinNode', documentOrElement]);

Where documentOrElement points either to document or an element similar to the other methods. Piwik will then scan the page for newly added content blocks.

Measuring Single-Page Apps: Complete Example

In this example we show how everything works together assuming you want to track a new page whenever a hash changes:

var currentUrl = location.href;
window.addEventListener('hashchange', function() {
    _paq.push(['setReferrerUrl', currentUrl]);
     currentUrl = '' + window.location.hash.substr(1);
    _paq.push(['setCustomUrl', currentUrl]);
    _paq.push(['setDocumentTitle', 'My New Title']);

    // remove all previously assigned custom variables, requires Piwik 3.0.2
    _paq.push(['deleteCustomVariables', 'page']); 
    _paq.push(['setGenerationTimeMs', 0]);
    // make Piwik aware of newly added content
    var content = document.getElementById('content');
    _paq.push(['MediaAnalytics::scanForMedia', content]);
    _paq.push(['FormAnalytics::scanForForms', content]);
    _paq.push(['trackContentImpressionsWithinNode', content]);


If you have any questions or need help, please get in touch with us. You can find more information about the Piwik JavaScript tracker on the Piwik Developer Zone.


We are the makers of Piwik Analytics, the leading open source analytics platform used on more than 1 million websites and apps. We provide outstanding products and services to help you grow and achieve your business goals using the power of Piwik Analytics. We also love privacy and giving our customers full control over their digital analytics data.

Any questions?

Many answers and more information about Piwik You can find here:

We are social

Follow us: