Skip to content

Instantly share code, notes, and snippets.

@rzubek
Last active December 17, 2015 08:49
Show Gist options
  • Save rzubek/5583039 to your computer and use it in GitHub Desktop.
Save rzubek/5583039 to your computer and use it in GitHub Desktop.
Simple and very rough AS3 hookup for Google Analytics. It's limited in scope, but it's tiny and requires no external libraries.
package
{
import flash.display.Stage;
import flash.events.HTTPStatusEvent;
import flash.events.IOErrorEvent;
import flash.events.TimerEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.Capabilities;
import flash.utils.Timer;
import Logger; // NOTE: REPLACE WITH YOUR OWN LOGGER CLASS :)
/**
* Simple interface to the Google Analytics service.
*
* <p> Usage example:
* <ul>
* <li>tracker.initialize(...);
* <li>tracker.log("my", "path", "elements");
* </ul>
*/
public class GATracker
{
private static const GA_VERSION :String = "5.4.2";
private static const ENCODING :String = "UTF-8";
private var _id :Identity;
private var _queue :Array;
private var _queueTimer :Timer;
private var _queueTimerDelayMs :int = 500;
private var _stage :Stage;
private var _settings :GATrackerSettings;
private var _urlConstants :String;
private var _cookieTimestamp :String;
/**
* Initializes a new tracker.
*
* @param stage Reference to the Stage instance
* @param settings Instance of GATrackerSettings
*/
public function initialize (stage :Stage, settings :GATrackerSettings) :void
{
_stage = stage;
_settings = settings;
var now :Date = new Date();
_cookieTimestamp = String(uint(now.getTime() / 1000));
_urlConstants =
"utmac=" + _settings.id +
"&utmwv=" + GA_VERSION +
"&utmn=" + makeRandomNumber() +
"&utmcs=" + ENCODING +
"&utmsr=" + Capabilities.screenResolutionX + "x" + Capabilities.screenResolutionY +
"&utmvp=" + _stage.stageWidth + "x" + _stage.stageHeight +
"&utmul=" + makeLanguageString() +
"&utmfl=" + makeFlashVersionString() +
(_settings.proxied ? "&utmip=___IP___" : "") +
"&utmr=-";
_queue = [];
_queueTimer = new Timer(_queueTimerDelayMs);
_queueTimer.addEventListener(TimerEvent.TIMER, onQueueTimer);
_queueTimer.start();
}
/** Release all resources */
public function release () :void {
_queueTimer.stop();
_queueTimer.removeEventListener(TimerEvent.TIMER, onQueueTimer);
_queueTimer = null;
_queue.length = 0;
_queue = null;
_settings = null;
_stage = null;
}
public function get identity () :Identity { return _id; }
/** Resets tracking identity. Subsequent tracking will look like it's coming from a different visitor. */
public function reset () :void {
_id.clear();
}
/**
* Main logging function. Each argument will be converted into its own URL path element.
* For example, "log(1, 2, 3)" will be logged as the path "/1/2/3".
*/
public function log (... params) :void {
_queue.push(params);
}
/** Consumes items from the queue */
private function onQueueTimer (e :TimerEvent) :void {
if (_queue.length == 0) {
return; // nothing to do
}
var params :Array = _queue.shift();
lazyInitializeIdentity();
var url :String = makeUrl(params);
if (_settings.debug) {
Logger.debug("ANALYTICS URL: " + url);
}
var req :URLRequest = new URLRequest(url);
var loader :URLLoader = new URLLoader();
if (_settings.debug) {
loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, onHttpStatus, false, 0, true);
loader.addEventListener(IOErrorEvent.IO_ERROR, onIoError, false, 0, true);
}
loader.load(req);
}
/** Initializes identity if needed */
private function lazyInitializeIdentity () :void {
// get or make a tracking identity. this needs to happen in a lazy way,
// so that just initializing the tracker (without logging any data)
// won't cause session count to go up.
if (_id == null) {
_id = Identity.load();
if (_id.uid == null) {
_id.initialize();
}
_id.sessions ++;
}
}
private function makeUrl (params :Array) :String {
// URL format documented here:
//
// http://stackoverflow.com/questions/1027660/generate-google-analytics-events-utm-gif-requests-serverside
// https://developers.google.com/analytics/resources/articles/gaTrackingTroubleshooting#gifParameters
var path :String = encodeURIComponent("/" + params.join("/"));
var cookie :String = makeCookieString();
var query :String = "?utmp=" + path + "&" + _urlConstants + "&utmcc=" + cookie;
return _settings.url + query;
}
private function makeFlashVersionString () :String {
try {
var version :Array = Capabilities.version.split(","); // "WIN 11,7,0,0" -> array
var major :Array = String(version[0]).split(" "); // "WIN 11" -> array
var result :String = "" + major[1] + "." + version[1] + " r" + version[2]; // "11.7 r0"
return encodeURIComponent(result);
} catch (e :Error) {
return "unknown";
}
}
private function makeLanguageString () :String {
if (Capabilities.languages != null && Capabilities.languages.length > 0) {
return String(Capabilities.languages[0]).toLowerCase();
} else {
return Capabilities.language;
}
}
private function makeCookieString () :String {
var str :String =
"__utma=" +
_id.gacookie + "." +
_id.uid + "." +
_cookieTimestamp + "." +
_cookieTimestamp + "." +
_cookieTimestamp + "." + _id.sessions + ";+" +
"__utmz=" + _id.gacookie + "." +
_cookieTimestamp + ".1.1." +
"utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);";
return encodeURIComponent(str);
}
private function makeRandomNumber (max :uint = 99999999, min :uint = 10000000) :String {
var n :uint = min + Math.random() * (max - min);
return String(n);
}
private function onHttpStatus (event :HTTPStatusEvent) :void {
Logger.debug("ANALYTICS RESPONSE CODE: " + event.status);
}
private function onIoError (event :IOErrorEvent) :void {
Logger.debug("ANALYTICS IO ERROR: " + event.toString());
}
}
}
package
{
/** Settings object for the tracker */
public class GATrackerSettings
{
private var _id :String;
private var _proxy :String;
private var _debug :Boolean;
/**
* Initializes a new tracker settings object.
*
* @param id Google Analytics ID, like "UA-nnnnnnnn-n"
* @param proxy If not null, this should be the full URL for the stats page.
* If null, we'll use Google Analytics tracker instead.
* @param debug If true, additional debug info will be traced; defaults to false
*/
public function GATrackerSettings (id :String, proxy :String, debug :Boolean)
{
this._id = id;
this._proxy = proxy;
this._debug = debug;
}
public function get id () :String { return _id; }
public function get debug () :Boolean { return _debug; }
public function get proxied () :Boolean {
return (_proxy != null);
}
public function get url () :String {
return (_proxy != null) ? _proxy : "http://www.google-analytics.com/__utm.gif";
}
}
}
package
{
import flash.net.SharedObject;
public class Identity
{
public static const SHARED_OBJECT_KEY :String = "identity";
private var _so :SharedObject;
public function Identity (so :SharedObject)
{
_so = so;
}
public function get uid () :String { return _so.data.uid; }
public function set uid (value :String) :void { _so.data.uid = value; }
public function get gacookie () :String { return _so.data.gacookie; }
public function set gacookie (value :String) :void { _so.data.gacookie = value; }
public function get sessions () :uint { return _so.data.sessions; }
public function set sessions (value :uint) :void { _so.data.sessions = value; }
public function initialize () :void {
this.uid = uint(Math.random() * 10000000).toString();
this.gacookie = uint(Math.random() * 10000000).toString();
this.sessions = 0;
}
public function clear () :void {
_so.clear();
}
public static function load () :Identity {
var so :SharedObject = SharedObject.getLocal(SHARED_OBJECT_KEY);
var id :Identity = new Identity(so);
return id;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment