Content Security Policy (CSP)

Introduction

Specifying a Content Security Policy (CSP) is a common way to secure web applications. This policy controls which scripts and styles can run on a page. You can implement it by adding a Content-Security-Policy header or using a meta tag.

Content Security Policy nonce setup

It's common practice to allow only scripts and styles from trusted domains or those with a special nonce attribute. The nonce mechanism involves two steps: defining the nonce value in the Content Security Policy and adding the same nonce value as an attribute in the styles and scripts.

Define a nonce in Content Security Policy settings

The nonce mechanism requires an additional definition in the script-src directive of the Content Security Policy:

script-src <your-sources> 'nonce-INSERT_VALID_NONCE_VALUE';

Note: The nonce value should be generated server-side and must be unique for each request. Note that <your-sources> is a placeholder for your permitted sources.

Add the nonce to the container code

As a result, the default container code requires the following modifications to function properly.

Asynchronous snippet: The following changes are required in this container code:

<script type="text/javascript" nonce="INSERT_VALID_NONCE_VALUE">
      (function(window, document, dataLayerName, id) {
      window[dataLayerName]=window[dataLayerName]||[],window[dataLayerName].push({start:(new Date).getTime(),event:"stg.start"});
      var scripts=document.getElementsByTagName('script')[0],tags=document.createElement('script');
      function stgCreateCookie(a,b,c){var d="";if(c){var e=new Date;e.setTime(e.getTime()+24*c*60*60*1e3),d=";expires="+e.toUTCString()}document.cookie=a+"="+b+d+"; path=/"}
      var isStgDebug=(window.location.href.match("stg_debug")||document.cookie.match("stg_debug"))&&!window.location.href.match("stg_disable_debug");
      stgCreateCookie("stg_debug",isStgDebug?1:"",isStgDebug?14:-1);
      var qP=[];dataLayerName!=="dataLayer"&&qP.push("data_layer_name="+dataLayerName),isStgDebug&&qP.push("stg_debug");
      var qPString=qP.length>0?("?"+qP.join("&")):"";
      tags.async=!0,tags.src="https://client.containers.piwik.pro/"+id+".js"+qPString,tags.nonce="INSERT_VALID_NONCE_VALUE",
      scripts.parentNode.insertBefore(tags,scripts);
      !function(a,n,i){a[n]=a[n]||{};for(var c=0;c<i.length;c++)!function(i){a[n][i]=a[n][i]||{},a[n][i].api=a[n][i].api||function(){
      var a=[].slice.call(arguments,0);"string"==typeof a[0]&&window[dataLayerName].push({event:n+"."+i+":"+a[0],parameters:[].slice.call(arguments,1)})}}(i[c])}(window,"ppms",["tm","cm"]);
      })(window, document, 'dataLayer', 'feacd61d-0232-40a1-96c3-7e469f7bfa7f');
  </script>

Note: To make Tag Manager work correctly, replace INSERT_VALID_NONCE_VALUE with the generated nonce value.

Adjusting tags to work with the Content Security Policy

In most cases, no changes are needed to make the tags work. Tag Manager will automatically insert the nonce attribute into all fired tags. The only exception is when your tag adds additional scripts or styles to the page; in such cases, you should manually add the nonce attribute.

Note: Not all third-party tools available as built-in templates are configured to work with Content Security Policy. This includes tools like Google Analytics. In these cases, refer to the documentation for each tool (e.g., https://developers.google.com/web/fundamentals/security/csp).

Tag Manager's debug mode

Note: Starting from version 18.36.0 no adjustments to the Content Security Policy will be required to use Tag Manager's debug mode. The adjustments below apply only to older versions.

To load all necessary assets from the Tag Manager debugger, define sources using the img-src, font-src and style-src directives.

img-src <your-sources> client.containers.piwik.pro;
font-src <your-sources> client.containers.piwik.pro;
style-src <your-sources> client.containers.piwik.pro;

Consent Manager form assets

If Consent Manager is enabled on your website, you'll need to set the connect-src, style-src and img-src directives:

connect-src <your-sources> client.piwik.pro client.containers.piwik.pro;
style-src <your-sources> 'nonce-INSERT_VALID_NONCE_VALUE';

Note: We define the tracking domain as client.piwik.pro for collecting visitor consents and the container domain as client.containers.piwik.pro for fetching consent form assets.

Consent Manager’s data subject request widget

When using a data subject request widget, you need to add a nonce attribute to its <script> tag.

<div id="ppms_cm_data_subject" class="ppms_cm_data_subject_widget__wrapper" data-editor-centralize="true" data-main-container="true" data-root="true">
    <h3 id="ppms_cm_data_subject_header" class="header3">Data requests</h3>
    <p id="ppms_cm_data_subject_paragraph" class="paragraph">
        Please select below the type of data request along with any special requests in the body of the message. (...)
    </p>
    <form id="ppms_cm_data_subject_form" class="ppms_cm_data_subject_form" data-disable-select="true">
        ...
    </form>
    <script nonce="INSERT_VALID_NONCE_VALUE">
        ...
    </script>
</div>

JavaScript tracking client

To load all the necessary assets for the JavaScript tracking client, define the sources for script-src, img-src and connect-src.

script-src <your-sources> https://client.piwik.pro/ppms.js;
img-src <your-sources> https://client.piwik.pro/ppms.php;
connect-src <your-sources> https://client.piwik.pro/ppms.php;

Note: You may need to adjust these paths if you're not using the default settings. For example, the JavaScript library might be loaded as an alternative build that doesn't conflict with the Matomo script: https://client.piwik.pro/ppas.js.

Tracking with a custom domain

If you have a custom tracking domain, define it using the img-src and script-src directives:

img-src <your-sources> your-custom-cpp-domain.com;
script-src <your-sources> your-custom-cpp-domain.com;

Allowing the site inspector extension to work on the site

Our site inspector is a Chrome browser extension that visualizes analytics data like clickmaps, heatmaps and scrollmaps on tracked pages. By default, the JavaScript tracking client adds the necessary configuration for this extension in the page's HTML. However, you can disable this behavior if needed using setSiteInspectorSetup.

Since the extension integrates with the page it runs on, additional CSP rules are required to ensure it functions properly.

connect-src <your-sources+necessary-Piwik-PRO-sources> https://client.piwik.pro/api/;
frame-src <your-sources+necessary-Piwik-PRO-sources> https://client.piwik.pro/site-inspector/;

Note: If you're using a custom domain for tracking, make sure to adjust the domain in the CSP rules accordingly.

Example Content Security Policy definition

The following example Content Security Policy setup assumes:

  • Your website address: client.com
  • Your account name in Piwik PRO: client
  • Your container domain: client.containers.piwik.pro
  • You have a Piwik PRO tag with the default tracking domain: client.piwik.pro
  • Nonce value: nceIOfn39fn3e9h3sd
  • The setup allows the 'self' source which is client.com
Content-Security-Policy: default-src 'self';
                         script-src  'self' client.piwik.pro 'nonce-nceIOfn39fn3e9h3sd';
                         connect-src 'self' client.containers.piwik.pro client.piwik.pro;
                         img-src     'self' client.containers.piwik.pro client.piwik.pro;
                         font-src    'self' client.containers.piwik.pro;
                         style-src   'self' client.containers.piwik.pro 'nonce-nceIOfn39fn3e9h3sd';