We’ve migrated our documentation to a new site, which means some URLs have changed.
Subscriptions

Installing Piano JavaScript

Overview

When implementing Piano, one of the first steps during setup is pasting a snippet of Piano JavaScript just before the closing body tag of the main document on both your staging and production websites.

We recommend implementing both Sandbox and Production scripts at the start of the implementation, even though we’ll be working in the Sandbox for the majority of the implementation process. The Piano Javascript loads the Composer integration script which includes your specific Piano configuration and also loads Piano’s complete JavaScript library tinypass.min.js (everything from Piano’s client-side browser API client to post a message and iframe support for Piano’s templates).

Note: The tinypass.min.js SDK requires the unsafe-eval directive in the Content Security Policy (CSP) due to the use of eval() in the Experience module for executing dynamic JavaScript code.

The Piano JavaScript you install may vary slightly depending on which Piano products you’re using, your CMS, and whether you’re adding it to a staging or production website. The documentation below will spell out exactly how to implement Piano’s JavaScript for any client-side implementation.

Client-side JavaScript for Clients using Composer

Sandbox vs Production Piano JavaScript

While the basic Piano JavaScript on every page of a given site is the same, the Application ID (AID) within that JavaScript is unique for every Piano application. Because every domain requires its own Piano application (and therefore AID), each website using Piano will have slightly different JavaScript running on it. Note that your Production and Sandbox applications point to different Piano JavaScript libraries and will have unique Application IDs; be careful to include the correct JavaScript for each environment.

Sandbox JavaScript

Here's the standard Piano JavaScript for a Sandbox application (simply swap in your own Sandbox AID and add this to your staging site's header code):

HTML
<script>
    (function(src) {
        var a = document.createElement("script");
        a.type = "text/javascript";
        a.async = true;
        a.src = src;
        var b = document.getElementsByTagName("script")[0];
        b.parentNode.insertBefore(a, b)
    })("//sandbox.piano.io/xbuilder/experience/load?aid=YOUR_SANDBOX_APPLICATION_ID");
</script>

Production JavaScript

Here's the standard Piano JavaScript for a US Production application (simply swap in your own Production AID and add this to your production site's header code):

HTML
<script>
    (function(src) {
        var a = document.createElement("script");
        a.type = "text/javascript";
        a.async = true;
        a.src = src;
        var b = document.getElementsByTagName("script")[0];
        b.parentNode.insertBefore(a, b)
    })("//experience.piano.io/xbuilder/experience/load?aid=YOUR_PRODUCTION_APPLICATION_ID");
</script>

Please use //experience-eu.piano.io/... if your application is located on the EU dashboard (with login at https://dashboard-eu.piano.io/), for the AP dashboard (with login at https://dashboard-ap.piano.io/) use //experience-ap.piano.io/... and for the AU dashboard (with login at https://dashboard-au.piano.io/) use //experience-au.piano.io/... as the base URL.

If you are running Piano's ad block detection script on your site, you should insert the above code at the end of your <body> tag, rather than in the header.

Another method of integrating this code is to directly copy the necessary JavaScript from within your Piano application(s) (with the appropriate AID already populated) by following these steps. Both methods accomplish the same outcome, but the procedure outlined in the linked article does not require you to copy and paste your AID.

Composer JavaScript For Single Page Applications

Piano captures user data and triggers experiences upon every page load. But Single Page Applications (SPAs) with infinite scroll dynamically load content. If you're using Single Page Applications, that means you'll need to manually initiate all Piano JavaScript values and inform Piano every time new content is loaded.

Here is an example of Piano's JavaScript with the fields manually defined (note that the values you need to pass here will vary depending on your implementation and any custom tracking/segmentation you've set up):

HTML
<script>
    tp = window.tp || [];
    // Set Application ID
    tp.push(["setAid", 'TYdG8Mh7eY']);
    // Is application in sandbox?
    tp.push(["setSandbox", false]);
    // Does application use Piano ID?
    tp.push(["setUseTinypassAccounts", false]);
    // Execute when the page is first loaded
    tp.push(["init", function() {
        tp.experience.init();
    }]);
    (function(src) {
        var a = document.createElement("script");
        a.type = "text/javascript";
        a.async = true;
        a.src = src;
        var b = document.getElementsByTagName("script")[0];
        b.parentNode.insertBefore(a, b)
    })("//cdn.piano.io/api/tinypass.min.js");
</script>

The tp.experience.init() function is used solely to initialize the Piano script and should appear only once in the implementation. On the other hand, the tp.experience.execute() function may appear multiple times, as it is used to dynamically update and re-render experiences based on changes in the user state or page context.

If your Piano application is located on the AP, AU, or EU dashboard, you will need to include also the below code defining the endpoint based on the dashboard environment:

AP

tp.push(["setEndpoint", "https://buy-ap.piano.io/api/v3"]);

AU

tp.push(["setEndpoint", "https://buy-au.piano.io/api/v3"]);

EU

tp.push(["setEndpoint", "https://buy-eu.piano.io/api/v3"]);

Sandbox

tp.push(["setEndpoint", "https://sandbox.tinypass.com/api/v3"]);

Then, whenever new content is loaded without a browser refresh, you need to execute the Piano experience you've designed in Composer by using this function:

tp.experience.execute();

How to override the current page's URL is explained here.

If needed, by executing tp.scrollDepth.clearMaxScrolledPosition() the scroll depth can be reset.

Client-side JavaScript for Subscription Management + Billing without Composer

Standard Subscription Management + Billing-Only JavaScript Implementation

If you're using Subscription Management + Billing without Composer, you'll want to use a slightly modified block of JavaScript that doesn't include all of the Composer logic but allows you to manually trigger offers.

Here's the Subscription Management + Billing-only JavaScript for a Production application (simply swap in your own Production AID and add this to your site's header code):

tp = window["tp"] || [];
tp.push(["setAid", "<APPLICATION_ID>"]);
tp.push(["setSandbox", false]);
tp.push(["setDebug", true ]);
tp.push(["init", function(){
    tp.offer.show({
        offerId: "<OFFER_ID>",
        templateId: "<TEMPLATE_ID>",
        displayMode: "modal"
    });

}]);
(function(src){var a=document.createElement("script");a.type = "text/javascript";a.async=true;a.src=src;var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a, b)})("//cdn.piano.io/api/tinypass.min.js");

You can use a variation of this same code for a Sandbox application; simply use your Sandbox AID and configure setSandbox to true. More information on manually triggering offers with JavaScript can be found here.

Defining a custom cookieDomain and cookiePath

With the help of the below JS functions, you have the ability to define a custom cookie domain and/or path for your Piano integration.

The purpose of this is to have the ability to use different application IDs (AIDs) on your site's subdomains, or even on paths.

tp.push(['setCookieDomain', 'sub1.pub.com']);
tp.push(['setCookiePath', '/premium/sport']);

The type of cookies affected by this setup:

  • __tbc

  • xbc

  • __tac

  • __tae

  • __eea

  • __ut

  • __utp

More information about the purpose and expiration of these cookies is available here.

Types of integrations that are supported by this functionality are as follows:

  • cookieDomain: same-level subdomains (e.g. sub1.pub.com and sub2.pub.com)

  • cookiePath: same-level paths (e.g. /premium/sport/ and /premium/cars/)

Types of integrations that we cannot guarantee this feature to work on smoothly are:

  • cookieDomain: sites with crossing subdomains on different levels (e.g. pub.com and sub1.pub.com)

  • cookiePath: same-level paths, e.g.

    • / and /sport

    • /premium and /premium/sport

If you are an existing Piano client, a transfer to a new custom domain and path will be smooth as once you implement the change, we will check if the provided subdomain or/and path contain a cookie, if there’s no cookie then check we the second-level domain (.publisher.com) and if it contains a cookie then we write it to specified subdomain/path.

This way we don’t log out the user and reset meters after the transfer to your custom domain/path.

Last updated: