# OIL Documentation

## Version: 1.1.2-RELEASE

## Introduction

### About oil.js

The OIL project aims for a stable cross-company solution for the challenges the GDPR and new EU ePrivacy Regulation will pose to our business.

- Data privacy opt-in overlay for all users of services offered by various Axel Springer brands and/or units

- Local opt-in (called "Site Opt-In", SOI) as well as group-based cross-company opt-in (called "Power Opt-In", POI)

- Integration and hosting on Tealium with the option to run it standalone.

The Opt-In Layer (OIL) is an offical Consent Management Provider (CMP) after the IAB Europe "Transparency & Consent Framework".

### Technical Quality Goals

- OIL will be held compatible with the latest official browser releases, going back to the latest version as listed below and tested on broad range of browsers using Browserstack.com:

  - Chrome 14 - Latest

  - IE 9 - Latest

  - Firefox 9 - Latest

  - Safari 6 - Latest

  - Opera 12

  - Apple iOS 5.1 - Latest

  - Android 4.4.4 - Latest

- Continously integrated and delivered

- Modular and maintainable solution

### Features

- Customisable UI and text with audit-proof versioning

- Fully configurable (cookie categories, timeouts, …​)

- Easy AB-Testing with extensive events for each user interaction

- AB-Tested in different brand specific designs with 250k unique users

- Supports IAB Europe Standard and additionally custom calls

- Supports Group-Opt-In

- Works with 99,9% of all browsers (in Germany) & Works with all devices and all resolutions

- Optimised for high performance and low latency (build to be loaded first)

- OpenSource

- Tested in the cloud on all possible devices

- Tealium integration and additional features via Tealium like reporting

- Redirect-Fallback for some older browsers and even for disabled 3rd party cookies in Safari

- High quality code with high test coverage and static code analysis

- Loads with low latency and asynchronously for different parts

- Happy path loads only 10.5k (subject to change and further optimization) of gzipped JavaScript

- Easy to implement with open documentation and examples, including dev kit

- With SaaS: Domain White Listing against unauthorized usage

### Team & Stakeholders

Role/Name | Contact
--- | ---
Business Owner | Johannes Fenner, CDP
Legal Affairs | Susanne Stollhoff, Dr. Olaf Koglin
Product Owner | Antonino Tumminelli, AS Ideas Engineering
UX | Özden Gelgec, AS Ideas Engineering
UX | Andreas Wagner, AS Ideas Engineering
Developer | Sebastian Waschnick, AS Ideas Engineering
Developer | Marcel Bankmann, AS Ideas Engineering
Developer | Alexander Glintschert, AS Ideas Engineering
Developer | Dmitri Awerkov-Schäfer, AS Ideas Engineering
Tealium Consulting | Michael Sievers, CDP

### Solution Strategy

According the proposal of the Commission, the European Parliament, and the Council of Ministers, websites will be required to prompt users with a menu of privacy options when they are visited for the first time.[1]

The Opt-In Layer (OIL) is our solution for these requirements consisting of three parts:

- A subscriber part, which adds the opt-in Layer to the host pages DOM and asks the user to opt-in.

- A hub part, which acts as a registry site for POI on a domain hosted by Ideas Engineering. This is optional and only needed for POI functionality.

- A backend part on a domain hosted by Ideas Engineering that provides all the texts and labels shown by the Opt-In Layer. Different languages and variants of these texts and labels are supported.

Opt-In Information is stored in a first party cookie in the user’s browser and communicated in a general way to the host site and Tealium. For Power Opt-In there is also a 3rd party cookie stored on a second domain to share information between sites.

### Why is there no native app support?

Native mobile apps are very customized concerning technology stack and implementation of tracking and advertising. Therefore, the OIL project won’t offer a generic solution for this purpose. Each unit has to review their app how tracking and advertising is implemented and find a solution to get the consent from the user by a dialog. Consents both on desktop or mobile browsers given by the user are not able to be used in the mobile app because: * mobile browsers and in app web views use different ressources to store their cookies * desktop browsers and mobile apps have no physical connections

## Quickstart

### Minimal setup

- Add your configuration tag, for example:

    <script id="oil-configuration" type="application/configuration">
      {
        "poi_activate_poi": true,
        "poi_group_name": "axelSpringerSe_01",
        "locale": "enEN_01"
      }
    </script>

- Add OIL and the CMP-stub to your website, with a tag manager like tealium or directly as a tag, for exampel:

    <script>
    /*! 1.1.2-RELEASE */!function(e){var n={};function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="//oil.axelspringer.com/release/1.1.2/",t(t.s=110)}({110:function(e,n,t){"use strict";!function(e,n){e.__cmp||(e.__cmp=function(){function t(){return!(!e.AS_OIL||!e.AS_OIL.commandCollectionExecutor)}(e.attachEvent||e.addEventListener)("message",function(n){e.__cmp.receiveMessage(n)},!1),function e(){if(!(n.getElementsByName("__cmpLocator").length>0))if(n.body){var t=n.createElement("iframe");t.style.display="none",t.name="__cmpLocator",n.body.appendChild(t)}else setTimeout(e,5)}();var o=[],r=function(n,r,a){if("ping"===n)(l=a)&&l({gdprAppliesGlobally:!1,cmpLoaded:t()});else{var c={command:n,parameter:r,callback:a};o.push(c),t()&&e.AS_OIL.commandCollectionExecutor(c)}var l};return r.commandCollection=o,r.receiveMessage=function(e){var n=e&&e.data&&e.data.__cmpCall;n&&o.push({callId:n.callId,command:n.command,parameter:n.parameter,event:e})},r}())}(window,document)}});
    </script>
    <script type="text/javascript" src="https://oil.axelspringer.com/release/1.1.2/oil.1.1.2-RELEASE.min.js"></script>

- Style your layer according to your style guide

