McNeel - Google Analytics Hits

Cross posted on the Grasshopper3d site, David Rutten suggested I might get better answers here…

So I have some working code to successfully register a “hit” with google analytics when a user runs a solution that includes a plugin I wrote.

My next step is to figure out something I can use as a client ID or user ID.

This can be any string or a UUID, with a few conditions (in order of most important to least):
It cannot be personally identifiable information or any form of sensitive information
It would be the same for any given user, even if they close and then reopen rhino/ grasshopper (so system based, not session-based or random)
It would be different for different users

I just came across this function in the docs for V6 RhinoCommon:

It seems like the guys at McNeel are making this super easy in Rhino 6, but the function doesn’t exist in Rhino 5! In the meantime, while working with Rhino 5, what is something that can be used for a user id/ client id? And/or what does the function in Rhino 6 use?

Hi @Matthew_Breau,

Perhaps adding something like this to your plug-in object is sufficient?

/// <summary>
/// Returns a GUID that allows events to be aggregated by user. 
/// There is no way to determine who the end user is based on this 
/// GUID, unless the user tells you their ID.
/// </summary>
public static Guid GoogleAnalyticsUserId
    var id = Instance.Settings.GetGuid("GoogleAnalyticsUserId", Guid.Empty);
    if (id == Guid.Empty)
      id = Guid.NewGuid();
      Instance.Settings.SetGuid("GoogleAnalyticsUserId", id);
    return id;

Hi Dale, thanks for the suggestion.

Would that “Instance” have some measure of persistence?

Hi @Matthew_Breau,

If you’ve run the RhinoCommon plug-in wizard, then you will see this definition in your PlugIn-inherited object.

///<summary>Gets the one and only instance of the MyTestPlugIn plug-in.</summary>
public static MyTestPlugIn Instance
  get; private set;

The Settings property return the plug-in’s PersistentSettings objects, which save and restores per-plug-in persistent settings.

Does this help?

– Dale

Ahh sorry, I should have specified, this is a Grasshopper plugin, does that make a difference?

Hi @Matthew_Breau,

Grasshopper components don’t implement a “plug-in” object. But using a singleton we can pretty much accomplish the same this (see attached sample).

– Dale (4.9 KB)

Hello Dale,

Is there the same definition in C++? What can be used for it?


Thanks for the example!

I understand the idea of singleton pattern and/ or using a static class, but I just want to confirm that I understand what the code actually does on the client’s computer…

It basically just stores each user’s unique key in the user’s registry, correct? If the key hasn’t been created yet, (or is corrupted/ erased), it will generate and store a new key. By virtue of being in the registry, the key will have strong persistence, and be the same even if rhino is closed and re-opened, or if the computer is restarted, etc.

Hi @pagarcia,

There is no Rhino C++ SDK equivalent. But it isn’t too difficult to hook Google Analytics in C++ if needed.

– Dale

Hi @Matthew_Breau,


@pagarcia, if it is helpful, here is how I implemented in C#. It uses the google measurement protocol, which is about as “low-level” as GA gets… I execute all the web calls on a sep. thread so it can happen in the background and the program doesn’t hang.

I’ve set mine up to automatically read the plugin version number. All my components call the method defined here, with it’s two parameters.
google analytics.cs (3.1 KB)

Thank you Matthew! I’ll give it a try. This is a class that I should add to my project, compile it and then communication will be set up between the user using it and my Google Analytics account, right?


Hmmm, sort of, yeah.

If you’re using C++ then you’ll need to rewrite the functions, as they were written for C#.

You’ll need to get a “property id” from google analytics and hard-code it into the function.

The class handles the actual act of sending of the data to Google Analytics, but you still need to call the function when the trackable event is triggered by the user. You’ll also need tell it what to send (via the two parameters in the function).

Definitely read through the google help page regarding the Measurement Protocol, (which I linked to above) especially if you’ve never used GA before… GA is a pretty nice platform with the ability to receive a range of information, you’ll have to choose what to send and how to structure it. For example, I only really care about what components are being used and roughly how much “work” they are doing for the user… So I chose to implement it like this:

                { "ea", "calculation" }, //event action - set as "calculation",  indicating that the hit is being generated during calculation of a solution
                { "ec", nodeReportingHit }, //event category - set as name of the node generating the "hit"
                { "ev", hitValueString }, //event value - set as number, indicates the number of items processed 

Definitely spend some time thinking about what analytics info is important to you and designing an appropriate schema for it.

Feel free to ask if you have more questions :slight_smile:

Awesome! Thanks for the hints :smiley: