DesktopAnalytics.net
Wrapper around segment.io's Analytics.net specifically for desktop apps (instead of servers).
Install / Use
/learn @sillsdev/DesktopAnalytics.netREADME
DesktopAnalytics.net
Segment.IO provides a nice <i>server-oriented</i> library in Analytics-CSharp. This project wraps that to provide some standard behavior needed by .Net <i>desktop</i> applications:
- Supplies guids for user ids, saves that in a Settings file
- Looks up the machine's external IP address or geolocation and sends that along
- Set $Browser to the Operating System Version (e.g. "Windows 10").
- Auto events
- First launch ("Create" to fit MixPanel's expectation)
- Version Upgrade
Install
PM> Install-Package DesktopAnalytics
Usage
Initialization
using (new Analytics("mySegmentIOSecret"), userInfo)
{
// other setup, and eventually
Application.Run();
}
If you want to go beyond anonymous users, you can feed information about your user into DA like this:
var userInfo = new UserInfo()
{
FirstName = "John",
LastName = "Smith",
Email="john@example.com",
UILanguageCode= "fr"
};
userInfo.OtherProperties.Add("FavoriteColor","blue");
using (new Analytics("mySegmentIOSecret"), userInfo)
{
// other setup, and eventually
Application.Run();
}
If you have a way of letting users (or testers) disable tracking, pass that value as the second argument:
using (new Analytics("mySegmentIOSecret", allowTracking))
In this example, we use an environment variable so that testers and developers don't get counted:
#if DEBUG
//always track if this is a debug built, but track to a different segment.io project
using (new Analytics("(the secret for the debug version)"))
#else
// if this is a release build, then allow an envinroment variable to be set to false
// so that testers aren't generating false analytics
string feedbackSetting = System.Environment.GetEnvironmentVariable("FEEDBACK");
var allowTracking = string.IsNullOrEmpty(feedbackSetting) || feedbackSetting.ToLower() == "yes" || feedbackSetting.ToLower() == "true";
using (new Analytics("(the secret for the release version)", RegistrationDialog.GetAnalyticsUserInfo(), allowTracking))
{
// other setup, and eventually
Application.Run();
}
#endif
Tracking
Wherever you want to register that something happened, call Track on the static object named "Analytics":
Analytics.Track("Create New Image");
If you have properties you need to record, add them by passing in a Dictionary<string, string>, like this:
Analytics.Track("Save PDF", new Dictionary<string, string>() {
{"PageCount", pageCount},
{"Layout", "A4Landscape"}
});
Error Reporting
Analytics.ReportException(error);
If you've also got LibPalaso in your app, hook up its ExceptionHandler like this:
ExceptionHandler.AddDelegate((w,e) => DesktopAnalytics.Analytics.ReportException(e.Exception));
Dependencies
The project is currently built for .net 4 client profile. If you get the solution, nuget should auto-restore the two dependencies when you build; they are not part of the source tree.
Publishing
When changes are merged to master a github action will run dotnet pack and publish to Nuget. The publishing task can also be triggered by pushing a tag to the master branch.
License
MIT Licensed (As are the dependencies, Analytics.Net and Json.Net).
About Determining User's IP
DesktopAnalytics.net determines the user's ip by querying a website. Previously, it used ipecho.net, but that has gone down. It is currently using icanhazip.com. If that goes down too, we can change again. Your client can also use any other service you want by setting UrlThatReturnsExternalIpAddress.
Related Skills
feishu-drive
352.5k|
things-mac
352.5kManage Things 3 via the `things` CLI on macOS (add/update projects+todos via URL scheme; read/search/list from the local Things database)
clawhub
352.5kUse the ClawHub CLI to search, install, update, and publish agent skills from clawhub.com
codebase-memory-mcp
1.3kHigh-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds. 66 languages, sub-ms queries, 99% fewer tokens. Single static binary, zero dependencies.
