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

Event data

Event data, e.g., information about when a page view event occurs, is submitted to the Piano platform using one of two supported mechanisms:

  • A HTTP API: A specially crafted HTTP request is submitted to Piano to trigger a statistics update.

  • A JavaScript API: The Piano platform gets automatically notified by the browser when a statistics update should take place.

The JavaScript API makes use of the HTTP API, and is the recommended mechanism for passing in event data. Interacting with the HTTP API directly might be relevant in custom applications and in settings where JavaScript cannot be executed.

For simplicity, the following section discusses traditional page view events. Custom parameters are also supported.

Pageview events are supported only for public host names with default port (or no port specified). If a non-standard port number is included in the URL, those PV events will be discarded.

JavaScript API

The JavaScript snippet to include on a given site's web pages will be automatically generated for you by the Piano Insight application when you register a new site, and might look something like shown below. The details around account and site identifiers will vary, of course.

HTML
<script type="text/javascript">
  var cX = cX || {}; cX.callQueue = cX.callQueue || [];
  cX.callQueue.push(['setSiteId', '1234']);  // <-- Insert the correct site identifier here!
  cX.callQueue.push(['sendPageViewEvent']);
</script>
<script type="text/javascript">
  (function(d,s,e,t){e=d.createElement(s);e.type='text/java'+s;e.async='async';
  e.src='https://cdn.cxense.com/cx.js';
  t=d.getElementsByTagName(s)[0];t.parentNode.insertBefore(e,t);})(document,'script');
</script>

The recommended placement of the JavaScript snippet is at the very top of the page, preferably inside the section.

Note the following:

  • The JavaScript snippet you place on the page is really a shim or thin wrapper around the "real" script which is named cx.js.

  • The cx.js script is loaded asynchronously by the client, hence there is no adverse performance impact perceived by the client when loading the page.

  • The cx.js script is empowering some of the highest traffic web-pages worldwide and we have continuously optimized our approach since 2010.

  • The cx.js script will usually always be served from the browser cache (no network traffic) and periodically an update request is sent but no content is transferred (HTML code 304 “Not Modified”), which keeps the network traffic and impact, especially for mobile browsers, at a minimum.

  • The cx.js script resides on a content delivery network (CDN) in order to ensure low latency delivery globally.

  • The cx.js script sets 1st and 3rd party cookies in order to do anonymous user identity management, to be able to tell the Piano platform not only which page was viewed but by whom.

  • The cx.js script does not work on webpages that include prototype.js v1.6. Upgrade to v1.7 (or later) or even v1.5 (or earlier) to make it work.

  • The cx.js script supports almost all browsers: IE5 and up, all Chrome, Safari and FireFox versions. It also supports embedded browsers in older mobile phones (Symbian, Blackberrty), gaming devices (Xbox, Playstation etc.), Smart TVs, in-stream converters like Opera Mini etc.

Only for clients still using Advertising. Serving ads from Advertising is also technically handled by means of cx.js. This is described here. The simplest, least error-prone and recommended way to use both Piano Insight and Advertising simultaneously is to add both the Piano Insight and Advertising JavaScript snippets independently of each other: The Piano Insight snippet should be added to all pages, and the Advertising snippet should in addition be added to those pages where ads are to be served. This ensures that you get a complete picture of the traffic on your site, and enables profile building to take place also based on pages that don't display Advertising results.

Alternative script placement

The Piano Insight tag should be placed within the section as this is the optimal position. If, for some reason, it is not possible to add the tag in the section, the tag can also be added to the element.

Placing the tag in the element is not an optimal solution and should be avoided unless it is the only way to get the tag onto the page.

Asynchronous calls and synchronous calls

Making asynchronous calls is generally recommended and the default-generated JavaScript tag makes asynchronous calls.

Only use a synchronous approach, if you are aware of all side effects with regard to your page loading!

All functions in the JavaScript API can be invoked asynchronously or synchronously. The two example calls below are functionally equal and only differ on timing.

// Asynchronous example
var cX = cX || {}; cX.callQueue = cX.callQueue || [];
cX.callQueue.push(['setSiteId', '12345']);

// Synchronous example
cX.setSiteId('12345');

Note the following:

  • When making asynchronous calls, cx.js can be loaded at any time, either before or after the call is added to the call queue.

  • When making synchronous calls, cx.js must have been loaded before the call is executed.

AJAX web applications

In AJAX applications the content is typically loaded dynamically and the browser isn't running its normal page load sequence when new pages are loaded. Pages loaded this way can still be tracked with the JavaScript API, as long as initializePage and sendPageViewEvent are invoked for each logical page load. The AJAX application should have a scheme where the currently loaded content is read and set from a hash argument, as shown in the example below.

See here for a live example.

HTML
<!DOCTYPE html>
<html>
<head>
    <title>Sample AJAX application with Cxense Insight tracking</title>

    <!-- This example uses jQuery, but the method can be used with any AJAX library. -->
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
    <script type="text/javascript" src="https://cdn.cxense.com/cx.js"></script>
</head>
<body>

    <!-- Page links. -->
    <div>
        <a href="#page=page1.html">Page1</a> |
        <a href="#page=page2.html">Page2</a> |
        <a href="#page=page3.html">Page3</a>
    </div>

    <!-- This div holds the page content for the individual pages. -->
    <div id="pageContent" style="border: 1px solid black; margin-top: 15px; padding: 5px;">
    </div>

    <script type="text/javascript">

        function loadPage() {
            var hashArgs = cX.parseHashArgs();
            $.ajax({
                url: hashArgs.page,
                success: function(pageContent, textStatus, jqXHR) {
                    document.getElementById('pageContent').innerHTML = pageContent;

                    // Initialize the tracking for this new page
                    cX.initializePage();

                    // Send a pageview event for this new page:
                    cX.setSiteId('0'); // <- Replace with correct site id
                    cX.sendPageViewEvent();
                }
            });
        }

        // Load a new page every time the hash changes
        $(window).on('hashchange', loadPage);


        // Initial page load
        var hashArgs = cX.parseHashArgs();
        if (!hashArgs.page) {
            location.hash = '#page=page1.html';
        } else {
            // onHashChange will not fire in this case, so we need to invoke loadPage() explicitly
            loadPage();
        }

    </script>

</body>
</html>

If you need to report a Content recommendations click at the same time, that can be done with the user of the helper function

  • cX.sendSpaRecsClick(, []);

HTML
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<script type="text/javascript" src="https://cdn.cxense.com/cx.js"></script>
<body xmlns:tmp="javascript:">
    <div id="spaTemplate" class="template">
        <div class="headline">
            <h2>Single Page Instrumentation Example</h2>
        </div>
        <!--%
        var items = data.response.items;
        for (var i = 0; i < items.length; i++) {
          var item = items[i];
          var clickUrl = item.click_url + '?cx_test=spaTest';
          %-->
        <div class="item" onclick="openArticlePage('{{item.url}}','{{clickUrl}}');">
            <!--%
             cX.renderContainedImage({
                 container: { width: 290, height:172},
                 image: {
                     src: item['dominantthumbnail'],
                     dimensions: 'dominantthumbnaildimensions'
                 },
                 tooWideStrategy: 'zoom',
                 tooTallStrategy: 'zoom',
                 tooWideFocusPoint: 0.5,
                 tooTallFocusPoint:0.5,
                 horizontalAlign: 'center',
                 verticalAlign: 'center',
                 scaleFactorMax: 2.0,
                 scaleFactorMin: 0.8
             });
           %-->
            <h3>{{item.title}}</h3>
        </div>
        <!--%
      }
      %-->
    </div>
    <div id="spaTarget"></div>
    <script type="text/javascript">
        cX.setSiteId('1234567890');
        cX.sendPageViewEvent();
        function openArticlePage(loc, clickUrl) {
            // First report the click url before leaving the current page
            cX.sendSpaRecsClick(clickUrl);
            // ..
            //  Do navigational logic loading up new page, history.pushState(..), etc
            // ..
            // Report the analytics event as normal
            cX.initializePage();
            cX.sendPageViewEvent();
        }
        cX.insertWidget({
            widgetId : '70ee1cb56fa19asdasda061ed7fdea6fd',
            templateElementId : 'spaTemplate',
            targetElementId : 'spaTarget'
        } );
    </script>
</body>
</html></pre>
<pre>

Reporting from within mobile applications

