Skip to content

Instantly share code, notes, and snippets.

/code.js

Created Jul 14, 2017
Embed
What would you like to do?
Optimizely: Persist custom attributes in a cookie
/**
* 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