Web activity tracking
Here we'll go through all aspects of web activity tracking.
Introduction to web activity tracking
Web activity tracking in Engage is the online tracking of a contact's website activity. Using cookies, it allows the activity of both anonymous and identified contacts to be tracked.
Reading this guide will help you to understand about:
Identification and cookies
Abandoned carts
Product views
Identification and cookies
The foundation of web activity tracking is identification and cookies. A contact can be identified through the script in three ways:
An email link (sent from Engage) that takes them to the website.
Being identified by the website by, for example, signing in, in which case the method setContactId() is called.
Being identified by an exiting _vaI cookie, previously set by the Voyado script.
The script, once implemented, will generate a unique client ID and store it in a first-party cookie named _va. All web activity on that browser will then be linked to that client ID via the cookie. When that user clicks on a link in an email from Engage, the tracking script reads the contact ID from the URL (vtid) and stores it in a cookie named _vaI. With this method, all web activity can be connected to a specific contact in Engage.
Read more about identification here.
Abandoned cart
The tracking script enables abandoned cart functionality. By registering every state of a user’s cart, Engage is able to receive information about cart abandonment and use this to trigger automation workflows.
How to get started:
Configure a product feed, read more here.
Implement the tracking script, read more here.
Track cart changes, read more here.
If you want to learn more about abandoned cart from a user's perspective, check out Help Center.
Abandoned browse
The tracking script enables abandoned browse functionality, in the same way as abandoned cart. The site sends product view and cart events to Engage through the tracking script (or the API if the user has been identified). Using this Engage can detect when a session is abandoned and nothing has been added to the cart and then trigger an automation.
How to get started:
Implement everything for Abandoned cart, see above
Track product views, including locale read more here.
If you want to learn more about abandoned browse from a user's perspective, check out Help Center.
Products of interest
By tracking which products a user interacts with, Engage can calculate a list of products of interest. This can then be used in, for example, segmentations. This data will also be a part of the algorithm that calculates Engage's product recommendations.
Configure a product feed, read more here.
Implement the tracking script, read more here.
Track product views, read more here.
Important
Products of interest are connected to the article register, and not to the product feed.
Setting up the tracking script
This article will show you how to configure and implement the Voyado Engage tracking script.
What is a tracking script?
A tracking script allows you to gather behavioral data such as cart changes and product views from website visitors. It consists of a small snippet of code, usually as JavaScript, placed in the HTML source code of a website. The tracking script is required for using features like abandoned cart and products of interest. The tracking script should not be confused with tracking parameters attached to the URL.
Once the script is implemented it will generate a unique client ID and store it in a first-party cookie named _va. All web activity on that browser is then linked to that client ID via the cookie. When that user clicks on a link in an email from Engage, the tracking script reads the contact ID from the URL (vtid) and stores it in a cookie named _vaI. With this method, web activities can be connected to a specific contact in Engage.
Caution
Note that the string "_vaI" is _va followed by an uppercase letter I (as in Ingemar) which can be difficult to make out in some fonts (like this one).
Configuring the tracking script
This is the Voyado tracking script:
<script> (function (i, s, o, g, r, a, m) { i['VoyadoAnalyticsObject'] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date(); a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, 'script', '[SCRIPT-PATH]', 'va'); va("setTenant", "[TENANT-ID]"); </script>
Two things need to be changed here before you can use it, [SCRIPT-PATH] and [TENANT-ID].
[SCRIPT-PATH]
This is the path to the JavaScript analytics package. There are just two options you can use, depending on if you are running in the staging or production environment.
For the production environment, change [SCRIPT-PATH] to:
https://assets.voyado.com/jsfiles/analytics_0.1.7.min.js
And for the staging environment [SCRIPT-PATH] will be:
https://assets.voyado.com/jsfiles/analytics_0.1.7.staging.min.js
Note that analytics_0.1.7 refers to the latest version but can be changed to whatever version you need.
[TENANT-ID]
This string is your unique client (tenant) ID and is the same in production and staging. It is usually the subdomain name in *.voyado.com. For instance, the [TENANT-ID] for supershop.voyado.com would just be "supershop".
Contact your Voyado Engage team if you are unsure about this.
Once you know these two values, you can put them in to configure your tracking script.
Here's an example of how it looks when it is configured.
<script> (function (i, s, o, g, r, a, m) { i['VoyadoAnalyticsObject'] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments) }, i[r].l = 1 * new Date(); a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m) })(window, document, 'script', 'https://assets.voyado.com/jsfiles/analytics_0.1.7.min.js', 'va'); va("setTenant", "supershop"); </script>
Implementing the tracking script
The tracking script can now be placed as it is (implemented in code) on your website, or implemented through a tag manager such as Google Tag Manager (GTM).
A. Implemented in code
Copy your configured code snippet and paste it right after the <head> tag in the HTML page of each page on your website. It's vital, on every page it's used, that the script is initiated and always running, so that it can catch all relevant interactions like cart changes and productviews (through the script's cart and productview methods).
B. Implemented through Google Tag Manager
Follow the steps below:
Log into your Tag Manager.
Select "New Tag".
Name your Tag something easily recognizable.
Open “Tag configuration” and select “Custom HTML” as tag type.
Copy and paste your configured tracking script into the box.
Open ”Triggers” and select the trigger “All pages” (recommended).
Save your Tag.
Publish the new version of your Tag container.
Important
The tracking script can identify which user has arrived via an email link and is therefore required on all pages on your site, including non-product and other landing pages. Make sure the script is implemented on all pages or you risk the user not being identified.
Server-side cookie support
To increase the identification rate for Safari browsers, cookies can be created server-side. The latest script version (0.1.7) supports this. See this article to read more and see how to adjust your implementation.
Identification and cookies
This article will help you understand:
The setContactId() function
Identification through clicking a link in an email
Identification on-site
Best practices concerning cookies and identification
Important steps to ensure during implementation
Identification
Identification means linking a user to a contact ID in Engage. When a user is identified, it's then possible to build an understanding of their behavior on the site and offer a personalized experience and more relevant communication.
Common situations when a visitor is identified are:
A contact registers as a newsletter subscriber
A contact registers for a loyalty program
A contact logs in
A contact completes a purchase
A contact uses a soft identification
Using setContactId() on identified users
As soon as a visitor is identified by the site (see the common cases listed above) the setContactId() method should be invoked.
Keep in mind the visitor might already be identified (such as by an email link click), and invoking this method incorrectly might clear the existing identification. The function setContactId() will not generate a HTTP request to the Collect endpoint.
Param | Type | Description |
---|---|---|
*contactId | string | Voyado Engage contact id |
va("setContactId", "contactId");
Identified and non-identified tracking events
From when a contact is identified, all upcoming tracking events from the same browser are linked to them. This applies until the first-party cookie disappears or changes (for example, when another user logs into the site from the same browser). Voyado recommends that the e-com always includes the contactId in all tracking events such as cart() and productview().
Regardless of whether the contact is identified or not, all tracking events are always linked to the browser via a first-party cookie. That means anonymous tracking events can be linked to a contact ID afterwards, and the e-com site should not limit tracking events such as cart() and productview() to only identified or logged-in users.
List of relevant cookies
Name | Content | Example | Life span* |
_va | Client ID. Generated by the script and links all events to a specific contact. | VA671.1135834162 | 1 year |
_vaI | Contact ID (guid/shortguid). If the contact is identified in Engage this links events to them. | a8tPsy8eqUm-yKoeAMPv7Q | 1 year |
*In Safari, the lifespan of all cookies created with JavaScript is a maximum of 7 days, but this can be extended using server-side cookies (see below).
Important
The final character in _vaI is an upper-case I as in igloo. This can be hard to see in certain fonts.
Important to remember during implementation
Call setContactId() only when the user is identified by the site.
As soon as the site knows who the user is (for instance after login), setContactId() must be called with the user’s contactId. Likewise, when using the soft identification in links to sites implementing the tracking script, make sure to set the contactId from the decrypted eClub query parameter. The function should never be called with zero, empty (no value) or other invalid value, as this could potentially reset an existing identification.
Support for server-side cookies
The cookie _vaI (which stores the contactId) is created client-side by the script. With Apple ITP (Intelligent Tracking Prevention) all client-side cookies (and LocalStorage) have a capped lifetime (of 7 days) in Safari. Which means that when an identified visitor doesn't revisit the site within 7 days, the cookie will expire and the script won't be able to identify the visitor using the _vaI cookie.
The cookie lifetime cap applies only to cookies created client-side (with Safari) and doesn't affect server-side created cookies. The tracking script now supports copying the value from a cookie _vaI_server created server-side as a fallback to recreate the client-side cookie _vaI.
The cookie _vaI will be recreated, if needed, in this specific order:
The site invokes setContactId() or includes contactId in an event
The URL param vtid exists
The LocalStorage key vtid exists
The cookie _vaI_server exists
By implementing _vaI_server identified visitors will stay identified when returning even after 7 days have passed. To implement this, the site (server-side) should check if the request includes a _vaI cookie. If so, the site should copy the value to a new cookie _vaI_server, giving it a 1-year expiration date, and add it to the response.
An example in C#:
if(HttpContext.Request.Cookies.TryGetValue("_vaI", out var contactId) && !string.IsNullOrWhiteSpace(contactId) && contactId != "undefined") { var option = new CookieOptions { Expires = DateTimeOffset.Now.AddYears(1), HttpOnly = false }; HttpContext.Response.Cookies.Append("_vaI_server", contactId, option); }
Tracking cart changes
Cart changes can be tracked either with the Voyado Engage tracking script or the tracking API. Engage can trigger abandoned cart communication to be sent to identified contacts. To enable this, Engage need to know:
Every update of every unique shopping cart
The contactId of the visitor
There are two methods to consider when tracking cart changes:
cart(): Used for registering visitor actions related to any cart modification
emptyCart(): Used for pruning the cart of all items, usually when indicating a purchase or logout by the e-com visitor
Data flow
This is how the flow looks:
The site submits shopping cart changes, either via the tracking script implemented on the e-com site or through the tracking API.
Carts containing products that haven't been accessed for at least 30 minutes are considered abandoned. If the cart is connected to a specific contact it will be sent to Engage. All other carts will be filtered out.
Engage then triggers the relevant automation (based on language/locale).
Cart automation requirements
The following are required so that an abaondoned cart automation can be triggered:
The locale must match a product feed in Engage and the corresponding language is set in an automation.
The SKU/SKUs must match products in the product feed (commonly “g:id”). If a SKU doesn’t match the feed, that particular product will not be included in the email. If no SKUs match the products in the feed the automation won't be triggered at all.
No products in the cart have been purchased (meaning no transaction has been sent to Engage) since the cart was identified as abandoned (although this can be overruled when configuring the trigger).
Using the tracking script
Here is how to use the tracking script to track cart changes.
The cart() method
Invoke this method every time the cart is changed (items added/removed or the quantity updated) regardless of if the user has been identified by the website or not. The cart() method will then generate a HTTP POST request to the Collect endpoint.
Field | Type | Description |
*cartRef | string | Cart identifier, must be unique for each cart |
cartUrl | string | URL to the cart |
contactId | string | Engage contact ID, cookie _vaI will be used as fallback |
*locale | string | Locale for the site where the cart is (example sv-SE). Format as defined by IETF language tag. Only locales with a Product Feed assigned in Engage can trigger an abandoned cart automation |
*items | Array<object> | The array of items added to the cart |
*items[].itemId | string | Item ID (SKU in Engage) |
*items[].quantity | int | The number of items |
Fields marked with * are mandatory
This is what a cart update looks like in code:
va("cart",{ "cartRef":"354354", "contactId":"afa7625d-2e97-4667-b4c1-ad3b01194bee", "cartUrl":"https://www.store.se/cart?id=354354", "locale":"sv-SE", "items": [{ "itemId": "456436", "quantity": 2, }, { "itemId": "456437", "quantity": 2, }] }); <!-- Adds two products in the cart-->
The emptyCart() method
Invoke this method when the cart has been emptied, either manually by the user or when the checkout process has been completed. This method is equivalent to invoking cart() with no items. It’s important to invoke emptyCart() after each successful checkout to avoid faulty abandoned cart communications.
The emptyCart() method will generate a HTTP POST request to the Collect endpoint.
Field | Type | Description |
---|---|---|
*cartRef | string | Cart identifier |
contactId | string | The contact's Engage ID |
Fields marked with * are mandatory
This is how a call to emptyCart() looks in code:
va("emptyCart",{ "cartRef": "354354"} );
Using the tracking API
It's possible to submit cart changes directly via the API instead of implementing the tracking script. If you choose this approach, it is important to identify all contacts that come to the e-com via links in emails (add “vtid” in “contactId”). The calls can be tested through your OpenAPI (Swagger) page.
[tenantname].voyado.com/api/v3/ui/index#/tracking
Read more about the Engage API and your OpenAPI page here.
Important points when tracking cart changes
All behavioral data can be used to build understanding and insights. A shopping cart belonging to an anonymous user can still be linked to a contact after they are identified.
Important
If the user is identified / logged in, both the “cart()” script method and the Carts API can be used to track their behavior. For anonymous users, however, only the “cart()” script can be used. This is because the tracking API always requires the contactId.
Cart updates: Call the “cart()” script method (for identified and anonymous users) or the Carts API (for identified users only) for all updates to the shopping cart, regardless of where on the site or at what stage the cart update takes place (product page, popup or checkout). Engage handles the shopping cart based on its latest change. It is therefore important that all changes generate a call to “cart()” or the Carts API and that the data corresponds to the shopping cart currently displayed on the website.
cartRef: The “cartRef” value must be unique and must not be shared between different baskets or users. A "cartRef" of a specific shopping cart must not be changed, and all updates regarding a shopping cart must use the same "cartRef" value.
Empty carts: Use “cartRef” for empty carts as well. Even empty carts need a cart reference.
Important
Make sure to call “cart()” script method or the Carts API only when the cart is updated. Doing it at other times risks polluting your data in Engage.
Locale: Call the “cart()” script method or Carts API with a “locale” value corresponding to the locale of your Product Feed in Engage. In order to enrich the products with article data, a Product Feed for that locale needs to be set up in Engage. An automation using that locale also needs to be active.
Abandoned carts: All carts not emptied before the website visitor leaves, or makes a purchase, risk being marked as abandoned. If you have an abandoned cart automation active that will be triggered by those unemptied carts.
Tracking product views
By tracking product views, Engage can:
Trigger abandoned browse automations
Build audiences based on products of interest
Get improved product recommendations
Ways to track product views
Product views can be tracked through:
The Voyado tracking script
The tracking API
When tracking product views, the JavaScript method used is productview().
Features built on product views
The following features in Engage are enabled by the tracking of product views.
Abandoned browse
The site submits product views, which are part of a session, either via the tracking script implemented on the e-com site or through the tracking API.
Sessions without activity for at least 30 minutes are considered abandoned. If the session doesn’t contain any cart event, and the product views are connected to a specific contact, it will be sent to Engage. All other sessions will be filtered out. A session can only be sent to Engage once.
All product views sent to Engage are enriched with data from the product feed.
Engage then triggers the relevant automation, based on the specific trigger configurations. If automations contain email activities those can include dynamic product data enriched from the product feed.
Read more about abandoned browse here.
Products of interest
The site submits product views, which are part of a session, either via the tracking script implemented on the e-com site or through the tracking API.
Engage, using the recency, frequency and other patterns of product views from the last 90 days, calculates up to 25 products which each contact is probably most interested in, based only on their onsite behaviour.
These products are updated using a scheduled job and enriched by the article registry and can then be used in segmentation and as part of a scheduled selection in an automation.
Read more about products of interest here.
Product recommendations
If a contact has products of interest, these will be part of the data used to calculate personal recommendations in Engage. This means that their onsite behaviour (Products of interest) will be combined with all historical purchase and return behavior to present a set of personalized recommendations that can be used in emails.
Read more about Engage product recommendations here.
Abandoned browse automation requirements
The following are required so that an abandoned browse automation can be triggered:
The locale must match a product feed in Engage. Events without a matching product feed will be filtered out.
The SKUs must match products in the product feed (commonly “g:id”). If an SKU doesn’t match the feed, that particular product will not be included in the email. If no SKUs match the products in the feed, the automation won't be triggered at all.
Using the tracking script
Here is how to use the tracking script to track product views.
The productview() method
Invoke this method every time a product is viewed, such as on a product page, whether the user has been identified by the website or not.
Param | Type | Description |
---|---|---|
*categoryName | string | Product category, e.g. “Men / Sweaters / Cardigan” |
*itemId | string | Mapped to SKU in Engage |
contactId | string | The Engage contact ID |
**locale | string | Format as defined by IETF language tag. Should match a product feed locale in Engage and is required for abandoned browse automations. |
Fields marked * are mandatory and ** is also mandatory when using abandoned browse.
This is what a call to the productview() method looks like:
va("productview", { "categoryName": "Women / Armour / Greaves", "itemId": "123XYZ", "contactId":"afa7625d-2e97-4667-b4c1-ad3b01194bbb", "locale":"sv-SE" })
Important points when tracking product views
Call productview() in all cases, regardless of whether the user is anonymous/identified or logged in.
All behavioral data can be used to create insights. A product view belonging to an anonymous user can be linked to a specific user after the user is identified.
Call productview() for all product views and with an itemId that matches SKU in Engage.
A product view can be a visit to a product page but can also be anything else that shows a selected product to the user, for example a “quick look” in a popup. The product/itemId will be matched against the SKU in Engage and enriched with product and transaction data. A product page can call productview() multiple times if it represents multiple SKUs.
Using the tracking API
It's possible to submit product views directly via the API instead of implementing the tracking script. Keep in mind that a lot of functionality that exists out-of-the-box when using the script has to be handled by the retailer.
Identification
It's important to identify contacts that enter the e-com from a link in a newsletter by reading the encrypted JSON that is sent in the link's query string. This contains the information needed to identify the contact. Only identified product views can be registered via API (since the contactId is required).
SessionID
A product view is part of a session, identified by sessionId, which is required for abandoned browse. This is handled automatically by the tracking script, but when using the API the sessionId has to be included in all calls.
Read more about the Engage REST API here or go directly to the Swagger page to try it out.
Use cases
When the user enters the e-com via a link from a newsletter
The user clicks a link to the e-com in an email newsletter sent out from Engage.
The link is decorated with vtid (contact ID).
The user views a specific product and invokes productview()
Populate categoryName with the current product category (e.g. “categoryName”: ”Computer accessories > Printers > Toners”)
Populate itemId with the current product SKU (e.g. "itemId": "549852″)
Populate locale based on the current language/market of the site (e.g. “locale“: “sv-SE“)
Populate contactId with the users contact id from Engage, vtid is used as fallback
When the user enters the e-com unidentified
An unidentified user browses into the e-com
The user views a specific product, invoking productview()
Populate categoryName with the current product category (e.g. “categoryName”: ”Computer accessories > Printers > Toners”)
Populate itemId with the current product SKU (e.g. "itemId":"549852″)
Populate locale based on the current language/market of the site (e.g. “locale“: “sv-SE“)
Do NOT populate contactId
When the user enters a product display page (PDP) with multiple SKUs/colors/variants
Avoid sending a productview for each size when the customer visits a product page and instead send a product view when a specific size/colour/variant is picked.
If you want to track the view no matter the variant, then send a random SKU from the PDP, or, as a last resort, send all variants.
Caution
If all variants are sent, you risk triggering abandoned browse emails containing many variants of the same product.
Verification and common issues
Here's how to deal with a few common situations and issues connected to web tracking.
Verifying that the tracking script is working
Go to your e-com site.
Open the JavaScript/developer console and go to “Sources”.
Search for “analytics” and make sure you are using the latest script version.
Go to "Application" → Cookies → the site that has implemented the tracking.
If you are logged in/identified, look for the _val cookie. If you aren’t logged in/identified look for a _va cookie.
Tracking script implementation checklist
Verify that the tracking script is also loaded on non-product pages, such as the landing page.
If an email link leads to a page that does not have the tracking script, the contact identification could fail.
Verify that no empty events are sent on page load/page navigation.
Verify that events are sent when you are anonymous and that the cookie does not exist.
Engage can connect anonymous events to a user after they have been identified.
Verify that events are sent when a contact is identified via an email link and that the _vaI cookie is set correctly.
The user can be identified without being logged in.
Verify that events are sent when you are identified via login and that the _vaI cookie is set correctly.
When the user identifies himself via login, the site must set the _vaI cookie with the setContactId() function. Verify that events are sent when you are identified via login and that the _vaI cookie is set correctly. When the user identifies themselves via login, the site must set the _vaI cookie with the setContactId() function.
Verify that the cookie _vaI is set correctly with and without a trailing slash in the URL.
Test with the slash: www.site.se/?vtid=LTq-P1eRKU2s8CWc5KPe5w
And without slash: www.site.se?vtid=LTq-P1eRKU2s8CWc5KPe5w
Navigate further into the site to verify that _vaI is not cleared.
Verify that the cookie _vaI is updated with a new vtid.
Try first setting vtid to "a4fa7a46-23b0-4523-b09c-5462053e7627" and then changing it to "3fbe3a2d-9157-4d29-acf0-259ce4a3dee7".
Verify that sessionid is set in the payload. The abandoned browse trigger will not work if this is not set.
Verify tracking of product views
Here's how to verify that tracking of your product views is working.
Go to your e-com site.
Open the JavaScript/developer console, go to "Networks", and select the Fetch/XHR tab.
Visit any random product on the site.
You should now see a call made to the Collect endpoint.
In the payload, the te value should be your tenants/account name. Note that Locale does not have to be the same as the cart payload, and is not used in to identify anything.
When viewing a product, the t (type) value should be "productview", as pictured below.
If you are logged in/identified, click on the payload and make sure the ci value is the same ID as in the _val cookie mentioned above. The value of ci should not be anything other than the ID.
Product of interest implementation checklist
Make sure itemId matches SKU
In order to track if a purchase followed after the last product view, the itemId from the product view is matched against the SKU in the article registry that is included on the receipt.
Verify that sessionid is set in the payload. The abandoned browse trigger will not work if this is not set.
Verify that the same events are not sent multiple times
A product page should trigger a productview event for each itemId/SKU. If several productview events are triggered, they must be for different itemId/SKU.
Verify productview event when navigating to product page in different ways
There are usually different ways to navigate to a product page, for example via the landing page, checkout, another product page, the menu, the shopping cart. For sites that are built as SPAs, no full page loading is done, which can cause inconsistent functionality.
Verify tracking cart changes
Go to your e-com site.
Open the JavaScript/developer console and go to "Networks" and select the Fetch/XHR tab.
Place an item in the cart.
You should now see a call made to an endpoint named Collect.
In the payload, the t (type) value should be "cart". Note the items[] array which may include products you’ve placed in your cart.
If possible, complete the purchase / check out the cart.
At this point a new Collect event should be fired with an empty cart indicating that the purchase has been made.
Cart tracking implementation checklist
Verify that cart events are sent with the correct language/locale.
A shopping cart must have a language/locale that matches a Product Feed and the language version of the site (if it is a multimarket site).
Verify cart event before checkout.
Try updating the shopping cart in different ways (add item, remove item, change quantity, emptying). Is the quantity updated when the same item is added for the second time? What happens when you remove the last item? There are usually different ways to update the shopping cart, e.g. on the product page, popup. Sites built as SPAs tend to have inconsistent functionality.
Verify cart event in checkout.
Try updating the shopping cart on the checkout page, since the functionality on the checkout page usually differs from the rest of the site. Is there a difference between when you change the quantity to zero and remove the item? What happens when all items are removed? Is it possible to add new items from checkout? Does it differ between with/without vtid?
Verify that no incorrect events are sent when entering and exiting checkout.
What happens when you go in and out of the checkout and update the shopping cart on "both" pages?
Common implementation errors
Cart event is not sent for every update.
Every update of the cart needs to generate a cart event to the Collect endpoint. This includes updates such as add/remove product, update quantity, empty cart. These updates can occur in different contexts (product page, cart popup/sidebar, checkout, etc) and function differently.
Different cartRef for the same cart.
The cartRef value must be unique per cart and have to stay persistent for all cart-events, it cannot change between updates. Invalid cartRef on remove product and empty cart are common problems.
Multiple cart/productview events.
Make sure that a cart update only generates a single cart event and that non-cart actions (e.g. page loads) don't generate any additional cart events. A visit to a product page should not generate more than one productview event per unique SKU (multiple SKUs with corresponding events on a single product page is fine).
Common implementation errors related to identification
Clearing the _vaI cookie when it is set with vtid.
The _val cookie is set with vtid when the user is identified by e-mail. Do not invoke setContactId() with an invalid value (such as empty or null) when the user is not signed in, since the user might already be identified without being signed into the website.
The _val cookie is not set when link in e-mail ends with slash (/).
Some websites remove (redirect/rewrite) the ending slash from URLs without the querystrings being preserved. This might cause _vaI to not be set if the link in an Engage e-mail contains an ending slash.
For example:
www.mysite.com/myproduct/?vtid=uaz2QuT9NEez_eAsr8hEeQ
might be changed to:
www.mysite.com/myproduct
No cart/productview events before checkout or sign in.
Do not limit cart/productview events only to the checkout page only, or only to signed in/identified users.
Support for server-side cookies
The cookie _vaI (which stores contactId) is created client-side by the script. With Apple ITP (Intelligent Tracking Prevention) all client-side cookies (and LocalStorage) have a capped lifetime (7 days) in Safari. Which means when an identified visitor doesn't revisit the site within 7 days the cookie will expire and the script wont be able to identify the visitor using the _vaI cookie.
The cookie lifetime cap applies only to cookies created client-side (with Safari) and doesn't affect server-side created cookies. The tracking script now support copying the value from a cookie _vaI_server created server-side as a fallback to recreate the client-side cookie _vaI.
The cookie _vaI will be recreated, if needed, in this specific order:
The site invokes setContactId or includes contactId in an event
The URL param vtid exists
The LocalStorage key vtid exists
The cookie _vaI_server exists
By implementing _vaI_server identified visitors will stay identified when returning even after 7 days have passed. To implement this, the site (server-side) should look if the request includes a _vaI cookie. If so the site should copy the value to a new cookie _vaI_server, giving it a 1-year expiration date, and add it to the response.
An example in C#:
if(HttpContext.Request.Cookies.TryGetValue("_vaI", out var contactId) && !string.IsNullOrWhiteSpace(contactId) && contactId != "undefined") { var option = new CookieOptions { Expires = DateTimeOffset.Now.AddYears(1), HttpOnly = false }; HttpContext.Response.Cookies.Append("_vaI_server", contactId, option); }