-
-
Save davidsertillange-optimizely/4a2d9a04e9029f8fbb0ae8b36810ed31 to your computer and use it in GitHub Desktop.
Mirroring Web events in Full Stack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
How to use: | |
Step 1: line 20-26, enter account_id, project_id, Full Stack user_id, environmentKey, and updateDatafile | |
Step 2: make sure your Full Stack project has the events you want to mirror created. | |
The API names need to match between the Web and Full Stack events. | |
Example: on Web, i have a click event "Homepage clicks" with API name "123456790_homepage_clicks" | |
In the Full Stack project, a custom event with the same name "123456790_homepage_clicks" needs to be created for this script to work | |
Step 3: add the script to Project Javascript | |
Step 4: load your page and check the network tab for events going to /events with "client_name": "Optimizely/fswebintegration" | |
The script attaches to every Web event (pageviews, clicks or custom) and dispatches an additional | |
network request with the payload for Full Stack | |
It supports value and revenue metrics | |
It also mirror custom attributes from Web to Full Stack | |
*/ | |
window.FSWebIntegrator = (function() { | |
return { | |
account_id: "", // Optimizely Account ID | |
project_id:"", // project ID where the full stack events need to be dispatched to | |
user_id:"", // add the Full Stack UserID | |
endpoint:"https://logx.optimizely.com/v1/events", | |
method:"POST", | |
environmentKey:"", // Full Stack SDK Key | |
updateDatafile:86400 // how often the datafile should be updated (in ms) | |
}; | |
}); | |
window.FSWebIntegrator.getCookie = function(cname) { | |
var name = cname + "="; | |
var decodedCookie = decodeURIComponent(document.cookie); | |
var ca = decodedCookie.split(';'); | |
for(var i = 0; i <ca.length; i++) { | |
var c = ca[i]; | |
while (c.charAt(0) == ' ') { | |
c = c.substring(1); | |
} | |
if (c.indexOf(name) == 0) { | |
return c.substring(name.length, c.length); | |
} | |
} | |
return null; | |
}; | |
// Send Full Stack by mirroring Web event | |
window.FSWebIntegrator.sendFullStackEvent = function(event) { | |
// Parse datafile and get event ID-name map | |
var datafile = JSON.parse(localStorage.getItem('OptlyDatafile') || '{}'); | |
var eventMap; | |
if(datafile.hasOwnProperty('events')) { | |
eventMap = datafile.events.map(function(DatafileEvent) { | |
return { | |
id:DatafileEvent.id, | |
key:DatafileEvent.key | |
}; | |
}); | |
} | |
buildEventPayload(event, eventMap, window.FSWebIntegrator().user_id); | |
dispatchNetworkEvent(); | |
function findEntityId(event_name, eventMap) { | |
return eventMap.filter(function(event) { | |
if(event_name === event.key) { | |
return true; | |
} | |
}).map(function(event) { | |
return event.id; | |
}).join(); | |
} | |
function dispatchNetworkEvent() { | |
var Http = new XMLHttpRequest(); | |
Http.open(FSWebIntegrator().method, FSWebIntegrator().endpoint); | |
Http.send(JSON.stringify(this.body)); | |
Http.onreadystatechange = function(e) { | |
}; | |
// todo: handle event failure | |
Http.onerror = function(e) { | |
console.log(e); | |
}; | |
} | |
function buildEventPayload(event, eventMap, user_id) { | |
// We copy the web attributes | |
if(optimizely.get('visitor').hasOwnProperty('custom')) { | |
var attributes = Object.entries(optimizely.get('visitor').custom).map(function(entry) { | |
return { | |
entity_id: null, // entity_id set to null as web snippet doesn't expose attribute ID | |
key: entry[0], | |
type:"custom", | |
value: entry[1].value | |
} | |
}) | |
} | |
// Support for bot filtering | |
var attributes = attributes || []; | |
attributes.push( | |
{ | |
entity_id: "$opt_bot_filtering", | |
key: "$opt_bot_filtering", | |
type:"custom", | |
value: false | |
} | |
); | |
this.body = { | |
"account_id": FSWebIntegrator().account_id, | |
"project_id":FSWebIntegrator().project_id, | |
"revision":"100", | |
"visitors": | |
[ | |
{ | |
"visitor_id":FSWebIntegrator().user_id, | |
"attributes": attributes, | |
"snapshots": [ | |
{ | |
"decisions": [], | |
"events": [ | |
{ | |
"entity_id": findEntityId(event.data.name, eventMap), | |
"key": event.data.name, | |
"timestamp": Date.now(), | |
"uuid":Date.now().toString(), | |
"revenue":event.data.metrics.hasOwnProperty("revenue") ? event.data.metrics.revenue : 0, | |
"value":event.data.tags.hasOwnProperty("value") ? event.data.tags.value : 0 | |
} | |
] | |
} | |
] | |
} | |
], | |
"anonymize_ip": true, | |
"client_name": "Optimizely/fswebintegration", | |
"client_version": "1.0.0", | |
"enrich_decisions": true | |
}; | |
return this; | |
} | |
}; | |
window.FSWebIntegrator.onActivated = function() { | |
// Full Stack integration check for datafile existence + last fetch | |
var lastFetch = localStorage.getItem('OptlyDatafileFetch') || 0; | |
if(Date.now() - lastFetch > FSWebIntegrator().updateDatafile) // if datafile is older defined interval | |
{ | |
// Get datafile to map entity_id | |
var xhttp = new XMLHttpRequest(); | |
xhttp.onreadystatechange = function() { | |
if (this.readyState == 4 && this.status == 200) { | |
// Typical action to be performed when the document is ready: | |
var datafile = JSON.parse(xhttp.responseText); | |
if(datafile.hasOwnProperty('events')) { | |
localStorage.setItem('OptlyDatafile', JSON.stringify(datafile)); | |
localStorage.setItem('OptlyDatafileFetch', Date.now()); | |
} | |
} | |
}; | |
xhttp.open("GET", "https://cdn.optimizely.com/datafiles/"+FSWebIntegrator().environmentKey+".json", true); | |
xhttp.send(); | |
} | |
// Future Web integration / we map the events so we can track without the Web snippet (future feature) | |
var optimizelyData = optimizely.get('data'); | |
if(optimizelyData.hasOwnProperty('events') && optimizelyData.hasOwnProperty('pages')) { | |
localStorage.setItem('OptlyWebData', JSON.stringify(Object.assign(optimizelyData.events,optimizelyData.pages))); | |
} | |
} | |
// Initialize the integration | |
window["optimizely"] = window["optimizely"] || []; | |
window["optimizely"].push({ | |
type: "addListener", | |
filter: { | |
type: "lifecycle", | |
name: "activated" | |
}, | |
handler: window.FSWebIntegrator.onActivated | |
}); | |
// For every webevent, dispatch it to FullStack | |
window["optimizely"] = window["optimizely"] || []; | |
window["optimizely"].push({ | |
type: "addListener", | |
filter: { | |
type: "analytics", | |
name: "trackEvent" | |
}, | |
handler: window.FSWebIntegrator.sendFullStackEvent | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment