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).