Tuesday, November 2, 2010

Tracking Sales Statistics with the Silverlight Analytics Framework for Windows Phone

The official statistics are now available at the App Hub portal. However, this approach is capable of more than sales tracking.

Are you a Windows Phone developer? Are you also curious how well your app performs in the Windows Phone Marketplace? I am!
Some might say it doesn't matter yet, since there aren't many devices out there, but nevertheless I'd like to know my statistics. Also O2 Germany recently reported they have sold out the first batch of HTC HD7 devices with sales in the 5-figure range. Unfortunately we won't see official statistics from the Marketplace any time soon. An App Hub forum member contacted the Microsoft App Hub support and they told him that sales statistics won't be available before January 2011. Bummer!
Fortunately we are app developers and we can implement our own statistic tracking. On the other hand this means we have to setup and pay some service and implement tracking code. Here is where the Silverlight Analytics Framework and Google Analytics come to the rescue.
This blog post provides a step-by-step guide on how to track your app (sales) statistics with the Silverlight Analystics Framework and Google Analystics. Did I mention it's free and not only free for a limited period?
Let's go...

Setup Google Analytics
If you don't have a Google Analytics account, just sign up here. It's free.
  1. Create an empty HTML page with the minimum tags and upload it to some public webspace. If you don't have webspace available, just create a free Dropbox account and put the page in the public folder.

  2. Go to Google Analytics and use the "Add Website Profile" functionality. Choose "Add a Profile for a new domain". Enter the URL of the dummy website.

  3. The next page setup page will show the necessary Java Script tracking code. Copy the code, paste it into the dummy website and upload the website.

  4. Your website profile is now waiting for activation. Go back to the overview and click the Edit link of your website profile. See the little yellow exclamation mark with the text "Tracking Not Installed" at the upper right corner. Click on "Check Status". The status should change soon and the profile will become active. If not, give Google a couple of minutes and retry it then.


Setup the Silverlight Analytics Framework
Now it's time to submit the tracking events from your app to Google Analytics. This task is pretty easy with the help of the Silverlight Analytics Framework.
The Silverlight Analytics Framework is an extensible web analytics framework mainly developed by the Microsoft evangelist Michael S. Scherotter. It's really nice, designed in a flexible way with the use of modern technologies and open source. Google Analytics is just one of the many supported analytics services.
  1. Download the latest version from the Codeplex site and install it or download the latest source code from the repository and build it yourself. I've chosen the latter since Michael recently implemented a nice feature: The Silverlight Analytics Framework for Windows Phone tracks each page view by default. In the changeset 63020 Michael added an IsPageTracking property which allows to disable the page tracking. This feature is part of the latest release 1.4.8.

  2. Add the following assembly references to your project.
    From the Silverlight for Windows Phone Framework: System.Device, System.Windows.Interactivity
    From the Silverlight Analytics Framework: Microsoft.WebAnalytics, Microsoft.WebAnalytics.Behaviors, Google.WebAnalytics, System.ComponentModel.Composition, System.ComponentModel.Composition.Initialization

  3. Create a new class in your project:
    public class AnalyticsService : IApplicationService
    {
       public void StartService(ApplicationServiceContext context)
       {
          // Wire up MEF
          CompositionHost.Initialize(
             new AssemblyCatalog(
                Application.Current.GetType().Assembly),
                new AssemblyCatalog(typeof(Microsoft.WebAnalytics.AnalyticsEvent).Assembly),
                new AssemblyCatalog(typeof(Microsoft.WebAnalytics.Behaviors.TrackAction).Assembly));
       }
    
       public void StopService() { }
    }
    

  4. Go to the App.xaml file of your project and add the namespace definitions to the first tag:
    <Application
        x:Class="MyApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
        
        xmlns:local="clr-namespace:MyApp"
        xmlns:ga="clr-namespace:Google.WebAnalytics;assembly=Google.WebAnalytics"
        xmlns:mpc="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:mwa="clr-namespace:Microsoft.WebAnalytics;assembly=Microsoft.WebAnalytics"
        >
    
  5. Then add the service references inside the Application.ApplicationLifetimeObjects declaration in your App.xaml file:
    <Application.ApplicationLifetimeObjects>    
        <local:AnalyticsService />
        <mwa:WebAnalyticsService IsPageTrackingEnabled="False">
            <mwa:WebAnalyticsService.Services>
                <ga:GoogleAnalytics WebPropertyId="UA-XXXXXXX-X" />
            </mwa:WebAnalyticsService.Services>
        </mwa:WebAnalyticsService>
    </Application.ApplicationLifetimeObjects>
    
    Most important you need to replace the WebPropertyId in the GoogleAnalytics element with the Id of your newly created Google Analytics website profile.
    I'm not interested in the page tracking, therefore I've set the IsPageTrackingEnabled property to False. You should also keep in mind that page tracking has an impact on the performance of the app. I recommend to disable it.
     
  6. Since your app is now using a network connection, you need to add the ID_CAP_NETWORKING capability to your WMAppManifest.xml file
That was all to get the Silverlight Analytics Framework connected to your Google Analytics profile. It now tracks the Deactivated, Activated and Started events.
You can find the results here:

Please keep in mind that it usually takes 12 - 24 hours until the tracked data shows up in Google Analytics.


Add sales tracking
There's only one puzzle piece left now, the actual sales tracking. I use two Windows Phone APIs for this. First the LicenseInformation.IsTrial method which tells us if the app runs in trial mode or if it was paid. The second API is the DeviceExtendedProperties class with the DeviceUniqueId key which provides a unique 20 byte long hash for the phone. Such an id is needed to count unique installations.
  1. Add a new class to your project for the explicit tracking from code:
    public class AnalyticsHelper
    {
       // Injected by MEF   
       [Import("Log")]
       public Action<AnalyticsEvent> Log { get; set; }
    
       public AnalyticsHelper()
       {
          // Inject
          CompositionInitializer.SatisfyImports(this);
       }
    
       public void Track(string category, string name)
       {
          // Track analytics event
          Log(new AnalyticsEvent { Category = category, Name = name, });
       }
    }
    

  2. Call the Track method when your app launches and provide the necessary information.
    Add this code to the Application_Launching event handler in the App.xaml.cs file.
    private void Application_Launching(object sender, LaunchingEventArgs e)
    {
       var analyticsHelper = new AnalyticsHelper();
    
       // Get device id
       var value = (byte[])DeviceExtendedProperties.GetValue("DeviceUniqueId");
       var id = Convert.ToBase64String(value);
       
       // Track launch
       analyticsHelper.Track("Launch All", id);
    
       // Track if paid
       if (!new LicenseInformation().IsTrial())
       {
          analyticsHelper.Track("Launch Paid", id);
       }
    }
    
    Gergely Orosz (@Gergely Orosz) gave me the idea to track the statistics only if the phone is connected to Wi-Fi. This is pretty easy to implement, just add an if condition around the tracking: NetworkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211

  3. The app is now using the unique id of the phone, so you have to add the ID_CAP_IDENTITY_DEVICE capability to your WMAppManifest.xml file

As you can see all app launches are tracked in the category "Launch All" and all paid launches in the "Launch Paid" category. This makes it easy to see all installations and all sales directly. Needless to mention that Launch Trial = Launch All - Launch Paid.
You can check if all works with the Fiddler or the TCPView tool while using the Windows Phone emulator. By the way, the tracking is pretty fast. I measured 20 to 40 ms for each Track call when the phone was connected to Wi-Fi.

The tracked events are best viewed when grouped by categories. The screenshot below shows a test with multiple launches of a phone and the emulator. The total number of events is listed at the bottom right of the table. Note that Unique Events aren't significant here since they only represent unique events for one session.

The id (event name) we supply through the AnalyticsEvent is mapped to the Google Analytics Event Action. You can find all event mappings and more info in the relevant Silverlight Analytics Framework documentation.

Conclusion
The update I submitted to the Marketplace works nicely and I hope to see some meaningful statistics in the next weeks. I think the described method is a good way to track your sales and other statistics until the App Hub team provides the official usage / sales statistics. Actually the provided tracking functionality is even useful when the App Hub team provides official statistics. And it's all free without a limited timeframe.

27 comments:

  1. This will work but using the analytics tracking seems like the long way round. I'm tracking results by having the app call a webservice to store the data in a DB. This gets you the results as they happen so you don't have to wait for analytics to play catch up.

    ReplyDelete
  2. If your app is already in the marketplace you might not have a way of tracking it. I have built a little Silverlight app which at least retrieves all the app reviews from different marketplaces, find it here: http://blog.tomverhoeff.nl/2010/11/02/windows-phone-7-review-reader/

    ReplyDelete
  3. Here is a nice comparison of the analytics being offered by Microsoft and the Silverlight analytics framework by its author at Microsoft in his blog http://blogs.msdn.com/b/synergist/archive/2010/11/02/dotfuscator-for-windows-phone-released.aspx

    ReplyDelete
  4. With the MSAF framework on a phone, if you are not using wifi, does it make a datacall every time you hit a page, or does it batch them together and send them once a day (something like what it does when running OOB). I think my users would be annoyed if it kept connecting to the internet on every single page... however it is sent it once a day or something it would be better...

    ReplyDelete
  5. Hi PokerDIY,

    The MSAF only tracks the Activated, Deactivated and Started events automatically if you set IsPageTrackingEnabled to False. And you can only track manually if the app is connected to Wi-Fi.
    (Both is covered in the above post)

    However, I agree that it would be nice to have a MSAF property to disable tracking when not connected to Wi-Fi. I started a discussion at the MSAF CodePlex site:
    http://msaf.codeplex.com/Thread/View.aspx?ThreadId=233281

    ReplyDelete
  6. Couple of questions:

    1. Does the framework log stuff directly to GoogleAnalytics using the Analytics ID (I cannot see where the URL that we setup is refferenced in the phones' code, so I am guessing this must be the case?)

    2. When we upload our apps using this framework do we need to request an supression exclusion? (I noticed that the WP7DataCollector.CS uses the following line:

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Object is disposed in Dispose method.")]


    With apologies if these questions are a little dumb (sometimes I can achieve a lot with just a little knowledge - maybe a dangerous thing!)

    ReplyDelete
  7. Hi Anonymous,

    Yes, the WebPropertyId is used directly. No need to supply an URL. The web site is only needed once for activation (see above).

    And no, you don't need a suppression exclusion. The line you copied is just a suppression for Visual Studio's code analysis (FxCop).

    ReplyDelete
  8. A note: In version 1.4.9 of the Silverlight Analytics Framework, the library that this article refers to as System.ComponentModel.Composition is actually listed as simply ComponentModel when adding the reference and then displays as System.ComponentModel.Composition in the list of preject references.

    ReplyDelete
  9. You need to add:
    using System.ComponentModel.Composition.Hosting;
    to your AnalyticsService class that is mentioned in the article above.

    ReplyDelete
  10. I am only getting a WP7 Started. I've followed the above instructions closely and also looked at the How To... in the MSAF Docs and tried a few things, but no change. Any suggestions?

    ReplyDelete
  11. for some reason my whole app got much slower when implementing this. does anyone have the same problem? also i had to add a "ga:" in the app.xaml file before the GoogleAnalytics... is that normal?

    ga:GoogleAnalytics WebPropertyId="UA-xxxxx-x"

    ReplyDelete
  12. As I wrote above, you should set IsPageTrackingEnabled="False" in the WebAnalyticsService to avoid that each page navigation is tracked. I also described how to add the needed GA namespace definition.

    Please read it carefully.

    ReplyDelete
  13. Rene,
    Do you have any advice for my problem above of only getting WP7 Started events and no others? Someone else replied on the MSAF Codeplex Discussion thread I started that they are having the same issue.

    ReplyDelete
  14. Hi techsage,

    It works for me and I did exactly the same as I wrote above. I know others where it also works fine.
    There's not much I can do.
    You should go through it again and also see the MSAF CodePlex forum.

    ReplyDelete
  15. I'm having the same problem with the WP7/Started events only. Followed instructions with copy/paste...still no result. Tried it on emulator and two devices. :(

    ReplyDelete
  16. Hi Coose,

    what should I say, it works for me and I have no clue why it's not working for you.

    Please go through the steps again and make sure the manual tracking with the AnalyticsHelper.Track method is called.

    I used revision 63020 of the MSAF. Maybe you should download the code of this revision and build it on your own:
    http://msaf.codeplex.com/SourceControl/changeset/changes/63020

    Keep me updated if it works then.

    ReplyDelete
  17. This comment has been removed by the author.

    ReplyDelete
  18. oops.. my comment got scrubbed

    the xmlns 'ga' is missing in the code for the app.xaml

    ReplyDelete
  19. Excellent! I have this working well. I wait to report the launch until they are on a menu screen, so they should not notice any delay.

    I am seeing an event category in Google Analytics for 'Open' and 'Close'. How can I eliminate these?

    ReplyDelete
  20. Set WebAnalyticsService.IsPageTrackingEnabled="False" in the App.xaml definition. Then the MSAF only tracks the Activated, Deactivated and Started events automatically. Unfortunately this can't be disabled AFAIK.

    ReplyDelete
  21. Rene, thanks for this post!

    I have google analytics working with both a SL4 app and a WP7 app. I am getting categories and actions recorded under events as expected, but what about labels?

    http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html#Labels

    ReplyDelete
  22. Hi Roger,

    you can find the complete mapping in the MSAF docs:
    http://msaf.codeplex.com/wikipage?title=Google%20Analytics&referringTitle=Home

    "The Event Tracking Label field corresponds to the name of the TrackAction parent object."

    ReplyDelete
  23. so...

    AnalyticsEvent analyticsEvent = new AnalyticsEvent(); analyticsEvent.ObjectName = label;

    or am I confused?

    ReplyDelete
  24. Dunno. Maybe you can find an answer at the MSAF Forums.

    ReplyDelete
  25. Such a great post.

    ReplyDelete
  26. I tried everything that is said in this post and it really works for me. I want to thank you for sharing this very useful post.

    ReplyDelete
  27. Thanks. This is what exactly i needed and it just took some minutes to implement but ofcoursei could only see results a day later in my google anlaytics account.

    ReplyDelete