Issue Description
As of March 25th, Apple released iOS 12.2 and Safari 12.1 on macOS High Sierra and Mojave. This includes ITP 2.1 (Intelligent Tracking Prevention), which enforces new rules that prevent certain tracking functions in the above-mentioned browsers.
In relation to Convert Experiences, it means that browser-issued cookies now have an enforced duration of seven days. Convert cookies are written exclusively by the browser, so current Convert cookies will be deleted after this seven day period.
In experiment terms, it means that visitors that have been previously bucketed into an experiment will be counted again if they return after seven days. Also, if they convert again after the 7 day period, the new conversion will be counted in the experiment. The default behavior is that Convert counts only the first conversion.
This could affect your experiment results substantially, as the usage of the affected browsers can be large in certain markets like the United States.

Tips
New users who install Firefox for the first time after 5th June 2019 will have Enhanced Tracking Protection (ETP) set on by default. This change will speed up the browser and keep users’ web habits more private, while nudging advertisers toward less invasive practices. Same solution that is described below can also be applied for ETP.

Important
The solutions below require technical expertise to implement.
Solution
As mentioned above, the new cookie duration restrictions are on browser-created cookies and not server-issued cookies. Convert's solution is to issue the cookie that tracks experience data directly from the customer's web server. In this way, the convert script won't have the restrictions imposed by ITP 2.1 on the browser-side.
To facilitate this, we are making available some code snippets to integrate on our customers' web server infrastructure. These code snippets are available for the following platforms: PHP, Node JS HTTP Module, Node JS Express, Ruby and Python.
PHP Code
<?php
$currentTime = time();
$convertCookieName = "_conv_v";
$yourTopDomain = ".example.com";
$defaultCookieData = "vi:1*sc:0*cs:$currentTime*fs:$currentTime*pv:0";
if(isset($_COOKIE[$convertCookieName])) $cookieData = $_COOKIE[$convertCookieName];
else $cookieData = $defaultCookieData;
//set the cookie
setcookie($convertCookieName,$cookieData, $currentTime + 15768000, "/", $yourTopDomain);
?>
Node JS HTTP Module Code
Requires cookie module.
var currentTime = Math.floor(Date.now()/1000);
var convertCookieName = "_conv_v";
var yourTopDomain = ".example.com";
var defaultCookieData = "vi:1*sc:0*cs:"+currentTime+"*fs:"+currentTime+"*pv:0";
var cookieData = defaultCookieData;
if(request.headers.cookie) {
var cookies = cookie.parse(request.headers.cookie);
if(cookies[convertCookieName]) {
cookieData = cookies[convertCookieName];
}
}
response.setHeader('Set-Cookie', cookie.serialize(convertCookieName, cookieData, {
maxAge: 15768000,
path: '/',
domain: yourTopDomain
}));
Node JS Express Code
Requires cookie-parser module required as cookieParser is no longer bundled with Express and must be installed separately.
var currentTime = Math.floor(Date.now()/1000);
var convertCookieName = "_conv_v";
var yourTopDomain = ".example.com";
var defaultCookieData = "vi:1*sc:0*cs:"+currentTime+"*fs:"+currentTime+"*pv:0";
var cookieData = defaultCookieData;
if(request.cookies[convertCookieName]) {
cookieData = request.cookies[convertCookieName];
}
response.cookie(convertCookieName, cookieData, {
maxAge: 15768000 * 1000,
path: '/',
domain: yourTopDomain
});
Ruby Code
currentTime = Time.now.to_i
convertCookieName = "_conv_v"
yourTopDomain = ".example.com"
defaultCookieData = "vi:1*sc:0*cs:#{currentTime}*fs:#{currentTime}*pv:0"
cookieData = defaultCookieData
if request.cookies[convertCookieName]
cookieData = request.cookies[convertCookieName]
end
response.set_cookie(convertCookieName,
:value => cookieData,
:domain => yourTopDomain,
:path => "/",
:expires => Time.at(currentTime + 15768000)
)
Note:
request is instance of Rack::Request
response is instance of Rack::Response
Python Code
import Cookie
import datetime
import os
currentTime = datetime.datetime.now().strftime('%s')
convertCookieName = '_conv_v'
yourTopDomain = '.example.com'
defaultCookieData = 'vi:1*sc:0*cs:'+currentTime+'fs:'+currentTime+'*pv:0'
cookieData = Cookie.SimpleCookie()
if 'HTTP_COOKIE' in os.environ:
cookieData.load(os.environ["HTTP_COOKIE"])
if (convertCookieName not in cookieData) or (not cooieData[convertCookieName].value.strip()):
cookieData[convertCookieName] = defaultCookieData
# Set the cookie
cookieData[convertCookieName]['domain'] = yourTopDomain
cookieData[convertCookieName]['path'] = '/'
cookieData[convertCookieName]['max-age'] = 15768000
print cookieData[convertCookieName].output()
Shopify (or any similar platform where you are prevented from adding any of the above code)
In the case that you are unable to add the required code (such as on Shopify's platform), the solution will be such as the following:
- Create a subdomain of your main domain and host it somewhere.
- Upload one of the scripts mentioned above to the host of the new subdomain. That host would need to support the language the script used, from the ones mentioned in this article. You will need to verify the script is running on the server correctly when called.
- Call the script in Shopify (eg templates, additional scripts, etc.). Tip: You can do it this way: <img src="cookiescript.php" width="0" height="0">.
You will have to store it in the theme.liquid, cart-template.liquid (if possible in your Shopify install).
Contact us through the support channels if you have any questions about the above.
Comments