Sending events from within mobile applications is done in a few different ways depending on how the mobile application itself is constructed. There are four main approaches:

  1. Mobile web application, i.e., the app runs inside a standard browser on the mobile device. Integration in the mobile web application is then no different from integration with a normal web site: The Piano Insight JavaScript tag can be used out-of-the-box, and user profiles and content profiles are created automatically.

  2. Native app wrapper for mobile web application, i.e., the app is native but is really just a thin wrapper around a browser embedded in the app. As above, all Piano JavaScript tag can be used out-of-the-box, and user and content profiling will happen automatically. Simple integration technologies that build both native iPhone and Android application wrappers are available, e.g., PhoneGap.

  3. Native app wrapper with HTML rendering, i.e., the app is native but the UI is rendered using HTML possibly served from local resources. The Piano JavaScript tag can be used, but there are two things the application developer needs to consider:

    1. The native app does not have a URL for a page. This can be addressed by creating synthetic URLs and passing these to Piano using the location override mechanism.

    2. The Piano crawler cannot access the content of an application page, and thus cannot create a content profile or user profiles. The content must be made available to Piano in some other way, e.g., by serving the content on a webserver (in parallel to the app) and having the synthetic URLs reference this, or by pushing the content to Piano.

  4. Native app with native UI and rendering, i.e., the app is fully native and does not run JavaScript. With this approach the Piano JavaScript tag cannot be used, but the application will have to be instrumented to call the relevant Piano APIs. Also, like above, the content is not accessible to Piano so it must be made available to Piano in some way if it is to be used for building user and content profiles. For the availability of native SDKs for various mobile platforms, please contact Piano support.

The recommendation for application developers is to use one of the first two approaches, as they result in both easier and better Piano Insight integration. In particular, the second approach provides the best of both worlds: The user gets an app in the app stores, icons on the home screen and access to all phone functions, and the application can still be updated in the same way a webpage is using standard well-known web technologies for the UI and layout. Also, it allows for the developer to write the application once and then build it for multiple native platforms, instead of having to build and maintain one separate version for each platform.

Disabling the auto-refresh check

cx.js has a check to prevent reporting of automatic page refreshes. In some cases, for example in AJAX applications where the URL does not change, you might want to disable this protection.

You can do that with the useAutoRefreshCheck parameter to the sendPageViewEvent function to disable this check:

// Asynchronous
cX.callQueue.push(['sendPageViewEvent', { useAutoRefreshCheck: false }]);

// Synchronous
cX.sendPageViewEvent( { useAutoRefreshCheck: false } );

Overriding the reported location URL

The sendPageViewEvent function will automatically report the current URL of the window from which the call is executed, i.e., the value of window.location.href. In certain cases there might be a need to override this default behavior, and that can be done by adding a location parameter to the sendPageViewEvent call, as shown below.

// Asynchronous
cX.callQueue.push(['sendPageViewEvent', { 'location': 'https://www.corp.com/artId123.html' }]);

// Synchronous
cX.sendPageViewEvent({ 'location': 'https://www.corp.com/artId123.html' });

The specified URL must be a syntactically valid URL, or else the event will be dropped.

Warning! Overriding the reported location can make your Piano Insight reports incorrect if the new reported location is not really the same item as the actual location. A good rule of thumb is therefore to only use this functionality if the new reported location is just a different way of accessing the same item as the current location. Another example is if there is a canonical URL that should rather be used than the current non-canonical URL.

To avoid any issues with Piano Insight reports, you can use the method for overriding the current page's URL from the page as described here.

Let's take for example the canonical URL of https://www.interesting.com/example-page.html.

Maintain all traffic to the canonical URL, and incorporate the use of a "channel" parameter e.g.:

cX.callQueue.push(['setCustomParameters', { 'cx_channel': '[platform_name]' }]);

to enable break-outs of the platform-specific traffic data:

  1. Web Page Views: 50 - (optional inclusion of a ‘web’ channel, though as web is often the ‘default’, a lack of a specific channel is usual for this case.)

  2. AMP Page Views: 23 - 'cx_channel': 'amp'

  3. FIA Page Viewss: 10 - 'cx_channel': 'fia'

  4. iOS Page Views: 12 - 'cx_channel': 'ios'

  5. Android Page Views: 5 - 'cx_channel': 'android'

  6. Total Page Views: 100 ("All Channels!")

This way each platform owner can analyze the value of an individual URL as above, whilst the product owner maintains a holistic, unified view of the value the single URL generated.

Further, platform owners can use the same filter (filter: cx_channel=[platform]) to identify only their platform’s traffic. Similarly, the Product owner - responsible for all channels - can include a total view (no filter), or any combination of platform filters to split out each platform if/as required.

filter: cx_channel=[platform1], [platform2], [platform3]

filter: cx_channel != [platform5]

Including all platform values removes web traffic (as it usually has no channel specification), or alternatively you can incorporate a platform value on web traffic as well, then use a 'not web' filter instead.

Overriding the reported referrer URL

The sendPageViewEvent function will automatically report the current referrer URL of the document from which the call is executed, i.e., the value of document.referrer. In certain cases, there might be a need to override this default behavior, and that can be done by adding a referrer parameter to the sendPageViewEvent call, as shown below.

// Asynchronous
cX.callQueue.push(['sendPageViewEvent', { 'referrer': 'https://www.corp.com/artId123.html' }]);

// Synchronous
cX.sendPageViewEvent({ 'referrer': 'https://www.corp.com/artId123.html' });

The specified URL must be a syntactically valid URL, or else the event can be dropped.

Overriding the reported referrer can make your Piano Insight reports incorrect if the newly reported referrer is not really the same item as the actual referrer. A good rule of thumb is therefore to only use this functionality if the new reported referrer is just a different way of accessing the same item as the current referrer. Another example is if there is a canonical URL that should rather be used than the current non-canonical referrer URL. A third example is in AJAX single-page applications where the referrer does not change by itself and has to be overridden to give the correct picture of the navigation.

External user identifiers

As mentioned above, the cx.js script does basic anonymous user identity management, which allows each event to be associated with a user. However, in some use cases, it is beneficial to be able to link a customer-specific way of referencing a user with how Piano references the same user. For example, perhaps your site has a login mechanism and you want to be able to use your own way of referring to users in relevant API methods or want to augment the Piano platform with data you have about such users, or want to be able to track those logged-in users across different devices to build truly cross-device unique user profiles!

The JavaScript API exposes the addExternalId method to allow you to augment the event with information about which user (using whatever identity management scheme you prefer) that generated the event. The external user identifiers you specify are then consolidated on the server side with the user identifier that cx.js uses.

This functionality is also available using a server-side authenticated API: /profile/user/external/link/update

External user identifiers can take many forms, some typical examples include, for e.g.:

  • Application-specific login identifiers (i.e. CRM, eCommerce, newsletter database)

  • Apple identifiers for advertisers (IFA)

  • Facebook identifiers (as a hash thereof)

  • Google identifiers (as a hash thereof)

  • Email address (as a hash thereof)

According to our data-philosophy:

  • None of the information we aggregate should be based on PII (Personal Identifiable Information), thus the application of a hash-function (Wiki link) is recommended.

Name

Type

Required

Description

id

String

Yes

The identifier value to register

type

String

Yes

The customer identifier type as registered with Piano (see Customer Prefix)

An example invocation of addExternalId is shown below.

// Asynchronous
cX.callQueue.push(['addExternalId', { 'id': 'subscriber14', 'type': 'xyz'}]);

// Synchronous
cX.addExternalId({ 'id': 'subscriber14', 'type': 'xyz'});


  • Before you can start using addExternalId, you need to have a Customer Prefix registered with Piano.

  • Calls to addExternalId must be made before the call to sendPageViewEvent.

  • Limitation: The maximum allowed identifier length is 128 characters.

  • Both the user type and identifiers are case sensitive.

  • The valid characters in customer identifiers are digits (0 to 9), characters A to Z, a to z, space and the special characters "=", "@", "+", "-", "_" and ".".


A complete tag might look like this:

(Specifying an external user identifier (complete example))

HTML
<!-- Cxense script begin -->
<script type="text/javascript">
  var cX = cX || {}; cX.callQueue = cX.callQueue || [];
  cX.callQueue.push(['addExternalId', { 'id': 'subscriber14', 'type': 'xyz'}]);
  cX.callQueue.push(['setSiteId', '1234']); // <-- Insert the correct site identifier here!
  cX.callQueue.push(['sendPageViewEvent']);
</script>
<script type="text/javascript">
  (function(d,s,e,t){e=d.createElement(s);e.type='text/java'+s;e.async='async';
  e.src='https://cdn.cxense.com/cx.js';
  t=d.getElementsByTagName(s)[0];t.parentNode.insertBefore(e,t);})(document,'script');
</script>
<!-- Cxense script end -->

Note that specifying external user identifiers does not have to happen on every page view event. E.g., it might just happen on the page the user accesses after having logged in. As long as the linking between the external user identifier and the internal user identifier used by cx.js happens at least once, this is remembered server-side. The linking information is lost, however, if the server-side mapping is cleared (e.g., for capacity reasons users for which no activity has been observed for a very long time might have their mappings purged). The linking operation should happen at least once a month, preferably more often (this ensures that the server-side correctly distinguishes between active an in-active identities.

HTTP API

Warning! Using this API requires explicit consent from Piano. Please contact Piano if you need to use this API.

The cx.js script mentioned above collects various pieces of data, builds up a URL that encodes this information, and sends this back to the Piano platform by making a standard HTTP request to the Piano servers. This HTTP API can also be invoked directly by clients. The URL currently encodes the following parameters:

Parameter

Required

Sample Value

Description

ver

Yes

1

To which version of the API is this requested targeted

typ

Yes

pgv

What type of event is this? The value pgv denotes a page-view event.

sid

Yes

1234567890123

The Piano site identifier.

loc

Yes

https://www.yoursite.com/news/1

The URL of the page. Must be a syntactically valid URL, or else the event will be dropped.

ref

No

https://www.yoursite.com/

The URL of the referring page.

ltm

No

1473837694457

The local time on the client.

tzo

No

-120

The client's timezone.

res

No

1920x1080

The screen resolution. The format is "res=x", e.g. "res=1024x768".

wsz

No

1395x282

The initial browser window size: The format is "wsz=x", e.g. "wsz=544x365".

col

No

24

Device color depth.Typically read from window.screen.colorDepth in a browser.

dpr

No

1

Device pixel ratio (the ratio between physical and virtual pixels). Typically read from window.devicePixelRatio in a browser.

rnd

Yes

it2kwr95mv0uxmh3

A random number, for cache-busting purposes and to uniquely identify a page-view request.

bln

No

en-US

The client's browser language.

cks

No

it2kw3ldnxjc

The Piano site-specific session cookie. Must be at least 16 characters long. Allowed characters: A-Z, a-z, 0-9, "_", "-", "+" and ".".

ckp

Yes

if1211191dpr

The Piano site-specific persistent cookie. Contains a random number that identifies the user. Must be between 16 and 40 characters long. Allowed characters: A-Z, a-z, 0-9, "_", "-", "+" and ".".

glb

No

cx:pbad80kwtao0l1qyfh5vv7q7:2vaqowu49edjp

The global id that uniquely identifies the user in relation to other ids (ckp, etc.)

chs

No

UTF-8

The document's character set.

new

No

0

Indicates that the user on the device and web site is new. Specifically it states that cX.getUserId() created an identifier and stored it in the browser's storage. When using this field through a direct pixel request, it is advised to follow similar semantics: when creating a new identifier and storing the identifier, then the field should equal to 1.

cp_

No


Set a custom parameter "name=value" by adding a URL parameter with a "cp_" prefix and the same name and value as the wanted custom parameter. E.g. if you want to set "premiumPage: true", you add the URL parameter "cp_premiumPage=true". See the documentation for setCustomParameters for more details on setting custom parameters. The recommended practice is to use customer prefix for your parameter names. E.g. your customer prefix is "xyz", then add the URL parameter "cp_xyz-premiumPage=true".

cp_u_

No


Set a user profile parameter "name=value" by adding a URL parameter with a "cp_u_" prefix and the same name and value as the wanted user profile parameter. E.g. if you want to set "sportsFan: true", you add the URL parameter "cp_u_sportsFan=true". See the documentation for setUserProfileParameters for more details on setting custom parameters.

eid0

No


The value of the first optional external user id, used for linking external user ids to Piano users. 64 characters max length.

eit0

No


The type of the first optional external user id, used for linking external user ids to Piano users. 10 characters max length.

eid1

No


The value of the second optional external user id (etc..)

eit1

No


The type of the second optional external user id (etc..)

ptim

No


Position time.

plat

No


Position latitude.

plon

No


Position longitude.

amo

No

1473634205 (for 2016-09-11T22:50:05Z)

If the web page has a tag with a property of 'article:modified_time', the 'content' is parsed and converted into seconds.

con

No*

y,pv,segment

Consent. A comma separated list with the following values: y - Required, set if this event was obtained and may only be processed with the user's consent. pv - Page view tracking, event tracking and browsing habit collection to understand a user’s interests and profile. recs - Personalisation of content recommendations and suggested content based on user interests and browsing habits. segment - Audience segmentation, processing of browsing habits and first party data to include users in specific audience segments. ad - Targeting advertising based on browsing habits and audience segmentation. device - Device data should be recorded and used for profiling. geo - Geolocation lookups with IP address can be done and it can accept geolocation parameters from the page view (plat, plon).

cv

No*

2

Respect the "device" and "geo" flags. cv means "consent version", and specifying "2" specifies you want to use the second version.

altm

No


The script start time for the page before (After-the-fact reporting)

arnd

No


The page view id (rnd) from the prior page (After-the-fact reporting)

aatm

No


The amount of time the user was active on the page (After-the-fact reporting)

axtl

No


The exit link used from the prior page (After-the-fact reporting)

awsz

No


The window size while viewing the prior page (After-the-fact reporting)

amvw

No


The max viewport space for the prior page (After-the-fact reporting)

ascp

No


The scroll depth in pixels for the prior page (After-the-fact reporting)

aaid

No


List of widget IDs that shown the prior page, separated by commas (After-the-fact reporting)

aavp

No


The max view percentage of each widget, aligned with the "aaid" IDs (After-the-fact reporting)

aaps

No


The positions for each widget, aligned with the "aaid" IDs (After-the-fact reporting)

aasz

No


The offset widths and heights for each widget, aligned with "aaid" IDs (After-the-fact reporting)

aavt

No


Times for partial and full views of widgets for each aaid ID (After-the-fact reporting)

Taken together, the parameters ckp and rnd are used to identify a unique page view event.

For parameters above listed as 'Required: No', cx.js will still capture as many as is available.

Don't forget to properly URI encode both the value and the name (if using custom names) of the URL parameters!

The HTTP headers that are received as part of the HTTP request for the URL also carry important information that is used by the Piano platform:

Header

Required

Description

Accept-Language

No

Acceptable languages for response.

Cookie

No

For global tracking purposes within Piano's network of sites, the cookie values gcks and gckp (having similar semantics as cks and ckp listed above) might be set by cx.js.

Host

Yes

The domain name of the server.

Referer

No

The address of the previous web page from which a link to the currently requested page was followed.

User-Agent

Yes

Identifies the device type.

X-Forwarded-For

Yes

The IP address of the end user client, i.e., the IP address of the browser or handset. This header is only required if it's a server making the call. If the call is made from, e.g., a mobile application, it's not strictly required.

GET /Repo/rep.html?ver=1&typ=pgv&sid=1234&loc=http%3A//example.com/app%3Fa%3Db%26c%3Dd&ref=&ckp=user1234567891011&cks=session1234567891011 HTTP/1.0
Host: comcluster.cxense.com
X-Forwarded-For: 173.203.85.136
User-Agent: ExampleBrowser v1.0

The HTML response will always be with the HTTP status code 200 for all requests, even for malformed requests.

Sending requests over HTTPS instead of HTTP is also supported, but then the hostname is scomcluster.cxense.com instead of comcluster.cxense.com.

Only use the HTTPS version when the parent page is also HTTPS.

The response can be HTML, as in the above example, or it can be a GIF pixel image. To use the GIF pixel image type response, just replace rep.html with rep.gif as shown in the example below.

Minimal HTTP GET request with GIF pixel image response:

GET /Repo/rep.gif?ver=1&typ=pgv&sid=1234&loc=http%3A//example.com/app%3Fa%3Db%26c%3Dd&ref=&ckp=user1234567891011&cks=session1234567891011&rnd=0 HTTP/1.0
Host: comcluster.cxense.com
X-Forwarded-For: 173.203.85.136
User-Agent: ExampleBrowser v1.0


Last updated: