Skip to main content

Advanced options

This guide helps you get familiar with additional advanced implementation options Kameleoon provides.

Depending on the country you are operating your website in, you may need to manage consent before collecting any data about your visitors. You can read more about it in our documentation.

Cross-device history reconciliation

Kameleoon provides a powerful feature that enables the merging of a user's history and actions made across different devices. When a user visits a website multiple times via different devices, Kameleoon can identify them as a returning visitor and accurately report the number of visits. This feature is straightforward to enable as long as there's a way to identify users on your end, usually through a customer login.

By using cross-device history reconciliation, you can take advantage of three significant benefits:

  • a coherent targeting system that takes into account all visits and actions across devices,
  • ensuring that a visitor sees the same variation for a given A/B experiment, regardless of the device they're using,
  • and a precise and accurate reporting system that correctly counts unique visitors.

To learn more about this feature, you can refer to this documentation.

ITP management

If a significant portion of your website's traffic comes from mobile devices, we recommend that you implement a cookie synchronization method to prevent issues with Intelligent Tracking Prevention (ITP) on Safari. For more technical details about ITP management, please refer to our documentation.

There are several options available for synchronizing the visitorCode identifier (via the kameleoonVisitorCode cookie) between the front-end and back-end to avoid ITP issues on Safari. These options include:

  • modifying your front-facing web server or Content Delivery Network (CDN) configuration to generate and add the required cookie,
  • implementing a specific code snippet on your backend server,
  • or using one of our SDKs that includes a synchronization method.
note

Due to changes in Safari 16.4, we no longer recommend using a DNS entry to synchronize the visitorCode. Safari now limits the lifetime of server-set first-party cookies to a maximum of seven days if the server that is setting the cookie uses a CNAME that resolves to a third-party host.

If you need instructions for Akamai or nginx, we can provide them. Similarly, if you use Java, NodeJS, or another technology, you can implement the specific code snippet we provide.

Backend code snippets

To implement Kameleoon's synchronization method, you can choose to host the code below on a single URL belonging to your main top-level domain, or on every page hosting/serving the Kameleoon application file (typically all pages of your website).

If you opt for a single endpoint for synchronization, please inform your Customer Success Manager of the chosen URL so they can activate synchronization. With this approach, the Kameleoon engine will make a single call per session to the specified endpoint to ensure that the server sets the cookie. The call is asynchronous and occurs after the page has finished loading.

note

The endpoint you create for synchronization should typically not return any data, and a 204 response code is sufficient. This endpoint is used solely for the purpose of setting a server-side cookie.

If you embed the code everywhere, no additional actions are needed. The cookie will be automatically created when normal page requests are made to your servers.

tip

You have the option to provide your own visitorCode, typically a unique identifier from your database, instead of relying on our automatic generation. In this case, please ensure that the visitorCode you provide is unique for each of your visitors to ensure accurate data for your experiments.

Java

javax.servlet.http.HttpServletRequest request; // Provide a reference to the HttpServletRequest
javax.servlet.http.HttpServletResponse response; // Provide a reference to the HttpServletResponse
String topLevelDomain = "MY_DOMAIN";// Here you must provide your own base domain, eg mydomain.com
String visitorCode = null; // Here you can provide your own identifier if needed, else it will be generated randomly

String cookiesHeader = request.getHeader("Cookie");
if (cookiesHeader != null)
{
String[] cookies = cookiesHeader.split(";");
for(String cookieNameAndValue :cookies)
{
String[] cookieNameAndValuePair = cookieNameAndValue.split("=");
if (cookieNameAndValuePair[0].trim().equals("kameleoonVisitorCode"))
{
if (cookieNameAndValuePair[1].matches("^_js_(.*)"))
{
visitorCode = cookieNameAndValuePair[1].substring(4);
}
else
{
visitorCode = cookieNameAndValuePair[1];
}
}
}
}
if (visitorCode == null)
{
final String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
final int alphabetLength = alphabet.length();
final int visitorCodeLength = 16;
final StringBuilder visitorCodeBuilder = new StringBuilder(visitorCodeLength);
for (int i = 0; i < visitorCodeLength; ++i)
{
visitorCodeBuilder.append(alphabet.charAt(java.util.concurrent.ThreadLocalRandom.current().nextInt(alphabetLength)));
}
visitorCode = visitorCodeBuilder.toString();
}

javax.servlet.http.Cookie cookie = new Cookie("kameleoonVisitorCode", visitorCode.substring(100));
cookie.setMaxAge(32_832_000);
cookie.setHttpOnly(false);
cookie.setPath("/");
cookie.setDomain(topLevelDomain);
response.addCookie(cookie);

NodeJS

let topLevelDomain = "MY_DOMAIN";// Here you must provide your own base domain, eg mydomain.com
let visitorCode = null; // Here you can provide your own identifier if needed, else it will be generated randomly

request.headers && request.headers.cookie.split(';').forEach(function (cookie)
{
let cookieNameAndValuePair = cookie.match(/(.*?)=(.*)$/);
if (cookieNameAndValuePair[1].trim() == "kameleoonVisitorCode")
{
let value = cookieNameAndValuePair[2].trim();
if (value.indexOf("_js_") != -1)
{
visitorCode = value.substring(4);
}
else
{
visitorCode = value;
}
}
});
if (! visitorCode)
{
let alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
let alphabetLength = alphabet.length;
visitorCode = "";
for (let i = 0; i < 16; ++i)
{
let randomNumber = Math.floor(Math.random() * alphabetLength);
visitorCode += alphabet[randomNumber];
}
}

let expires = new Date(new Date().getTime() + 32832000000);
response.writeHead(200, {'Set-Cookie': [`kameleoonVisitorCode=${visitorCode}; expires=${expires}; path=/; domain=${topLevelDomain};`]});

PHP

<?php
$topLevelDomain = "MY_DOMAIN";// Here you must provide your own base domain, eg mydomain.com
$visitorCode = NULL; // Here you can provide your own identifier if needed, else it will be generated randomly

if (isset($_COOKIE["kameleoonVisitorCode"]))
{
$value = $_COOKIE["kameleoonVisitorCode"];
if (strpos($value, "_js_") !== false)
{
$visitorCode = substr($value, 4);
}
else
{
$visitorCode = $value;
}
}
if (is_null($visitorCode))
{
$alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
$alphabetLength = strlen($alphabet);
$visitorCode = "";

for ($i = 0; $i < 16; $i++)
{
$randomNumber = floor((mt_rand() / mt_getrandmax()) * $alphabetLength);
$visitorCode .= substr($alphabet, $randomNumber, 1);
}
}

setcookie("kameleoonVisitorCode", $visitorCode, time() + 32832000, "/", $topLevelDomain);
?>

Copy and paste this code, and replace MY_DOMAIN by your base top-level domain (ie, mydomain.com).

C#


Microsoft.AspNetCore.Http.HttpRequest request; // Provide a reference to the HttpRequest
Microsoft.AspNetCore.Http.HttpResponse response; // Provide a reference to the HttpResponse
String topLevelDomain = "MY_DOMAIN";// Here you must provide your own base domain, eg mydomain.com
String visitorCode = null; // Here you can provide your own identifier if needed, else it will be generated randomly

if (request.Cookies.ContainsKey("kameleoonVisitorCode"))
{
String cookieValue = request.Cookies["kameleoonVisitorCode"];
if (cookieValue.Contains("_js_"))
{
visitorCode = cookieValue.Substring(4);
}
else
{
visitorCode = cookieValue;
}
}
if (visitorCode == null)
{
String alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
int alphabetLength = alphabet.Length;
String randomVisitorCode = "";
Random rnd = new Random();
for (int i = 0; i < 16; i++)
{
int randomNumber = rnd.Next(alphabetLength);
visitorCode += alphabet[randomNumber];
}
}

Microsoft.AspNetCore.Http.CookieOptions cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions.CookieOptions();
cookieOptions.Expires = DateTime.Now.AddSeconds(32_832_000);
cookieOptions.HttpOnly = false;
cookieOptions.Path = "/";
cookieOptions.Domain = topLevelDomain;
response.Cookies.Append("kameleoonVisitorCode", visitorCode, cookieOptions);

Python

import random

topLevelDomain = "MY_DOMAIN" # Here you must provide your own base domain, eg mydomain.com

def fill_visitor_code(request, response, customer_visitor_code): # Here you can provide your own identifier via customer_visitor_code if needed, else it will be generated randomly
visitor_code_cookie = request.cookies.get("kameleoonVisitorCode")
if "kameleoonVisitorCode" in request.cookies:
visitor_code_cookie = request.cookies.get("kameleoonVisitorCode")
visitor_code = visitor_code_cookie[4:] if "_js_" in visitor_code_cookie else visitor_code_cookie
else:
visitor_code = customer_visitor_code if customer_visitor_code is not None else "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(16))
response.set_cookie("kameleoonVisitorCode", visitor_code[0:100], max_age=32832000, domain=topLevelDomain)

fill_visitor_code(request, response) # The method must be called with correct arguments (depending on your Python web framework)

Ruby

# Define constants
KAMELEOON_KEY_JS_COOKIE = '_js_'.freeze
KAMELEOON_COOKIE_VALUE_LENGTH = 16
KAMELEOON_COOKIE_NAME = 'kameleoonVisitorCode'.freeze
EXPIRE_DAYS = 365

# Method to generate a random visitor code
def generate_visitor_code(length)
alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'
alphabet_length = alphabet.length
visitor_code = ''

length.times do
random_number = rand(alphabet_length)
visitor_code.concat(alphabet[random_number])
end

visitor_code
end

# Main code
top_level_domain = 'MY_DOMAIN' # Replace with your actual domain
visitor_code = cookies[KAMELEOON_COOKIE_NAME]&.sub(KAMELEOON_KEY_JS_COOKIE, '')

visitor_code = generate_visitor_code(KAMELEOON_COOKIE_VALUE_LENGTH) if visitor_code.nil? || visitor_code.empty?

kameleoon_cookie = {
value: visitor_code,
expires: Time.now + 60 * 60 * 24 * EXPIRE_DAYS,
path: '/',
domain: top_level_domain
}

cookies[KAMELEOON_COOKIE_NAME] = kameleoon_cookie

Back-end SDK

If you're using Kameleoon in Hybrid mode with mixed front-end and back-end environments, it's crucial to ensure user identification consistency. To achieve this, consult the SDK documentation and use the obtainVisitorCode() method. This helper method automatically retrieves the Kameleoon visitorCode for the current visitor.

Using your own CDN or hosting server (self-hosting)

Please note that the Kameleoon application file (kameleoon.js), can be hosted either on the Kameleoon CDN or on your own CDN or servers. If you host it on your own servers, it can offer a slight performance improvement by avoiding an additional DNS query and SSL handshake that is required when using the Kameleoon CDN. Additionally, self-hosting may be preferred for security reasons, as you can ensure compliance with your internal security policies and take responsibility for the security of your hosting servers.

If you want to self-host the Kameleoon application file, see the self hosting documentation.