Custom Variables are quite simple way to remember some additional information related to pageview, visti (session) or visitor. I assume using

The Problem

But there is one unpleasant limitation:
“There is a 64-byte character limit for the name and value combined…”
It means that name and value strings (passed to _setCustomVar(slot, name, value, scope)) together must not exceed 64 characters in URL-encoded form. If you set string with non-ASCII characters, it is encoded. But if the total encoded string lenght exceed 64 chars, custom variables is not recorded (without a visible error!).

 

The only way to check recorded custom variables I found is using Chrome Extension Google Analytics Tracking Code Debugger

The Solution

Step by step

  • get lenght of encoded name + value sring
  • trim encoded value string
  • fix end of the value string if it was cut off in the middle of character sequence representing encoded character
  • decode trimmed value
  • call _setCustomVar() passing trimmed value
    In addition you can convert some non-ASCII characters (e.g. letters with accents) to their ASCII equivalents to reduce string lenght or add a special character to the end of trimmed values.
/**
* Google Analytics Utils
* @class
* @name GAUtils
* @author Miroslav Pecka
*/
var GAUtils = {
/**
* Sets custom variable to given slot (limited to 64 bytes name+value length in URL encoded form)
* @memberOf GAUtils
* @param {Number} slot Slot number (1-5)
* @param {String} name Variable name
* @param {String} value Variable value
* @param {Number} scope Variable scope (1,2,3)
* @param {Boolean} [replaceChars=true] Some characters (with accents etc.) will be replaced with substitution.
* @param {String} [trailingString=""] String appended at the of value if it was trimmed.
*/
setCustomVar : function(slot, name, val, scope, replaceChars, trailingString) {
trailingString = trailingString || "";
replaceChars = (typeof replaceChars == "undefined") ? true : replaceChars;
function le(input) { return encodeURIComponent(input).length };
if ( replaceChars ) {
val = this._replaceChars(val);
};
if ( le(name) + le(val) > 64 ) {
var nameLen = 64 - le(name) - le(trailingString);
var trimmedVal = encodeURIComponent(val).substr(0, nameLen).replace(/(%\w{2})?%\w?$/,"");
trimmedVal += encodeURIComponent(trailingString);
val = decodeURIComponent(trimmedVal);
};
_gaq.push(['_setCustomVar', slot, name, val, scope]);
},
/**
* Convert some character to their mapped replacements 
* @memberOf GAUtils
* @param {String} str String to be converted
* @returns {String} String after with characters replaced
*/
_replaceChars : function(str) {
var before = new Array( /[áäàâãå]/g, /[čćĉ]/g, /[ď]/g, /[éěèêë]/g, /[íìîï]/g, /[ĺľ]/g, /[ňñ]/g, /[óòôö]/g, /[ŕř]/g, /[šśŝ]/g, /[ť]/g, /[úůüùûű]/g, /[ýÿŷ]/g, /[ž]/g, /[ÁÄÀÂÃÅ]/g, /[ČĆĈ]/g, /[Ď]/g, /[ÉĚÈÊË]/g, /[ÍÌÎÏ]/g, /[ĹĽ]/g, /[ŇÑ]/g, /[ÓÒÔÖ]/g, /[ŔŘ]/g, /[ŠŚŜ]/g, /[Ť]/g, /[ÚŮÜÙÛŰ]/g, /[ÝŶŸ]/g, /[Ž]/g);
var after = new Array("a","c","d","e","i","l","n","o","r","s","t","u","y","z","A","C","D","E","I","L","N","O","R","S","T","U","Y","Z");
for (i=0; i<before.length; i++) {
str = str.replace((before[i]), after[i]);
}
return str;
}
};

Usage examples

  • GAUtils.setCustomVar(1,”UserGroup”,”admin”,2); – basic usage (defined characters are replaced by default)
  • GAUtils.setCustomVar(2,”UserName”,”Jan Novák”,2,false); – characters with accents are recorded untouched (default overriden)
  • GAUtils.setCustomVar(3,”UserComment”,”I love your eshop”,3,true,”$”); – defined characters replaced; long trimmed variables ends with $ (user-defined sign of being trimmed)

My solution is similar to Will Critchlow´s approach, but my code works with decriptive variable names (i. e. does not assume only one character name).