Created
July 14, 2017 20:36
-
-
Save anonymous/eb7c91960307a1df733bcbc48fe751cd to your computer and use it in GitHub Desktop.
Optimizely: Persist custom attributes in a cookie
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
/** | |
* Persist custom attributes via a cookie | |
* | |
* @param {string} COOKIE_DOMAIN | |
* The value of the `domain` attribute of the cookie. | |
* This should probably be the highest-level domain of your | |
* site (e.g., For 'blog.example.co.uk', use 'example.co.uk'). | |
*/ | |
var AttributePersistor = (function() { | |
/** | |
* SET PARAMETERS HERE | |
*/ | |
var COOKIE_DOMAIN = 'yourcookiedomain.com'; | |
// For maximum compatibility with browsers which implement an | |
// old version of the cookie spec. | |
COOKIE_DOMAIN = ensureLeadingDot(COOKIE_DOMAIN); | |
var CUSTOM_ATTR_COOKIE_NAME = 'optimizelyCorsAttrs'; | |
/** | |
* @param {string} str | |
* @returns {string} | |
* The given string, modified to surely have a leading period. | |
* @private | |
*/ | |
function ensureLeadingDot(str) { | |
return (str[0] === '.') ? str : ('.' + str); | |
} | |
/** | |
* @param {string} cookieValue | |
* Value to be assigned directly to the attributes cookie. | |
* @private | |
*/ | |
function setCookie(cookieValue) { | |
var expDate = (new Date()).setYear(2099); | |
document.cookie = | |
CUSTOM_ATTR_COOKIE_NAME + '=' + cookieValue + | |
';expires=' + expDate + | |
';domain=' + COOKIE_DOMAIN + | |
';path=/'; | |
} | |
/** | |
* @returns {(string|undefined)} | |
* The raw value of the attributes cookie. | |
* @private | |
*/ | |
function getCookie() { | |
var match = document.cookie.match(CUSTOM_ATTR_COOKIE_NAME + '=([^;]*)'); | |
return match ? match[1] : (void 0); | |
} | |
/** | |
* @returns {Object.<string, (string|number)>} | |
* The attributes map currently stored in the cookie, deserialized. | |
* An empty object if the cookie is not set or isn't valid JSON. | |
*/ | |
function getAttributesFromCookie() { | |
try { | |
return JSON.parse(getCookie()); | |
} catch (e) { | |
return {}; | |
} | |
} | |
/** | |
* @param {Object.<string, (string|number)>} attributesToMerge | |
* A map of attributes to be merged into the map | |
* stored in the cookie. | |
*/ | |
function persistAttributes(attributesToMerge) { | |
var merged = Object.assign({}, getAttributesFromCookie(), attributesToMerge); | |
setCookie(JSON.stringify(merged)); | |
} | |
/** | |
* @param {Object} item | |
* @returns {boolean} | |
* True if and only if the object resembles a request to the | |
* `User` JS API containing an attributes payload. | |
*/ | |
function isUserApiPayload(item) { | |
return item instanceof Object && | |
item.type === 'user' && | |
item.attributes instanceof Object; | |
} | |
return { | |
getAttributesFromCookie: getAttributesFromCookie, | |
persistAttributes: persistAttributes, | |
isUserApiPayload: isUserApiPayload, | |
}; | |
})(); | |
window.optimizely = window.optimizely || []; | |
window.optimizely.push({ | |
type: 'addListener', | |
filter: { | |
type: 'lifecycle', | |
name: 'initialized', | |
}, | |
handler: function attributePersistorInitializedHandler(event) { | |
// Merge the attributes stored in the cookie into the snippet's visitor profile | |
window.optimizely.push({ | |
type: 'user', | |
attributes: AttributePersistor.getAttributesFromCookie(), | |
}); | |
}, | |
}); | |
window.optimizely.push({ | |
type: 'addListener', | |
filter: { | |
type: 'lifecycle', | |
name: 'activated', | |
}, | |
handler: function attributePersistorActivatedHandler(event) { | |
// Write any attributes that the snippet read from pre-pushed User API | |
// calls and from this origin's localStorage back into the cookie | |
var snippetAttributes = window.optimizely.get('visitor').custom || {}; | |
var attributeMap = {}; | |
for (var attr in snippetAttributes) { | |
attributeMap[attr] = snippetAttributes[attr].value; | |
} | |
AttributePersistor.persistAttributes(attributeMap); | |
// Shim optimizely.push to have a side effect of persisting any attributes pushed | |
// via it post-initialization. This must occur after initialization, as that's | |
// when the API becomes available to shim. | |
var optlyPush = window.optimizely.push; | |
Object.defineProperty(window.optimizely, 'push', { | |
value: function() { | |
optlyPush.apply(null, arguments); | |
var item = arguments[0]; | |
if (AttributePersistor.isUserApiPayload(item)) { | |
AttributePersistor.persistAttributes(item.attributes); | |
} | |
} | |
}); | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment