Search Unity

Add Google Analytics to your project

Discussion in 'Scripting' started by ElmarKleijn, Aug 4, 2010.

  1. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    Hey everyone,

    Just wanted to share this class which I have used a while now. It allows you to track events and "levels" (normally pages ;)) at Google Analytics.

    Only thing you need is a Google Analytics account and a verified domain. This is just to get the tracking activated, just a one time process.

    The only thing you have to do is to set the account id and optionally the (request) domain in the singleton, and then it's just a one time function call per event. Like logins, registration, etc!

    Download the code on my old-dated but still quite useful website :wink:.

    http://www.persistentrealities.com/code/

    Example:

     
  2. Julian-Glenn

    Julian-Glenn

    Joined:
    Jul 23, 2010
    Posts:
    97
    Hey that's a novel use for Analytic's.
    Well done!

    /tip hat
     
  3. theBrandonWu

    theBrandonWu

    Joined:
    Sep 3, 2009
    Posts:
    244
    This is excellent! I've been thinking about event tracking in the game and can't wait to give this a try. Thanks!
     
  4. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    Kudos to you, Sir. This is useful as hell!
     
  5. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    I did forget to mention that it might take a few hours before the data shows up on your site. Especially if you just added a new domain. :).
     
  6. adriaanza

    adriaanza

    Joined:
    Jun 24, 2010
    Posts:
    41
    So Google and Unity already has a good relationship what with the webplayer being integrated with Chrome. You know, this is the kind of thing that the two should look into themselves and promote - just showing how powerful it can be on the web for game developers and marketing firms/departments.
     
  7. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    a small technical note: I think you should remove the last line from the LogEvent function... the "while ( w.isDone == false ) {};" will cause a lag in program flow - and is quite unneccessary.
     
  8. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    Ah, I likely left it there because of debugging reasons, since I have often looked at the response data. I will remove it later today.
     
  9. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    I adapted the system for .Net 1.1 (iPhone-compatible) and put in an asynchronous call of the LogEvent() function (put it in a coroutine to make it even faster and completely without lag).

    Almar, you interested in the changed code?

    Oh, on another note: could you give some examples for ways to use LogEvent()? Analytics tells me, it's receiving data, but it does not show any counts. Any idea how to fix that?
     
  10. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    Hi azeitler,

    This is what I used to make sure the code really worked before uploading ;).

    GoogleAnalyticsHelper.Instance.Settings("UA-(yourid)", "127.0.0.1"); /// (or possibly domain which hosts the "activated" domain)
    GoogleAnalyticsHelper.Instance.LogEvent("Server", "myGame", "Startup", "",0); // The latter arguments can be used for values and prices for example. ("event value") at GA
    GoogleAnalyticsHelper.Instance.LogPage("DefaultLevel"); /// Actually the current level is used automatically if an empty string is passed
     
  11. Ony

    Ony

    Joined:
    Apr 26, 2009
    Posts:
    1,977
    Does this work for standalone games or just web players?
     
  12. 3Duaun

    3Duaun

    Joined:
    Dec 29, 2009
    Posts:
    600
    @azeitler

    Are you sharing your iPhone adapted code? That would be very cool to test it in a project.
     
  13. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    It should work fine on both, since I am not using any custom DLL's.
     
  14. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    Here is my version of the code. I did some improvements on the memory footprint, removed generics and turned all functionality into static functions.

    I dropped the async-Coroutine as it does not bring any performance-advantage after all, don't know where I got the idea that it would.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. /// Google analytics class v 1.1
    5. /// v1.0 (c) by Almar Joling
    6. /// E-mail: [email]unitydev@persistentrealities.com[/email]
    7. /// Website: [url]http://www.persistentrealities.com[/url]
    8.  
    9. /// Performs a google analytics request with given  parameters
    10. /// Important: account id and domain id are required.
    11. /// Make sure that your site is verified, so that tracking is enabled! (it needs a file to be placed somewhere in a directory online)
    12.  
    13. /// Example usage:
    14. /// One time initialize:
    15. /// Use a different hostname if you like.
    16. /// GoogleAnalyticsHelper.Instance.Settings("UA-yourid", "127.0.0.1");
    17.  
    18. /// Then, for an "event":
    19. ///  GoogleAnalyticsHelper.Instance.LogEvent("levelname", "pickups", "pickupname", "optionallabel", optionalvalue);
    20.  
    21. /// For a "page" (like loading a level?)
    22. /// GoogleAnalyticsHelper.Instance.LogPage("Mainscreen");      
    23.  
    24. /// If you made any improvements please let me know :).
    25.  
    26.  
    27.  
    28. public sealed class GoogleAnalyticsHelper
    29. {
    30.     private static string accountid;
    31.     private static string domain;
    32.    
    33.     private static readonly GoogleAnalyticsHelper instance = new GoogleAnalyticsHelper();      
    34.    
    35.     /// Init class with given site id and domain name
    36.     public static void Settings(string p_accountid, string p_domain)
    37.     {
    38.         domain = p_domain;
    39.         accountid = p_accountid;
    40.     }
    41.  
    42.  
    43.     public static void LogPage(string page)
    44.     {
    45.         LogEvent(page, "","","", 0);
    46.     }
    47.  
    48.     /// Perform a log call, if only page is specified, a page visit will be tracked
    49.     /// With category, action, and optionally opt_label and opt_value, there will be an event added instead
    50.     /// Note that the statistics can take up to 24h before showing up at your Google Analytics account!
    51.     private static Hashtable requestParams = new Hashtable();
    52.     public static void LogEvent(string page, string category, string action, string opt_label, int opt_value)
    53.     {
    54.         if (domain.Length == 0)
    55.         {
    56.             Debug.Log("GoogleAnalytics settings not set!");
    57.             return;
    58.         }
    59.        
    60.         long utCookie = Random.Range(10000000,99999999);
    61.         long utRandom = Random.Range(1000000000,2000000000);
    62.         long utToday = GetEpochTime();
    63.         string encoded_equals = "%3D";
    64.         string encoded_separator = "%7C";
    65.        
    66.         string _utma = utCookie + "." + utRandom + "." + utToday + "." + utToday + "." + utToday + ".2" + [url]WWW.EscapeURL[/url] (";") + [url]WWW.EscapeURL[/url] ("+");
    67.         string cookieUTMZstr = "utmcsr" + encoded_equals + "(direct)" + encoded_separator + "utmccn"+ encoded_equals +"(direct)" + encoded_separator + "utmcmd" + encoded_equals + "(none)" + [url]WWW.EscapeURL[/url] (";");
    68.        
    69.         string _utmz = utCookie + "." + utToday + "2.2.2." + cookieUTMZstr;
    70.        
    71.         /// If no page was given, use levelname:
    72.         if (page.Length == 0)
    73.         {
    74.             page = Application.loadedLevelName;
    75.         }
    76.  
    77.         requestParams.Clear();
    78.         requestParams.Add("utmwv", "4.6.5");           
    79.         requestParams.Add("utmn", utRandom.ToString());
    80.         requestParams.Add("utmhn", WWW.EscapeURL(domain));
    81.         requestParams.Add("utmcs", "ISO-8859-1");
    82.         requestParams.Add("utmsr", Screen.currentResolution.width.ToString() + "x" + Screen.currentResolution.height.ToString());  
    83.        
    84.         requestParams.Add("utmsc", "24-bit");
    85.         requestParams.Add("utmul", "nl");  
    86.         requestParams.Add("utmje", "0");       
    87.         requestParams.Add("utmfl", "-");       
    88.         requestParams.Add("utmdt", WWW.EscapeURL(page));
    89.         requestParams.Add("utmhid", utRandom.ToString());              
    90.         requestParams.Add("utmr", "-");            
    91.         requestParams.Add("utmp", page);   
    92.         requestParams.Add("utmac", accountid);     
    93.         requestParams.Add("utmcc", "__utma" + encoded_equals +_utma + "__utmz" + encoded_equals + _utmz );
    94.        
    95.        
    96.         /// Add event if available:
    97.         if (category.Length > 0  action.Length > 0)
    98.         {
    99.             string eventparams = "5(" + category + "*" + action;
    100.            
    101.             if (opt_label.Length > 0)
    102.             {
    103.                 eventparams += "*" + opt_label + ")(" + opt_value.ToString() + ")";
    104.            
    105.             } else {
    106.                        
    107.                 eventparams += ")";
    108.             }
    109.            
    110.             requestParams.Add("utme", eventparams);
    111.             requestParams.Add("utmt", "event");
    112.         }
    113.        
    114.  
    115.         /// Create query string:
    116.         ArrayList pageURI = new ArrayList();
    117.         foreach( string key in requestParams.Keys )
    118.         {
    119.                 pageURI.Add( key  + "=" + requestParams[key]) ;
    120.         }
    121.  
    122.        
    123.         string url =   "http://www.google-analytics.com/__utm.gif?" + string.Join("", (string [])pageURI.ToArray(typeof(string)));
    124.        
    125.         /// Log url:
    126.         Debug.Log("[Google URL]" + url);       
    127.        
    128.         /// Execute query:
    129.         WWW w = new WWW(url);
    130.         //while ( w.isDone == false ) {};
    131. //      string d = w.data;     
    132.        
    133.     }
    134.  
    135.     private static long GetEpochTime()
    136.     {
    137.         System.DateTime dtCurTime = System.DateTime.Now;
    138.         System.DateTime dtEpochStartTime = System.Convert.ToDateTime("1/1/1970 0:00:00 AM");
    139.         System.TimeSpan ts = dtCurTime.Subtract(dtEpochStartTime);
    140.  
    141.         long epochtime;
    142.         epochtime = ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);
    143.        
    144.         return epochtime;
    145.     }
    146.    
    147.    
    148. }
    149.  
     
  15. 3Duaun

    3Duaun

    Joined:
    Dec 29, 2009
    Posts:
    600
    @azeitler
    thanks for the new optimizations to the script! :)

    Is this new version compatible with iPhone/iPad development in Unity?

    EDIT: @azeitler, thanks for the confirmation, and thank for sharing this with the UnityCommunity! Your hard work is appreciated.
     
  16. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
  17. weeble

    weeble

    Joined:
    Aug 19, 2010
    Posts:
    2
    Can the Google analytics js code be embedded in the unity standalone, or is it dependent on the host sites page js? I ask not as a developer, as oyu can see, but as a PM trying to prep for a game yet to be made.
     
  18. 3Duaun

    3Duaun

    Joined:
    Dec 29, 2009
    Posts:
    600
    any word on the compatibility of this great script with Unity3?(now that its officially released)
     
  19. jrbitt

    jrbitt

    Joined:
    Oct 18, 2010
    Posts:
    5
    Hi zhx
    I did an experiment in Unity3, exactly this code and doesn't work
    In log in web player luccheck6 luccheck6 luccheck6 luccheck6 ... when try to acess crossdomain in www.google-analytics.com
    Until now I don't see an example that works pure in Unity3 in web player
    Best
     
  20. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    I did not have any problems actually, it upgraded without a problem as far as I know. (In a standalone though)
     
  21. 3Duaun

    3Duaun

    Joined:
    Dec 29, 2009
    Posts:
    600
    hmmm, I wonder if it works in iOS with Unity3
     
  22. ibyte

    ibyte

    Joined:
    Aug 14, 2009
    Posts:
    1,047
    Hi

    I tried Andreas's updated code but I have run into 2 problems

    1) When I tried to implement it as is (GoogleAnalyticsHelper.Instance.Settings("UA-22222222-1", "mydomain.com");') received this error GoogleAnalyticsHelper' does not contain a definition for `Instance'.

    2) When I modified the code by removing .Instance, the code runs. I can see the url being logged but so far no events are showing up on the google analytics web site. I can see that my tracking code is working as I also put it on my web page (and tried a few hits).

    Any suggestion on what missed in item 1 or what to look for in item 2?

    iByte
     
    Last edited: Apr 12, 2011
  23. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    Hi folks,

    I have not been using this script due to legal reasons (I will get back to that below the code) for some time.

    As far as I can tell the people experiencing problems used the old code from the header-comments I forget to remove/update. Here we go with a final version:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. /// Google analytics class v 1.2
    5. /// Optimized for .Net 1.1 and Unity iOS by Andreas Zeitler
    6. /// Check in with my work at: www.azeitler.com, azeitler@dopanic.com
    7. ///
    8. /// based on v1.0 (c) by Almar Joling
    9. /// E-mail: unitydev@persistentrealities.com
    10. /// Website: http://www.persistentrealities.com
    11.  
    12. /// Performs a google analytics request with given  parameters
    13. /// Important: account id and domain id are required.
    14. /// Make sure that your site is verified, so that tracking is enabled! (it needs a file to be placed somewhere in a directory online)
    15.  
    16. /// Example usage:
    17. /// One time initialize:
    18. /// Use a different hostname if you like.
    19. /// GoogleAnalyticsHelper.Settings("UA-yourid", "127.0.0.1");
    20.  
    21. /// Then, for an "event":
    22. ///  GoogleAnalyticsHelper.LogEvent("levelname", "pickups", "pickupname", "optionallabel", optionalvalue);
    23.  
    24. /// For a "page" (like loading a level?)
    25. /// GoogleAnalyticsHelper.LogPage("Mainscreen");
    26.  
    27.  
    28. public static class GoogleAnalyticsHelper
    29. {
    30.     private static string accountid;
    31.     private static string domain;
    32.    
    33.     private static readonly GoogleAnalyticsHelper instance = new GoogleAnalyticsHelper();      
    34.    
    35.     /// Init class with given site id and domain name
    36.     public static void Settings(string p_accountid, string p_domain)
    37.     {
    38.         domain = p_domain;
    39.         accountid = p_accountid;
    40.     }
    41.  
    42.  
    43.     public static void LogPage(string page)
    44.     {
    45.         LogEvent(page, "","","", 0);
    46.     }
    47.  
    48.     /// Perform a log call, if only page is specified, a page visit will be tracked
    49.     /// With category, action, and optionally opt_label and opt_value, there will be an event added instead
    50.     /// Note that the statistics can take up to 24h before showing up at your Google Analytics account!
    51.     private static Hashtable requestParams = new Hashtable();
    52.     public static void LogEvent(string page, string category, string action, string opt_label, int opt_value)
    53.     {
    54.         if (domain.Length == 0)
    55.         {
    56.             Debug.Log("GoogleAnalytics settings not set!");
    57.             return;
    58.         }
    59.        
    60.         long utCookie = Random.Range(10000000,99999999);
    61.         long utRandom = Random.Range(1000000000,2000000000);
    62.         long utToday = GetEpochTime();
    63.         string encoded_equals = "%3D";
    64.         string encoded_separator = "%7C";
    65.        
    66.         string _utma = utCookie + "." + utRandom + "." + utToday + "." + utToday + "." + utToday + ".2" + WWW.EscapeURL (";") + WWW.EscapeURL ("+");
    67.         string cookieUTMZstr = "utmcsr" + encoded_equals + "(direct)" + encoded_separator + "utmccn"+ encoded_equals +"(direct)" + encoded_separator + "utmcmd" + encoded_equals + "(none)" + WWW.EscapeURL (";");
    68.        
    69.         string _utmz = utCookie + "." + utToday + "2.2.2." + cookieUTMZstr;
    70.        
    71.         /// If no page was given, use levelname:
    72.         if (page.Length == 0)
    73.         {
    74.             page = Application.loadedLevelName;
    75.         }
    76.  
    77.         requestParams.Clear();
    78.         requestParams.Add("utmwv", "4.6.5");           
    79.         requestParams.Add("utmn", utRandom.ToString());
    80.         requestParams.Add("utmhn", WWW.EscapeURL(domain));
    81.         requestParams.Add("utmcs", "ISO-8859-1");
    82.         requestParams.Add("utmsr", Screen.currentResolution.width.ToString() + "x" + Screen.currentResolution.height.ToString());  
    83.        
    84.         requestParams.Add("utmsc", "24-bit");
    85.         requestParams.Add("utmul", "nl");  
    86.         requestParams.Add("utmje", "0");       
    87.         requestParams.Add("utmfl", "-");       
    88.         requestParams.Add("utmdt", WWW.EscapeURL(page));
    89.         requestParams.Add("utmhid", utRandom.ToString());              
    90.         requestParams.Add("utmr", "-");            
    91.         requestParams.Add("utmp", page);   
    92.         requestParams.Add("utmac", accountid);     
    93.         requestParams.Add("utmcc", "__utma" + encoded_equals +_utma + "__utmz" + encoded_equals + _utmz );
    94.        
    95.        
    96.         /// Add event if available:
    97.         if (category.Length > 0  action.Length > 0)
    98.         {
    99.             string eventparams = "5(" + category + "*" + action;
    100.            
    101.             if (opt_label.Length > 0)
    102.             {
    103.                 eventparams += "*" + opt_label + ")(" + opt_value.ToString() + ")";
    104.            
    105.             } else {
    106.                        
    107.                 eventparams += ")";
    108.             }
    109.            
    110.             requestParams.Add("utme", eventparams);
    111.             requestParams.Add("utmt", "event");
    112.         }
    113.        
    114.  
    115.         /// Create query string:
    116.         ArrayList pageURI = new ArrayList();
    117.         foreach( string key in requestParams.Keys )
    118.         {
    119.                 pageURI.Add( key  + "=" + requestParams[key]) ;
    120.         }
    121.        
    122.         string url =   "http://www.google-analytics.com/__utm.gif?" + string.Join("", (string [])pageURI.ToArray(typeof(string)));
    123.        
    124.         /// Log url:
    125.         Debug.Log("[Google URL]" + url);       
    126.        
    127.         /// Execute query:
    128.         WWW w = new WWW(url);
    129.     }
    130.  
    131.     private static long GetEpochTime()
    132.     {
    133.         System.DateTime dtCurTime = System.DateTime.Now;
    134.         System.DateTime dtEpochStartTime = System.Convert.ToDateTime("1/1/1970 0:00:00 AM");
    135.         System.TimeSpan ts = dtCurTime.Subtract(dtEpochStartTime);
    136.  
    137.         long epochtime;
    138.         epochtime = ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);
    139.        
    140.         return epochtime;
    141.     }
    142.    
    143.    
    144. }
    @iByte: did you wait 24 hours for the tracked events to show up in your google analytics account? google states it takes up to 24h to update the states on the webinterface.

    As far as the legal issue I mentioned goes: I am from Europe (Germany) and we have some quite strict laws about tracking user and usage data over here. As far as we could gather you are not allowed to track user data without informing the user about it, giving him an option to disable tracking and explaining all this in an extensive disclaimer.
    Just thought I mention it if anyone from my corner of the planet ever considers tracking user data :D
     
  24. ibyte

    ibyte

    Joined:
    Aug 14, 2009
    Posts:
    1,047
    Hi Andreas,

    Thanks very much for the code update. Will let you know if it helps.

    Yes I see pageviews from my website and I see one event that I copied and pasted from the Unity Log directly to my browser. So I am pretty sure the URL is formatted correctly. The event data confirms it was my Mac. I have not seen any events directly from my iPhone or iPad yet and it has been several days so I think there must be something wrong with the call to WWW.

    Thanks for the legal tip. I plan to inform the player and give an option to disable. I think in reality there is a lot of tracking going on that no one is informed of. In particular via in-game ad networks like Mobclix (which is disabled, so my interest in Google)

    I wonder do web sites have such disclaimers and options to turn page tracking off? If not then why are apps under such rules?

    iByte
     
    Last edited: Apr 13, 2011
  25. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    After over 24h GA doesn't show events so I tried using a GA id which works for a website and same result of nothing. Can you outline all the steps to make this work?
    Does it require a java script somewhere on my server as it was suggesting in another thread ?
     
  26. azeitler

    azeitler

    Joined:
    May 14, 2008
    Posts:
    162
    Somebody needs to look at the URL that is put together by the script. The URL parameters are probably outdated if GA does not accept events tracked by the script.
    Things you need to google for that focus on the google analytics Urching Traffic Monitor (UTM): http://www.google.com/support/urchin45/bin/answer.py?answer=28710

    I myself can't help with that.

    there are a lot of nuances in tracking usage data, the more data you track the longer the disclaimer about it needs to be. the need to provide an opt-out for the user kicks in as soon as you start tracking user-location (even if it is only IP-based) – that is as far as I know and only for german law.
    A lot of apps and websites don't need to care about this stuff, because the developers are located outside europe and germany, where you don't need to care about those things.
     
  27. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    Even LogPage doesn't do anything.

    By the way status is still the warning sign because obviously the game is running from the editor and is not a web page, anything I should change?
    $Screen shot 2011-04-13 at 3.57.27 PM.jpg
     
  28. ibyte

    ibyte

    Joined:
    Aug 14, 2009
    Posts:
    1,047
    llavigne, try copying the generated URL from the log and paste it into a browser. This works for me as a test which shows the code generates the correct parameters but still nothing shows up (even 24hrs later when i run the code directly from my app).

    I am starting to think that maybe the www request from unity is not showing up as a valid browser type to Google?

    Andreas, I also got an error from this line "private static readonly GoogleAnalyticsHelper instance = new GoogleAnalyticsHelper();

    I commented it out as Unity complained about it, the code still seems to generate the correct URL.

    iByte
     
  29. Thomas-Pasieka

    Thomas-Pasieka

    Joined:
    Sep 19, 2005
    Posts:
    2,174
    I moved this thread to "Scripting" as it doesn't belong into the "Showcase".
     
  30. 3Duaun

    3Duaun

    Joined:
    Dec 29, 2009
    Posts:
    600
    cool, an update, thanks @azeitler
     
  31. iisjreg

    iisjreg

    Joined:
    Mar 25, 2011
    Posts:
    101
    Hi all,

    Was just searching about and came across this thread again. (P.S. haven't actually tried to find the most recent posting in the forum on this, but this thread is from April, so c'mon... ;) )

    This page: http://code.google.com/intl/en-US/apis/analytics/docs/tracking/eventTrackerGuide.html still seems to be up to date, which implies that this code: http://blog.mostlytigerproof.com/20...ng-google-analytics-and-unity-3d/#comment-126 should work.

    I'm yet to try it out yet (and I know it's from 2009) but 1 line of code? Wow.
     
  32. immFX

    immFX

    Joined:
    Mar 20, 2010
    Posts:
    110
    ehmm...
    One line of code indeed... but doesn't work on standalones, while this one does.
     
  33. iisjreg

    iisjreg

    Joined:
    Mar 25, 2011
    Posts:
    101
    Aaah, true, but it's still useful.
     
  34. Jodon

    Jodon

    Joined:
    Sep 12, 2010
    Posts:
    434
    Thanks very much, it seems to work for me. Free is much better than spending $55 in the App Store :). Curious though, as I'm not familiar with web technologies at all, does anyone have any "best practices" for how to set this up to get interesting data back? I've just tested it on a trigger volume, and it appears every event counts as a "new visit".

    I would have loved to experiment with how to get some good data back, but unfortunately Google Analytics only updates data once a day, making it impractical. Any suggestions?
     
  35. Brad-Keys

    Brad-Keys

    Joined:
    May 1, 2006
    Posts:
    161
    Another analytics solution you can try is Lumos (http://www.uselumos.com/). It's free and requires no programming. And it's actually meant for Unity games.
     
  36. MetaMythril

    MetaMythril

    Joined:
    May 5, 2010
    Posts:
    150
    Awesome thread. Usage tracking definitely helps address design issues. Is Lumos a free service? Can't tell just from looking at the site.
     
  37. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    Lumos seems limited to player log, error report and hardware stats.

    An analytics should also count triggers such as rounds fired, death location and provide meaningly display which Lumos doesn't at this point.
     
    Last edited: Jun 30, 2011
  38. Brad-Keys

    Brad-Keys

    Joined:
    May 1, 2006
    Posts:
    161
    It is free. We'll be rolling out a paid premium service in time. But you can always count on using it for free.

    These points are some of the next features that we'll be releasing. Something I've done in my games at the moment is actually use the Debug log recording as my counters for things like rounds fired, levels completed, etc. But we by all means will be providing an actual "event" system to properly deal with that sort of thing.

    Here's the main thread on Lumos
     
    Last edited: Jun 30, 2011
  39. will123

    will123

    Joined:
    Aug 12, 2011
    Posts:
    5
    Cheers Almar this is AWSOME :)
     
  40. hs1S

    hs1S

    Joined:
    Jul 23, 2009
    Posts:
    153
    I created a new google analytics account (choosed Website's URL
    = not a website ). This code is working for me:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. /// Google analytics class v 1.0
    7. /// (c) by Almar Joling
    8. /// E-mail: unitydev@persistentrealities.com
    9. /// Website: http://www.persistentrealities.com
    10.  
    11. /// Performs a google analytics request with given  parameters
    12. /// Important: account id and domain id are required.
    13. /// Make sure that your site is verified, so that tracking is enabled! (it needs a file to be placed somewhere in a directory online)
    14.  
    15. /// Example usage:
    16. /// One time initialize:
    17. /// Use a different hostname if you like.
    18. /// GoogleAnalyticsHelper.Instance.Settings("UA-yourid", "127.0.0.1");
    19.  
    20. /// Then, for an "event":
    21. ///  GoogleAnalyticsHelper.Instance.LogEvent("levelname", "pickups", "pickupname", "optionallabel", optionalvalue);
    22.  
    23. /// For a "page" (like loading a level?)
    24. /// GoogleAnalyticsHelper.Instance.LogPage("Mainscreen");      
    25.  
    26. /// If you made any improvements please let me know :).
    27.  
    28.  
    29.  
    30. public sealed class GoogleAnalyticsHelper
    31. {
    32.     private string accountid;
    33.     private string domain;
    34.    
    35.     private static readonly GoogleAnalyticsHelper instance = new GoogleAnalyticsHelper();  
    36.    
    37.     public static GoogleAnalyticsHelper Instance
    38.     {
    39.         get
    40.         {
    41.             return instance;
    42.         }
    43.     }  
    44.    
    45.     /// Init class with given site id and domain name
    46.     public void Settings(string accountid, string domain)
    47.     {
    48.             this.domain = domain;
    49.             this.accountid = accountid;
    50.     }
    51.  
    52.  
    53.     public void LogPage(string page)
    54.     {
    55.             this.LogEvent(page, "","","", 0);
    56.     }
    57.  
    58.     /// Perform a log call, if only page is specified, a page visit will be tracked
    59.     /// With category, action, and optionally opt_label and opt_value, there will be an event added instead
    60.     /// Note that the statistics can take up to 24h before showing up at your Google Analytics account!
    61.     public void LogEvent(string page, string category, string action, string opt_label, int opt_value)
    62.     {
    63.  
    64.         if (this.domain.Length == 0)
    65.         {
    66.             Debug.Log("GoogleAnalytics settings not set!");
    67.             return;
    68.         }
    69.        
    70.         long utCookie = Random.Range(10000000,99999999);
    71.         long utRandom = Random.Range(1000000000,2000000000);
    72.         long utToday = GetEpochTime();
    73.         string encoded_equals = "%3D";
    74.         string encoded_separator = "%7C";
    75.        
    76.         string _utma = utCookie + "." + utRandom + "." + utToday + "." + utToday + "." + utToday + ".21.10" + WWW.EscapeURL (";") + WWW.EscapeURL ("+");
    77.         string cookieUTMZstr = "utmcsr" + encoded_equals + "(direct)" + encoded_separator + "utmccn"+ encoded_equals +"(direct)" + encoded_separator + "utmcmd" + encoded_equals + "(none)" + WWW.EscapeURL (";");
    78.        
    79.         string _utmz = utCookie + "." + utToday + "2.2.2." + cookieUTMZstr;
    80.        
    81.         /// If no page was given, use levelname:
    82.         if (page.Length == 0)
    83.         {
    84.             page = Application.loadedLevelName;
    85.         }
    86.        
    87.         Dictionary<string, string> requestParams = new Dictionary<string, string>();
    88.        
    89.         requestParams.Add("utmwv", "1");           
    90.         requestParams.Add("utmn", utRandom.ToString());
    91.         requestParams.Add("utmhn", WWW.EscapeURL(domain));
    92.         //requestParams.Add("utmcs", "ISO-8859-1");
    93.         requestParams.Add("utmsr", Screen.currentResolution.width.ToString() + "x" + Screen.currentResolution.height.ToString());  
    94.        
    95.         //requestParams.Add("utmsc", "24-bit");
    96.  
    97.         requestParams.Add("utmul", "nl");  
    98.         //requestParams.Add("utmje", "0");     
    99.         //requestParams.Add("utmfl", "11.1 r102");     
    100.         requestParams.Add("utmdt", WWW.EscapeURL(page));
    101.         //requestParams.Add("utmhid", utRandom.ToString());            
    102.         requestParams.Add("utmr", "-");            
    103.         requestParams.Add("utmp", page);   
    104.         requestParams.Add("utmac", this.accountid);    
    105.         requestParams.Add("utmcc", "__utma" + encoded_equals +_utma + "__utmz" + encoded_equals + _utmz );
    106.        
    107.        
    108.         /// Add event if available:
    109.         if (category.Length > 0  action.Length > 0)
    110.         {
    111.             string eventparams = "5(" + category + "*" + action;
    112.            
    113.             if (opt_label.Length > 0)
    114.             {
    115.                 eventparams += "*" + opt_label + ")(" + opt_value.ToString() + ")";
    116.            
    117.             } else {
    118.                        
    119.                 eventparams += ")";
    120.             }
    121.            
    122.             requestParams.Add("utme", eventparams);
    123.             requestParams.Add("utmt", "event");
    124.         }
    125.        
    126.  
    127.         /// Create query string:
    128.         ArrayList pageURI = new ArrayList();
    129.         foreach( KeyValuePair<string, string> kvp in requestParams )
    130.         {
    131.                 pageURI.Add( kvp.Key  + "=" + kvp.Value) ;
    132.         }
    133.  
    134.        
    135.         string url =   "http://www.google-analytics.com/__utm.gif?" + string.Join("", (string [])pageURI.ToArray(typeof(string)));
    136.        
    137.         /// Log url:
    138.         Debug.Log("[Google URL]" + url);       
    139.        
    140.         /// Execute query:
    141.         WWW w = new WWW(url);
    142.         while ( w.isDone == false ) {};
    143. //      string d = w.data;     
    144.         Debug.Log(w.text);
    145.        
    146.     }
    147.        
    148.    
    149.     private long GetEpochTime()
    150.     {
    151.         System.DateTime dtCurTime = System.DateTime.Now;
    152.         System.DateTime dtEpochStartTime = System.Convert.ToDateTime("1/1/1970 0:00:00 AM");
    153.         System.TimeSpan ts = dtCurTime.Subtract(dtEpochStartTime);
    154.  
    155.         long epochtime;
    156.         epochtime = ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);
    157.        
    158.         return epochtime;
    159.     }
    160.    
    161.    
    162. }
    163.  
    164.  

    Then I use like this:

    Code (csharp):
    1.  
    2. ...
    3. if (Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork){
    4.     GoogleAnalyticsHelper.Instance.Settings ("UA-XXXXXXXX", "127.0.0.1"); // your id
    5.     GoogleAnalyticsHelper.Instance.LogEvent ("MyGame", Application.platform.ToString(), "MyAction", "MySubAction", 0);
    6. }
    7. ...
    8.  
    9.  
    Then you need to wait Google analytics update. I try to not send much requests per seconds and it looks like it's working for me.
     
    Last edited: Mar 4, 2012
  41. andresp

    andresp

    Joined:
    Aug 12, 2011
    Posts:
    38
    @TimViana Your code doesn't work here and I'm a bit surprised you say it works for you. Besides png and jpg textures, Unity doesn't let you do WWW requests to domains without crossdomain.xml (like google-analytics.com) as far as I know.
     
  42. hs1S

    hs1S

    Joined:
    Jul 23, 2009
    Posts:
    153
    As I said before: I created a new google analytics account (choosed Website's URL = not a website ).

    Actually, when you do the WWW request to Google Analytics it returns a blank gif.
     
  43. andresp

    andresp

    Joined:
    Aug 12, 2011
    Posts:
    38
    Not on the webplayer.
     
  44. schizo

    schizo

    Joined:
    Dec 13, 2010
    Posts:
    2
    I have gotten this code to work on iOS and Android, but it does not work in the webplayer, likely due to the crossdomain issue others have mentioned. Anyone have any idea how to get around that other than changing my web player code to use the standard google analytics javascript calls?

    If anyone has questions about getting it up and running for iOS/Android I can definitely help there.
     
  45. Tobias J.

    Tobias J.

    Joined:
    Feb 21, 2012
    Posts:
    423
    Sweet! Thanks Almar! :)

    Is the Sprite/Tile object pack free for any sort of use?
     
  46. taar1

    taar1

    Joined:
    Jan 12, 2012
    Posts:
    26
    I could use some of your help :) I used the code posted above for my Unity Android game. If I run it I get following error in the logfile:

    not sure what I would have to do to get this work. Is the URL broken? Thanks for any tips.
     
  47. schizo

    schizo

    Joined:
    Dec 13, 2010
    Posts:
    2
    taar1:
    Check to make sure you're calling the Settings function before any Log calls to set the User Account info. Also your page URL has a space in it (DrTeeth Android), remove the space.
     
  48. taar1

    taar1

    Joined:
    Jan 12, 2012
    Posts:
    26
    Thanks for the hint with the blank space. I've changed that and now I don't get any errors in the logfile anymore. Will have to check tomorrow with Google Analytics if it received the logging.

    Ah... cheered too soon. I still get an error:

    I'm always calling the Settings function before I do any logging. Here is the whole URL again since in the quotes above it seems to shorten the link for some reasons:

    [urlx]http://www.google-analytics.com/__utm.gif?utmwv=1&utmn=1169097616&utmhn=127.0.0.1&utmsr=480x800&utmul=en&utmdt=%c3%a3%e2%80%9a%c2%aa%c3%a3%c6%92%e2%80%94%c3%a3%e2%80%9a%c2%b7%c3%a3%c6%92%c2%a7%c3%a3%c6%92%c2%b3&utmr=-&utmp=オプション&utmac=UA-XXXXXXX-3&utmcc=__utma%3D90450805.1169097616.1338374114.1338374114.1338374114.21.10%3b%2b__utmz%3D90450805.13383741142.2.2.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3b&utme=5(Android*SFXオン��る* --- 0)(0)&utmt=event[/urlx]

    Any ideas on this?
    Thank you.
     
    Last edited: May 30, 2012
  49. EddieB

    EddieB

    Joined:
    Apr 12, 2012
    Posts:
    2
    The Script work for me on Android (even the real time function)

    I had a problem with the encoding so my URL wan't good. (chek your script encoding)

    now i have a new problem.

    - On Iphone the game freez when i send the request.

    any idea to resolve this?
     
  50. cledin

    cledin

    Joined:
    May 29, 2009
    Posts:
    13
    bump same problem.