- If needed: Create your own language pack and create your own POI group (currently only possible by mail to the developers, a UI is currently worked on)

### OIL SDK

This is a like a drop-in to add a small sdk to any site, which has oil included.

Add this to your favorites and open the link on the website you want it to be included:

    javascript:(function () {let d = document, s = d.createElement('script');s.id = 'oil-dev-kit-js';s.src = '//oil.axelspringer.com/latest/oildevkit.min.js';(d.head || d.body).appendChild(s)}());

### How to implement OIL on your site

Setting up OIL on your page consists of the following steps:

- Add the oil.js javascript snippet to your page

- Add a configuration block to your pages DOM

OIL creates a standard for the Opt-In but can’t automatically stop your site from tracking your users. So to actually make your page respond to opt-ins you also need to do the following.

- Make sure your page doesn’t track the user in its default state.

- Use Tealium for all tracking activities and use the loading rules we provide

- Listen to OIL events for loading non-Tealium tags, after the user opted in.

#### Adding oil.js to your site via Tealium (recommended)

Axel Springer Tealium needs to configure your site to inherit the predefined lib-dip-optin library profile. Once this is in place you publish those changes in the following way:

- Open your Tealium profile and go to "extensions"

- Find the entry for "AS Opt-in Overlay", you’ll be noticed of a change to this extension

- Publish / deploy your profile to activate the changes to Oil.js

This needs to be repeated for every new version of OIL. The library profile can’t push new code to your website without your action.

#### Adding oil.js to your site via direct integration

If Tealium can’t be used on your site you also can add OIL directly from our CDN.

Example (replace with the latest version):

    <script>
    /*! 1.1.2-RELEASE */!function(e){var n={};function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="//oil.axelspringer.com/release/1.1.2/",t(t.s=110)}({110:function(e,n,t){"use strict";!function(e,n){e.__cmp||(e.__cmp=function(){function t(){return!(!e.AS_OIL||!e.AS_OIL.commandCollectionExecutor)}(e.attachEvent||e.addEventListener)("message",function(n){e.__cmp.receiveMessage(n)},!1),function e(){if(!(n.getElementsByName("__cmpLocator").length>0))if(n.body){var t=n.createElement("iframe");t.style.display="none",t.name="__cmpLocator",n.body.appendChild(t)}else setTimeout(e,5)}();var o=[],r=function(n,r,a){if("ping"===n)(l=a)&&l({gdprAppliesGlobally:!1,cmpLoaded:t()});else{var c={command:n,parameter:r,callback:a};o.push(c),t()&&e.AS_OIL.commandCollectionExecutor(c)}var l};return r.commandCollection=o,r.receiveMessage=function(e){var n=e&&e.data&&e.data.__cmpCall;n&&o.push({callId:n.callId,command:n.command,parameter:n.parameter,event:e})},r}())}(window,document)}});
    </script>
    <script type="text/javascript" src="https://oil.axelspringer.com/release/1.1.2/oil.1.1.2-RELEASE.min.js"></script>

Updated versions of the script will be deployed using a different filename hence we’ll never alter an existing version.

Please make sure you’re working with the latest version available.

Please check https://oil.axelspringer.com/release for further updates. Choose the latest version or the version fitting to this documentation. Normalley there will be multiple files:

- oil.1.0.34-RELEASE.min.js - This is the file you will need to reference in your website

- hub.1.0.34-RELEASE.min.js

- Chunks, beginning with numbers - they will ne loaded asynchronously and you don’t need to do anything with them.

  - 0.1.0.34-RELEASE.chunk.js

  - X.1.0.34-RELEASE.chunk.js

## Configuration

### Configuring OIL

OIL comes with a wide range of customisation features which can be configured via a configuration block. Put the configuration object somewhere in the upper part of your page. Please disable the preview mode for the first production test. The preview mode hides the OIL layer except you enable it on your browser session. See the parameter section below for more details.

OIL also comes with a default configuration, that will support Single Opt-In with a German standard text.

#### SOI configuration

You need to add the configuration snippet to all pages where OIL is required. This is an example SOI configuration:

    <!-- Text labels, see Label Keys section below -->
    <script id="oil-configuration" type="application/configuration">
      {
        "preview_mode": false,
        "label_intro_heading": "Please confirm",
        "locale": "enEN_01"
      }
    </script>

#### POI configuration

You need to add the configuration snippet to all pages where OIL is required. Give extra attention to the configuration, if you want to use POI, which needs the additional POI configuration added and tailored to your situation. Contact us, if you need help. This is an example POI configuration:

    <script id="oil-configuration" type="application/configuration">
      {
        "preview_mode": false,
        /*
            Text labels, see Label Keys section below
        */
        "label_intro_heading": "Please confirm",
        /*
            POI optional params start here
        */
        "poi_activate_poi": true,
        "poi_hub_origin": "//oil.axelspringer.com",
        "poi_hub_path": "/hub.html",
        "poi_subscriber_set_cookie": true,
        "poi_group_name": "MyGroupName",
        "locale": "enEN_01"
      }
    </script>

POI can be partitioned in different groups using a prefix or group name. You need to use the same group name as every other unit in your group. This is not an optional parameter. Only group names configured by Axel Springer are allowed.

#### Functional Configuration Parameters

This is a full list of configurable options.

Config Parameter | Description | Default Setting
--- | --- | ---
locale | The locale version that should be used. The locale defines the standard labels for all legal texts and buttons. See available locale parameters | enEN_01
preview_mode | The preview mode is useful when testing OIL in a production or live environment. As a dev you can trigger the overlay by setting a cookie named "oil_preview" with the value "true". This will show the OIL layer on your client. | false
theme | The theme for the layer. By default there are two themes and size modifier themes, `dark` and `light` as well as `small dark` and `small light`. Themes currently work only as an additional css class. If you want to change the style or theme, please look into the styling guide in the development section. | light
poi_activate_poi | Activates or disactivates Power Opt-In. Rememeber that you also have to setup the hub.js part if you do so, or you will endup with a non-working button. | false
poi_hub_origin | The origin of the hub.js installation, if any. | //oil.axelspringer.com
poi_hub_path | The path to the hub.html installation on the origin, if any. | /hub.html
poi_group_name | POI group name. POI only affects those sites with the same group name (mandatory if POI is activated). The group name must be valid (existing). Supported POI groups. | none
poi_subscriber_set_cookie | Whether to set the SOI cookie on POI opt-ins or not. | true
cookie_expires_in_days | Value in days until the domain cookie used to save the users decision in days | 31
timeout | Value in seconds until the opt-in layer will be automatically hidden. 0 or lower deactivates auto-hide. | 60
advanced_settings | Replaces the No Button with a advanced settings button, which enables the user to select between different settings of privacy. The results of this selection is stored in the oil cookie (both SOI and POI) as well. | false
persist_min_tracking | If minimum tracking should result in removing all OIL cookies from the users browser and close the layer and store this selection in the oil cookie. | true
iabVendorListUrl | tbd | {embedded vendorlist}
oilBackendUrl | (deprecated) The backend from where OIL can load locale-versions | https://oil-backend.herokuapp.com/oil
iabVendorWhitelist | Array of vendor IDs to allow. If it is set, values in `iabVendorBlacklist` are ignored. | none
iabVendorBlacklist | Array of vendor IDs to exclude | None
customPurposes | Array of custom purposes defined by publisher. IDs for custom purposes may range from 25-88. | none
default_to_optin | Signal opt-in to vendors while still displaying the Opt-In layer to the end user | false
advanced_settings_purposes_default | All purposes in the advanced settings layer should be activated by default | false

##### Blacklisting and Whitelisting

With iabVendorWhitelist and iabVendorBlacklist you can exclude specific vendors from the consent (blacklist) or include only the ones you want (whitelist). You can only use one method at the time - either whitelist or blacklist.

As an example, the vendorlist may contain vendors with vendor IDs 1 to 10. In the example the user accepts everything, he just pressed "OK". The consent-string would normally contain (by getVendorConsents) this data:

Default result from getVendorConsents without whitelist/blacklist

    {
      "metadata": "consent-string",
      "purposeConsents": {
        "1": 1,
        "2": 1,
        "3": 1,
        "4": 1,
        "5": 1
      },
      "vendorConsents": {
        "1": true,
        "2": true,
        "3": true,
        "4": true,
        "5": true,
        "6": true,
        "7": true,
        "8": true,
        "9": true,
        "10": true
      }
    }

Whitelist: The whitelist contains IDs 3, 4, 5 in form of the configuration with `"iabVendorWhitelist": [3, 4, 5]`. If the user has given his consent by clicking on "OK" only vendors on the whitelist will be true.

Result from getVendorConsents with whitelisting vendor IDs 3, 4, 5

    {
      "metadata": "consent-string",
      "purposeConsents": {
        "1": 1,
        "2": 1,
        "3": 1,
        "4": 1,
        "5": 1
      },
      "vendorConsents": {
        "1": false,
        "2": false,
        "3": true,
        "4": true,
        "5": true,
        "6": false,
        "7": false,
        "8": false,
        "9": false,
        "10": false
      }
    }

Blacklist: The blacklist contains IDs 6, 7, 8 in form of the configuration with `"iabVendorBlacklist": [6, 7, 8]`. If the user has given his consent by clicking on "OK" only vendors NOT on the blacklist will be true.

Result from getVendorConsents with blacklisting vendor IDs 6, 7, 8

    {
      "metadata": "consent-string",
      "purposeConsents": {
        "1": 1,
        "2": 1,
        "3": 1,
        "4": 1,
        "5": 1
      },
      "vendorConsents": {
        "1": true,
        "2": true,
        "3": true,
        "4": true,
        "5": true,
        "6": false,
        "7": false,
        "8": false,
        "9": true,
        "10": true
      }
    }

#### Language configuration

You need to set a value for the `locale` config parameter. The locale defines the standard labels for all legal texts and buttons.

Locale | Description
--- | ---
deDE_01 | German
enEN_01 | English
plPL_01 | Polish

#### Label Configuration Parameters

The recommended way is to keep the standard locale definitions. If you need to customize single labels you can manually pass them in the configuration or directly override the properties of the object in `window.AS_OIL.LOCALE.texts`.

Config Parameter | Default value
--- | ---
label_intro_heading | We use cookies and other technologies
label_intro | The website uses cookies, web beacons, JavaScript and similar technologies. I agree that <a href=\"javascript:void(0)\" class=\"as-oilintro-txt—​link as-js-companyList\">companies belonging to Axel Springer SE</a> and <a href=\"javascript:void(0)\" class=\"as-oilintro-txt—​link as-js-thirdPartyList\">trusted partners</a> generate pseudonymous user profiles for adapting the website to the user, for market research and for advertising. The generated data can also be shared with third parties while the user profiles cannot be combined with personal data. Detailed information, also on the right to withdraw consent, can be found in the website’s privacy policy.
label_button_yes | OK
label_button_back | Back
label_button_advanced_settings | More information
label_cpc_heading | Please select a privacy setting:
label_cpc_text | Choose the allowed purposes.
label_cpc_activate_all | Activate all
label_cpc_deactivate_all | Deactivate all
label_cpc_purpose_desc | Purposes
label_cpc_purpose_01_text | Accessing a Device
label_cpc_purpose_01_desc | Allow storing or accessing information on a user’s device.
label_cpc_purpose_02_text | Advertising Personalisation
label_cpc_purpose_02_desc | Allow processing of a user’s data to provide and inform personalised advertising (including delivery, measurement, and reporting) based on a user’s preferences or interests known or inferred from data collected across multiple sites, apps, or devices; and/or accessing or storing information on devices for that purpose.
label_cpc_purpose_03_text | Analytics
label_cpc_purpose_03_desc | Allow processing of a user’s data to deliver content or advertisements and measure the delivery of such content or advertisements, extract insights and generate reports to understand service usage; and/or accessing or storing information on devices for that purpose.
label_cpc_purpose_04_text | Content Personalisation
label_cpc_purpose_04_desc | Allow processing of a user’s data to provide and inform personalised content (including delivery, measurement, and reporting) based on a user’s preferences or interests known or inferred from data collected across multiple sites, apps, or devices; and/or accessing or storing information on devices for that purpose.
label_cpc_purpose_05_text | Matching Data to Offline Sources
label_cpc_purpose_05_desc | Combining data from offline sources that were initially collected in other contexts
label_cpc_purpose_06_text | Linking Devices
label_cpc_purpose_06_desc | Allow processing of a user’s data to connect such user across multiple devices.
label_cpc_purpose_07_text | Precise Geographic Location data
label_cpc_purpose_07_desc | Allow processing of a user’s precise geographic location data in support of a purpose for which that certain third party has consent
label_poi_group_list_heading | Your consent for companies of the group
label_poi_group_list_text | Here is a list of companies of the group:
label_third_party | Third Parties
label_thirdparty_list_heading | Your consent for third party software
label_thirdparty_list_text |
label_nocookie_head | In order to be able to provide our services in the best possible way, cookies must be enable in your browser.
label_nocookie_text | Please enable Cookies in the properties of your Browsers. So you can do it in <a href=\"https://support.google.com/chrome/answer/95647?co=GENIE.Platform%3DDesktop&hl=en-GB\" class=\"as-oilintro-txt—​link\" target=\"_blank\">Google Chrome</a> or <a href=\"https://support.mozilla.org/en-US/kb/cookies-information-websites-store-on-your-computer\" class=\"as-oilintro-txt—​link\" target=\"_blank\">Firefox</a>."

Example Screenshot:

#### Auto-Hiding the layer (timeout)

If you do not interact with the Opt-In Layer, it will autohide after a fixed time. If you want to disable the feature, you need to edit the configuration and the set the value to 0 or -1. If you click on any navigation link in the Opt-In Layer the timeout will be canceled. The default timeout is:

    const defaultTimeoutInSeconds = 60;

## IAB Europe "Transparency & Consent Framework"

The IAB specification explains how a vendor should communicate with a CMP to gather consent information before running any data processing. That API is a set of JavaScript functions. You can find more at the official website http://advertisingconsent.eu/

The consent string is the central part of the IAB framework: it encodes all the consent information for the user, by purpose and by vendor.

### JS-API

This API has to support the following functionality. All methods are strings and can be called over the window.__cmp function.

    <script type="text/javascript">
    __cmp('getVendorConsents', null, (result) => console.info(result));
    </script>

#### getVendorConsents

Parameter: vendorIds (Uint16Array)

Callback signature: Callback( VendorConsents object, success: boolean)

The vendorIds array contains the vendor ids (as identified in the Global Vendor List) for which consent is being requested. If vendorIds is null or empty, the operation will return consent status for all vendors in the vendor list. The callback function will be called with a VendorConsents object as the parameter. If vendorIds is provided and not empty, then VendorConsents.vendorConsents will only included IDs from vendorIds, The callback is called only after consent is obtained from the UI or existing cookies. The consent will be returned false ("No Consent") for any invalid vendorId. The boolean success parameter passed to the callback indicates whether the call to getVendorConsents() was successful.

#### getConsentData

Parameter: consentStringVersion (string)

Callback signature: Callback(VendorConsentData object, success: boolean)

If consentStringVersion is provided, then fetch that version if available (else returns null). If consentStringVersion is null, then the latest supported version of the consent string is returned. The callback is called only after consent is obtained from the UI or existing cookies. The boolean success parameter passed to the callback indicates whether the call to getConsentData() was successful.

#### ping

Callback signature: Callback(PingReturn object, success: boolean)

The "ping" command invokes the callback immediately with information about whether the main CMP script has loaded yet and if GDPR has been configured for all users or just EU users. (This requires this command’s implementation and this configuration to be in the stub).

#### Optional call: getPublisherConsents

Parameter: purposeIds: Uint16Array

Callback signature: Callback( PublisherConsents object, success: boolean)

The purposeIds lists the purpose ids the publisher is requesting consent for. If this array is null or empty, it will default to all configured purposes. PurposeId’s 1-24 indicate standard purposes, while 25-88 indicate custom (publisher-configured) purposes. The callback function will be called with a PublisherConsents object as the parameter. The purpose ids would be set by the publisher using a CMP-defined initialization function. The callback is called only after consent is obtained from the UI or existing cookies. The boolean success parameter passed to the callback indicates whether the call to getPublisherConsents() was successful.

#### Optional call: getVendorList

Parameter: vendorListVersion (scalar)

Callback signature: Callback(GlobalVendorList object, success:boolean)

The callback function will be called with the GlobalVendorList parameter being the vendor list object of the requested version. If the vendorListVersion is null, the vendor list for the VendorListVersion in the current consent string is returned. If no consent string value is currently set, the latest version of the vendor list is returned. If the vendorListVersion value is ?LATEST?, the latest version available is returned. If the vendorListVersion is invalid, the callback function will be called with 'null' as the first argument and false as the success argument. The boolean success parameter passed to the callback indicates whether the call to getVendorList() was successful.

## OIL API

In addition to the configuration the host site can communicate with the OIL layer using its API. OIL, in its default state, never emits console errors. To get a full log and all errors you can enable the verbose mode. For test deployments and A/B testing OIL supports a preview mode.

### Test Deployment and Preview Mode

The preview mode is useful for testing OIL in a live environment without making it available to your end-users.

The preview mode is turned off by default, meaning OIL will be available to all your users. If you turn the preview mode on (please see configuration section), OIL won’t be shown at first, but can be enabled for your current session on the browser’s console:

    window.AS_OIL.previewModeOn();
    window.AS_OIL.previewModeOff();

When preview mode is turned on some debug information will be seen on the browser console. See also "Verbose Logging" below for more detailed logging.

### OIL Verbose Logging

OIL will show no logs, except in preview mode or verbose mode.

Run the following commands on the console of your browser to switch verbose logging on and off:

    window.AS_OIL.verboseModeOn();
    window.AS_OIL.verboseModeOff();

Debug mode can be turned on at any time, whereas the similar preview mode can only be enabled in the configuration, please see above.

Please note that verbose logging can only be activated for your own browser, all other users won’t see those logs.

### OIL JS-Calls

API Call | Description
--- | ---
window.AS_OIL.triggerOptIn(); | The user will opted in. It’s the same behaviour as when the user is clicking Accept on the layer.
window.AS_OIL.triggerOptOut(); | OIL will remove all cookies if triggered and therefore opt-out the user of everything, even POI.
window.AS_OIL.reload(); | OIL will reload the configuration from the host’s website.
window.AS_OIL.showPreferenceCenter(); | OIL will inject the Cookie Preference Center into your website. Please see "OIL CPC API" section.

### OIL Events

#2. Register an event handler with a callback to be executed when OIL fires the opt-in event or the user has opted in on an earlier occasion and revisits the page.

      <script type="text/javascript">
        // Cross browser event handler definition
        var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
        var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
        var eventer = window[eventMethod];

        // Callback to be executed when event is fired
        function receiveMessage(event) {
          function eventDataContains(str) {
            return JSON.stringify(event.data).indexOf(str) !== -1;
          }
          if (event && event.data && (eventDataContains('oil_optin_done') || eventDataContains('oil_has_optedin'))) {
            // Do something when event is fired...
            console.log("Do something when event is fired...");
          }
        }

        // Register event handler
        eventer(messageEvent, receiveMessage, false);
      </script>

OIL is currently emitting the following events:

Event name | Description
--- | ---
oil_optin_done | When a users selects opt-in.
oil_as_cpc_privacy_selected | When a user used the cpc and clicked opt-in.
oil_click_advanced_settings | When a users clicks the advanced settings button/link.
oil_click_back_to_main | When a user clicks the back link from the advanced settings page.
oil_no_cookies_allowed | When a users has no cookies allowed and the no cookies layer is displayed
oil_has_optedin | On every page reload, when the user has opted_in previously (OIL should be hidden)
oil_shown | When oil is shown
oil_hide_layer | When oil gets automatically hidden
oil_click_thirdparty_list | When a user clicks the third party list link
oil_click_company_list | When a user clicks the company list link

### OIL CPC API

You can add an integrated version of the OIL Cookie Preference Center to your page to give the user the chance to reverse his initial selection (or even Opt-Out).

For this include a div with the id below in your page:

    <div id="oil-preference-center"></div>

To insert the OIL CPC in the prepared div, which you included in your page, execute this javascript snippet:

    window.AS_OIL.showPreferenceCenter();

For the action element to save the current setting there is an API endpoint:

    window.oilTriggerOptin();

The inserted CPC will show the users current setting when inserted. Make sure OIL is part of the page first to make this work.

CPC API definition:

Function Name | Description
--- | ---
window.AS_OIL.showPreferenceCenter() | inserts the CPC into the predefined div with the id #oil-preference-center into the host site
window.AS_OIL.triggerOptIn() | will trigger the generic opt-in (can also result in an opt-out)

### Tracking and Google Analytics Events

If you want to use Google Analytics with OIL you can use OIL Events (see above) and proxy them to your specific GA installation.

This is an example script to subscribe to the event 'oil_optin_done' and forward it to Google Analytics. You might need to tweak it to your environment and needs.

    // Multibrowser Support
    var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
    var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
    var eventer = window[eventMethod];

    function receiveOptInMessage(event) {
      function eventDataContains(str) {
        return JSON.stringify(event.data).indexOf(str) !== -1;
      }
      if (window.ga && window.ga.loaded && event && event.data && eventDataContains('oil_optin_done')) { // event name
        var nonInteraction = true; // should be set to false for non-click events
        window.ga('send', 'event', 'OIL', 'oil_optin_done', {'nonInteraction': nonInteraction});
      }
    }

    eventer(messageEvent, receiveMessage, false);

## Customisation

### Supported A/B Testing with us

If you want to optimize and test your OIL installation with our Kameleoon A/B testing, you also need to include the right kameleoon script into your website, which will alter the optics and behaviour of OIL according to the test and your specific environment.

An example link would look like:

    <script type="text/javascript" src="//static-bp.kameleoon.com/css/customers/xxxxxxxxxxx/0/kameleoon.js"></script>

Instead of xxxxxxxxxxx the right hash needs to be present, so Kameleoon knows which website it deals with. When we setup OIL A/B testing on your page this hash needs to be generated within Kameleoon.

### Your own A/B Testing

For setting up A/B testing in your own environment, the following information could come handy.

#### Enabling OIL for a specific variant only

For testing you can also use the preview mode to disable OIL by default and enable it in certain variants.

Add the following standard configuration to your website, which will disable OIL by default:

    <script id="oil-configuration" type="application/configuration">
      {
        "preview_mode": true,
      }
    </script>

For enabling it in a variant you need to replace the configuration and trigger OIL to reload it. As part of your variant insert a customized version of this script:

    <script type="text/javascript">
        (function () {
            var config = {
                "preview_mode": false,
                "label_intro_heading": "Please confirm!",
                "label_button_yes": "Of course"
            };
            var oldScript = document.getElementById('oil-configuration');
            if (oldScript) {
                oldScript.parentNode.removeChild(oldScript);
            }

            var head = document.getElementsByTagName('head')[0];
            var script = document.createElement('script');

            script.id = 'oil-configuration';
            script.type = 'application/configuration';
            script.text = JSON.stringify(config);

            head.appendChild(script);
            window.AS_OIL.reload();
        }());
    </script>

#### Full Label Configuration

Even though OIL is supposed to come with legal texts that shouldnt be altered, except the main heading, for testing purposes all labels can be overwritten, even the default ones, in the OIL configuration block (see chapter "OIL configuration") as follows:

Config Parameter | Example Value
--- | ---
label_intro_heading | We use cookies and other technologies
label_intro | We’re using cookies, please confirm!
label_button_yes | Yes
label_button_back | Back
label_button_advanced_settings | More information
label_advanced_settings_heading | Cookie Preference Center
label_advanced_settings_text | Please select a setting:
label_advanced_settings_essential_text | Essentials
label_advanced_settings_essential_verbose | Only essential cookies
label_advanced_settings_functional_text | Social
label_advanced_settings_functional_verbose | Additional social cookies
label_advanced_settings_advertising_text | Ads
label_advanced_settings_advertising_verbose | Additional ads cookies
label_nocookie_head | No Cookies allowed.
label_nocookie_text | Please enable cookies!
label_poi_group_list_heading | Company units
label_poi_group_list_text | Here is a list of company units
label_thirdparty_list_heading | Third Parties
label_thirdparty_list_text | Here is a list of third parties

Important | If you want to reference the company or third party list from your custom text you need to add the links inline and set the right css classes.

    <a href="javascript:void(0)" class="as-oil__intro-txt--link as-js-companyList">CompanyListLink</a>
    <a href="javascript:void(0)" class="as-oil__intro-txt--link as-js-thirdPartyList">ThirdPartys</a>

### Styling guide

You can style the layer with additional CSS. All OIL styles use the css classes directly, this means the lowest possible css specificity. Here are two examples. The first one is for changing the font and the color. The second is for changing the background color and the shadow.

    div.as-oil {
      font-family: Arial;
      color: #bada55;
    }

    div.as-oil-content-overlay {
      background-color: #ff00ff;
      box-shadow: 0 -8px 20px 0 rgba(0, 0, 0, 0.2);
    }

Here are the current raw html snippets used for the opt-in layer. You can use these as reference for which classes were used.

#### Opt-In layer

    <div class="as-oil light" data-qa="oil-Layer">
      <div class="as-oil-content-overlay" data-qa="oil-full">
        <div class="as-oil-l-wrapper-layout-max-width">
          <div class="as-oil__heading">label_intro_heading</div>
          <p class="as-oil__intro-txt">label_intro</p>
          <div class="as-oil-l-row as-oil-l-buttons">
            <div class="as-oil-l-item">
              <button class="as-oil__btn-optin as-js-optin" data-context="YES" data-qa="oil-YesButton">label_button_yes
              </button>
            </div>
            <div class="as-oil-l-item as-oil-l-item--stretch"></div>
          </div>
        </div>
      </div>
    </div>

#### No-cookie layer

    <div class="as-oil light" data-qa="oil-Layer">
      <div class="as-oil-content-overlay oil-nocookies" data-qa="oil-nocookies">
        <div class="as-oil-l-wrapper-layout-max-width">
          <div class="as-oil__heading">
            label_nocookie_head
          </div>
          <p class="as-oil__intro-txt">
            label_nocookie_text
          </p>
        </div>
      </div>
    </div>

#### POI group list

    <div class="as-oil-fixed">
      <div class="as-oil-content-overlay as-oil-poi-group-list-wrapper" data-qa="oil-poi-list">
        <div class="as-oil-l-wrapper-layout-max-width">
          <div class="as-oil__heading">
            label_poi_group_list_heading
          </div>
          <p class="as-oil__intro-txt">
            label_poi_group_list_text
          </p>
          <div class="as-oil-poi-group-list">
            <div class="as-oil-poi-group-list-element">a</div>
            <div class="as-oil-poi-group-list-element">b</div>
          </div>
          <button class="as-js-oilback" data-context="BACK" data-qa="oil-back-button">
            <span class="as-js-oilback__text">label_button_back</span>
            <svg class="as-js-oilback__icon" width="22" height="22" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
              <g fill="none" fill-rule="evenodd">
                <circle fill="#757575" cx="11" cy="11" r="11" />
                <path d="M15.592 14.217a.334.334 0 0 1 .098.245c0 .098-.033.18-.098.246l-.928.908a.303.303 0 0 1-.22.098.33.33 0 0 1-.244-.098L11 12.4l-3.2 3.216a.303.303 0 0 1-.22.098.33.33 0 0 1-.244-.098l-.928-.908a.334.334 0 0 1-.098-.246c0-.098.033-.18.098-.245L9.632 11 6.408 7.808c-.163-.164-.163-.327 0-.491l.904-.933a.473.473 0 0 1 .244-.098.33.33 0 0 1 .244.098L11 9.576l3.2-3.192a.473.473 0 0 1 .244-.098.33.33 0 0 1 .244.098l.904.933c.163.164.163.32 0 .466l-3.224 3.192 3.224 3.242z"
                      fill="#FFF" opacity=".88" />
              </g>
            </svg>
          </button>
        </div>
        <div class="as-oil-l-row as-oil-l-buttons-light">
          <div class="as-oil-l-item">
            <button class="as-oil__btn-optin as-js-optin" data-context="YES" data-qa="oil-YesButton">
              label_button_yes
            </button>
          </div>
        </div>
      </div>
    </div>

#### Advanced Settings (CPC, Cookie Preference Center)

    <div class="as-oil light" data-qa="oil-Layer">
      <div id="as-oil-cpc" class="as-oil-content-overlay" data-qa="oil-cpc-overlay">
        <div class="as-oil-l-wrapper-layout-max-width as-oil-cpc-wrapper">
          <div class="as-oil__heading">
            label_cpc_heading
          </div>
          <p class="as-oil__intro-txt">
            label_cpc_text
          </p>
          <div class="as-oil-cpc__row-btn-all">
            <span class="as-js-btn-deactivate-all as-oil__btn-grey">label_cpc_deactivate_all</span>
            <span class="as-js-btn-activate-all as-oil__btn-blue">label_cpc_activate_all</span>
          </div>
          <button class="as-js-oilback" data-context="BACK" data-qa="oil-back-button">
            <span class="as-js-oilback__text">
                      label_button_back
                    </span>
            <svg class="as-js-oilback__icon" width="22" height="22" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
              <g fill="none" fill-rule="evenodd">
                <circle fill="#757575" cx="11" cy="11" r="11"></circle>
                <path d="M15.592 14.217a.334.334 0 0 1 .098.245c0 .098-.033.18-.098.246l-.928.908a.303.303 0 0 1-.22.098.33.33 0 0 1-.244-.098L11 12.4l-3.2 3.216a.303.303 0 0 1-.22.098.33.33 0 0 1-.244-.098l-.928-.908a.334.334 0 0 1-.098-.246c0-.098.033-.18.098-.245L9.632 11 6.408 7.808c-.163-.164-.163-.327 0-.491l.904-.933a.473.473 0 0 1 .244-.098.33.33 0 0 1 .244.098L11 9.576l3.2-3.192a.473.473 0 0 1 .244-.098.33.33 0 0 1 .244.098l.904.933c.163.164.163.32 0 .466l-3.224 3.192 3.224 3.242z"
                      fill="#FFF" opacity=".88"></path>
              </g>
            </svg>
          </button>
          <div data-qa="cpc-snippet" class="as-oil-l-row as-oil-cpc__content">
            <div class="as-oil-cpc__left">
              <a href="#as-oil-cpc-purposes" onclick="AS_OIL._switchLeftMenuClass(this)" class="as-oil-cpc__category-link as-oil-cpc__category-link--active">
                label_cpc_purpose_desc
              </a>
              <a href="#as-oil-cpc-third-parties" onclick="AS_OIL._switchLeftMenuClass(this)" class="as-oil-cpc__category-link">
                label_third_party
              </a>
            </div>
            <div class="as-oil-cpc__middle as-js-purposes">
              <div class="as-oil-cpc__row-title" id="as-oil-cpc-purposes">
                label_cpc_purpose_desc
              </div>
              <div class="as-oil-cpc__purpose">
                <div class="as-oil-cpc__purpose-container">
                  <div class="as-oil-cpc__purpose-header">Purpose 1</div>
                  <div class="as-oil-cpc__purpose-text">label_cpc_purpose_01_desc</div>
                  <label class="as-oil-cpc__switch">
                    <input data-id="1" id="as-js-purpose-slider-1" class="as-js-purpose-slider" type="checkbox" name="oil-cpc-purpose-1" value="false">
                    <span class="as-oil-cpc__status"></span>
                    <span class="as-oil-cpc__slider"></span>
                  </label>
                </div>
              </div>
              <div class="as-oil-cpc__purpose">
                <div class="as-oil-cpc__purpose-container">
                  <div class="as-oil-cpc__purpose-header">Purpose 2</div>
                  <div class="as-oil-cpc__purpose-text">label_cpc_purpose_02_desc</div>
                  <label class="as-oil-cpc__switch">
                    <input data-id="2" id="as-js-purpose-slider-2" class="as-js-purpose-slider" type="checkbox" name="oil-cpc-purpose-2" value="false">
                    <span class="as-oil-cpc__status"></span>
                    <span class="as-oil-cpc__slider"></span>
                  </label>
                </div>
              </div>
              <div class="as-oil-cpc__purpose">
                <div class="as-oil-cpc__purpose-container">
                  <div class="as-oil-cpc__purpose-header">Purpose 3</div>
                  <div class="as-oil-cpc__purpose-text">label_cpc_purpose_03_desc</div>
                  <label class="as-oil-cpc__switch">
                    <input data-id="3" id="as-js-purpose-slider-3" class="as-js-purpose-slider" type="checkbox" name="oil-cpc-purpose-3" value="false">
                    <span class="as-oil-cpc__status"></span>
                    <span class="as-oil-cpc__slider"></span>
                  </label>
                </div>
              </div>
              <div class="as-oil-cpc__purpose">
                <div class="as-oil-cpc__purpose-container">
                  <div class="as-oil-cpc__purpose-header">Purpose 4</div>
                  <div class="as-oil-cpc__purpose-text">label_cpc_purpose_04_desc</div>
                  <label class="as-oil-cpc__switch">
                    <input data-id="4" id="as-js-purpose-slider-4" class="as-js-purpose-slider" type="checkbox" name="oil-cpc-purpose-4" value="false">
                    <span class="as-oil-cpc__status"></span>
                    <span class="as-oil-cpc__slider"></span>
                  </label>
                </div>
              </div>
              <div class="as-oil-cpc__purpose">
                <div class="as-oil-cpc__purpose-container">
                  <div class="as-oil-cpc__purpose-header">Purpose 5</div>
                  <div class="as-oil-cpc__purpose-text">label_cpc_purpose_05_desc</div>
                  <label class="as-oil-cpc__switch">
                    <input data-id="5" id="as-js-purpose-slider-5" class="as-js-purpose-slider" type="checkbox" name="oil-cpc-purpose-5" value="false">
                    <span class="as-oil-cpc__status"></span>
                    <span class="as-oil-cpc__slider"></span>
                  </label>
                </div>
              </div>
              <div class="as-oil-cpc__row-title" id="as-oil-cpc-third-parties">
                label_third_party
              </div>
              <div id="as-js-third-parties-list">
                <div class="as-oil-poi-group-list">
                  <div class="as-oil-third-party-list-element">
                    <span onclick="AS_OIL._toggleViewElements(this)">
                            <svg class="as-oil-icon-plus" width="10" height="10" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
                              <path d="M5.675 4.328H10v1.344H5.675V10h-1.35V5.672H0V4.328h4.325V0h1.35z" fill="#0068FF" fill-rule="evenodd" fill-opacity=".88"></path>
                            </svg>
                            <svg class="as-oil-icon-minus" style="display: none;" width="10" height="5" viewBox="0 0 10 5" xmlns="http://www.w3.org/2000/svg">
                              <path d="M0 0h10v1.5H0z" fill="#3B7BE2" fill-rule="evenodd" opacity=".88"></path>
                            </svg>
                            <span class="as-oil-third-party-name">Emerse Sverige AB</span>
                    </span>
                    <div class="as-oil-third-party-toggle-part" style="display: none;">
                      <a class="as-oil-third-party-link" href="https://www.emerse.com/privacy-policy/">https://www.emerse.com/privacy-policy/</a>
                    </div>
                  </div>
                  <div class="as-oil-third-party-list-element">
                    <span onclick="AS_OIL._toggleViewElements(this)">
                            <svg class="as-oil-icon-plus" width="10" height="10" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
                              <path d="M5.675 4.328H10v1.344H5.675V10h-1.35V5.672H0V4.328h4.325V0h1.35z" fill="#0068FF" fill-rule="evenodd" fill-opacity=".88"></path>
                            </svg>
                            <svg class="as-oil-icon-minus" style="display: none;" width="10" height="5" viewBox="0 0 10 5" xmlns="http://www.w3.org/2000/svg">
                              <path d="M0 0h10v1.5H0z" fill="#3B7BE2" fill-rule="evenodd" opacity=".88"></path>
                            </svg>
                            <span class="as-oil-third-party-name">BeeswaxIO Corporation</span>
                    </span>
                    <div class="as-oil-third-party-toggle-part" style="display: none;">
                      <a class="as-oil-third-party-link" href="https://www.beeswax.com/privacy.html">https://www.beeswax.com/privacy.html</a>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div class="as-oil-cpc__right">
              <div class="as-oil-l-row as-oil-l-buttons-light">
                <div class="as-oil-l-item">
                  <button class="as-oil__btn-optin as-js-optin" data-context="YES" data-qa="oil-YesButton">
                    label_button_yes
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

#### "Thank you" Screen

If you are performing A/B tests on the OIL Layer while not having the tracking disabled technically, we recommend to additionally insert this customized "Thank you"-Layer javascript code your website.

This code will listen to OIL events to show another window after the user finished the conversion process explaining the nature of the test.

    (function () {

        // Cross browser event handler definition
        var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent';
        var messageEvent = eventMethod === 'attachEvent' ? 'onmessage' : 'message';
        var eventer = window[eventMethod];

        // Callback to be executed when event is fired
        function receiveMessage(event) {
            function eventDataContains(str) {
                return JSON.stringify(event.data).indexOf(str) !== -1;
            }

            if (event && event.data && (eventDataContains('oil_opt'))) {
                var htmlCode = '<div class="as-oil-content-overlay">'
                    + '<div class="as-oil-l-wrapper-layout-max-width">'
                    + '<div class="as-oil__heading">'
                    + 'Thank you for your feedback!'
                    + '</div>'
                    + '<p class="as-oil__intro-txt">'
                    + 'We as a company take your privacy very seriously. In order to learn your expectations we '
                    + 'currently conduct this survey. Thank you for your understanding!'
                    + '</p>'
                    + '<div class="as-oil-l-row as-oil-l-buttons">'
                    + '<div class="as-oil-l-item">'
                    + '<button class="as-oil__btn-soi as-js-optin as-close-ty-button" onclick="closeOil()">'
                    + 'Close'
                    + '</button>'
                    + '</div>'
                    + '</div>'
                    + '</div>'
                    + '</div>';

                var thankYouNode = document.createElement('div');
                thankYouNode.id = "as-oil-thank-you";
                thankYouNode.innerHTML = htmlCode;
                thankYouNode.setAttribute('class', 'as-oil');
                document.body.appendChild(thankYouNode);
            }
        }

        // Register event handler
        eventer(messageEvent, receiveMessage, false);
    }());

### Adding Scripts programmatically

#### Adding oil.js configuration

    var oldScript = document.getElementById('oil-configuration');
    if (oldScript) {
      oldScript.parentNode.removeChild(oldScript);
    }

    var config = {
      preview_mode: true
    };
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');

    script.id = 'oil-configuration';
    script.type = 'application/configuration';
    script.text = JSON.stringify(config);

    head.appendChild(script);

## Appendix

### Glossary

Term | Explanation
--- | ---
OIL | Stands for opt-in Layer and besides the fact that it stand for the name of the product it is often used to refer to the UI layer shown on the page.
Site Opt-In (SOI) | The Site Opt-In stores a user’s opt-in permit for the current site only. Also known as domain opt-in.
Power Opt-In (POI) | The Power Opt-In functionality stores the opt-in permit for multiple Axel Springer websites. This allows users to only give their opt-in permit for many websites at once. POI is implemented via an iframe solution, see also Hub . Also known as group opt-in.
Hub | POI is implemented via an iframe solution that points to a hub site that acts as a third party cookie storage. Technically, the hub consists of an html and js.
Subscriber | A site that subscribes to a POI hub

### Supported POI Groups

- axelSpringerPl_01
- axelSpringerSe_01
- default
- insiderInc_01