{"id":18711724,"url":"https://github.com/keenlabs/keen-sdk-net","last_synced_at":"2025-07-29T15:31:19.647Z","repository":{"id":14996894,"uuid":"17722261","full_name":"keenlabs/keen-sdk-net","owner":"keenlabs","description":"A .NET SDK for the Keen IO API","archived":false,"fork":false,"pushed_at":"2017-11-16T03:29:10.000Z","size":1073,"stargazers_count":37,"open_issues_count":33,"forks_count":23,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-07-22T10:21:37.685Z","etag":null,"topics":["analysis","analytics","dotnet","keen-io","sdk","windows","xamarin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/keenlabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-13T18:56:49.000Z","updated_at":"2023-06-02T22:44:13.000Z","dependencies_parsed_at":"2022-09-23T04:02:00.855Z","dependency_job_id":null,"html_url":"https://github.com/keenlabs/keen-sdk-net","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/keenlabs/keen-sdk-net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keenlabs%2Fkeen-sdk-net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keenlabs%2Fkeen-sdk-net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keenlabs%2Fkeen-sdk-net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keenlabs%2Fkeen-sdk-net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/keenlabs","download_url":"https://codeload.github.com/keenlabs/keen-sdk-net/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/keenlabs%2Fkeen-sdk-net/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267709567,"owners_count":24131914,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analysis","analytics","dotnet","keen-io","sdk","windows","xamarin"],"created_at":"2024-11-07T12:40:37.854Z","updated_at":"2025-07-29T15:31:19.280Z","avatar_url":"https://github.com/keenlabs.png","language":"C#","funding_links":[],"categories":["C# #"],"sub_categories":[],"readme":"keen-sdk-net\n============\n\n[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/sxkqpvmlxto07y4r/branch/master?svg=true)](https://ci.appveyor.com/project/masojus/keen-sdk-net/branch/master) [![Travis CI Build Status](https://travis-ci.org/keenlabs/keen-sdk-net.svg?branch=master)](https://travis-ci.org/keenlabs/keen-sdk-net) [![Coverage Status](https://coveralls.io/repos/github/keenlabs/keen-sdk-net/badge.svg?branch=master)](https://coveralls.io/github/keenlabs/keen-sdk-net?branch=master) [![NuGet](http://img.shields.io/nuget/v/KeenClient.svg)](https://www.nuget.org/packages/KeenClient/)\n\nOverview\n-----\n\nThe Keen IO .NET SDK can be used to do custom analytics and event tracking for .NET applications. Use this SDK to capture large volumes of event data such as user actions, errors, server interactions, or any arbitrary event you specify. The SDK posts your events to Keen IO, a highly available, scalable cloud datastore. See [Keen IO docs](https://keen.io/docs) for instructions on extracting, querying, and building custom analytics with your data.\n\n.NET Version Support\n------------\n\nThe .NET SDK is currently comprised of a single project which produces two DLLs from which to choose based on the target platform.\n\nThis class library currently multi-targets .NET Standard 2.0 and .NET Framework 4.5. These two libraries should be able to cover most scenarios, including .NET Framework, .NET Standard in various environments/operating systems, UWP, Unity, Xamarin and other types of projects.\n\nInstallation\n------------\n\nThe easiest way to get started with the Keen IO .NET SDK is to use the [KeenClient NuGet package](http://www.nuget.org/packages/KeenClient/).\n\nInstall the NuGet package by running the following command from the NuGet Package Manager Console:\n\n```\nPM\u003e Install-Package KeenClient\n```\n\n...or if using the .NET Core SDK tools:\n```\n$ dotnet add package KeenClient\n```\n\nThe most up-to-date code is available in the following repository:\n\n```\nhttps://github.com/keenlabs/keen-sdk-net\n```\n\nInitializing the Library\n------------------------\n\nThe core object you'll interact with to add events to a collection is the `KeenClient` object. When creating a `KeenClient` instance, you'll want to provide it with a `ProjectSettingsProvider` instance that contains details about your project id, keys, and optionally a different root URL for Keen.IO's API.\n\n```\nusing Keen.Core;\n...\nvar projectSettings = new ProjectSettingsProvider(\"YourProjectID\", writeKey: \"YourWriteKey\");\nvar keenClient = new KeenClient(projectSettings);\n```\n\nRecording Events\n----------------\n\nEvent data is provided to the client as an object. A simple way to do this is with an anonymous object:\n\n```\nvar purchase = new\n{\n    category = \"magical animals\",\n    username = \"hagrid\",\n    price = 7.13,\n    payment_type = \"information\",\n    animal_type = \"norwegian ridgeback dragon\"\n};\n\nkeenClient.AddEvent(\"purchases\", purchase);\n```\n\nRecording Events Asynchronously\n-------------------------------\n\nSometimes you want to record events in a non-blocking manner. This is pretty simple:\n\n```\nkeenClient.AddEventAsync(\"purchases\", purchase);\n```\n\nUsing Global Properties\n-----------------------\n\nStatic global properties are added with the `KeenClient`'s `AddGlobalProperty` method:\n\n```\nkeenClient.AddGlobalProperty(\"client_type\", \"mobile\");\n```\n\nStatic global properties are added at the root level of all events just before they are sent or cached.\n\nDynamic global properties are an SDK concept that can be added in the same way, but rather than a static object, an object implementing `IDynamicPropertyValue` is added. The class `DynamicPropertyValue` implements this interface and may be used to provide dynamic properties with a `Func\u003cobject\u003e` delegate:\n\n```\nvar dynProp = new DynamicPropertyValue(() =\u003e new Random().Next(9999));\nkeenClient.AddGlobalProperty(\"bonus_field\", dynProp);\n```\n\nThe delegate is executed each time event data is added as well as during the `AddGlobalProperty` call.\n\nUsing Data Enrichment Add-ons\n------------------------------\n\nKeen IO can enrich event data by parsing or joining it with other data sets. This is done through the concept of “add-ons”. See the [Keen IO API documentation](https://keen.io/docs/api/#data-enrichment) for more on this. The .NET SDK enables add-ons with the `Keen.DataEnrichment.AddOn` class.\n\n```\n// Build an event object\nvar purchase = new\n{\n    category = \"magical animals\",\n    username = \"hagrid\",\n    price = 7.13,\n    payment_type = \"information\",\n    animal_type = \"norwegian ridgeback dragon\",\n    user_ip = \"8.8.8.8\",\n    ua = \"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; .NET CLR 1.0.3705)\"\n};\n\nvar addOns = new[]\n{\n    AddOn.IpToGeo(\"user_ip\", \"user_geo\"),\n    AddOn.UserAgentParser(\"ua\", \"user_agent\")\n};\n\n// send the event\nkeenClient.AddEvent(\"purchases\", purchase, addOns);\n```\n\nWhen the event is recorded the \"user_geo\" and \"user_agent\" fields will be populated automatically by the Keen IO API.\n\nComplete Event Recording Example\n------------\n\n```\nstatic void Main(string[] args)\n{\n    // Set up the client\n    var projectSettings = new ProjectSettingsProvider(\"YourProjectID\", writeKey: \"YourWriteKey\");\n    var keenClient = new KeenClient(projectSettings);\n\n    keenClient.AddGlobalProperty(\"client_type\", \"mobile\");\n\n    var dynProp = new DynamicPropertyValue(() =\u003e new Random().Next(9999));\n    keenClient.AddGlobalProperty(\"bonus_field\", dynProp );\n\n    // Build an event object\n    var purchase = new\n    {\n        category = \"magical animals\",\n        username = \"hagrid\",\n        price = 7.13,\n        payment_type = \"information\",\n        animal_type = \"norwegian ridgeback dragon\",\n        user_ip = \"8.8.8.8\",\n        ua = \"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; .NET CLR 1.0.3705)\"\n    };\n\n    var addOns = new[]\n    {\n        AddOn.IpToGeo(\"user_ip\", \"user_geo\"),\n        AddOn.UserAgentParser(\"ua\", \"user_agent\")\n    };\n\n    // send the event\n    keenClient.AddEvent(\"purchases\", purchase, addOns);\n}\n```\n\nCaching\n-------\n\nKeenClient supports an event data cache interface that allows transmission of event data to the Keen IO server to be deferred until you call SendCachedEvents(). You may implement your own cache by supporting the IEventCache interface or you may use one of the two cache classes included, EventCacheMemory and EventCachePortable which store event data in memory and in portable storage, respectively.\n\nTo enable caching provide an instance supporting IEventCache when constructing KeenClient:\n\n```\nvar client = new KeenClient(new ProjectSettingsProviderEnv(), new EventCacheMemory());\n```\n\nOr:\n\n```\nvar client = new KeenClient(new ProjectSettingsProviderEnv(), EventCachePortable.New());\n```\n\nEvents are added as usual, and at any time you may transmit the cached events to the server:\n\n```\nclient.SendCachedEvents();\n```\n\nThe server may reject one or more events included in the cache. If this happens the item that was rejected will be recorded and transmission of the remaining cached events will continue. After all events in the cache have been transmitted, if any events were rejected they will be attached as instances of CachedEvent to an instance of KeenBulkException which will then be thrown. The KeenBulkException FailedEvents property may be accessed to review the failures.\n\nGlobal properties are evaluated and added when AddEvent() is called, so dynamic properties will not be evaluated when SendCachedEvents() is called.\n\nAnalysis\n------------\n\nTo run [analyses](https://keen.io/docs/api/#analyses) on your data, use the provided `KeenClient.Query` family of methods. For example:\n\n```\nvar itemCount = keenClient.Query(QueryType.Count(), \"target_collection\", null);\n```\n\nAn `async` version of this analysis could be run as follows:\n\n```\nvar itemCount = await keenClient.QueryAsync(QueryType.Count(), \"target_collection\", null);\n```\n\nAdditional qualifiers can be added to the analysis, such as the target property to use for analyses that require it. A timeframe and/or list of filters to use for the analysis can also be provided. If you'd like to get results in a grouped or time interval format, the `KeenClient.QueryGroup`, `KeenClient.QueryInterval`, and `KeenClient.QueryIntervalGroup` synchronous and asynchronous methods can be used. See the Grouped and Interval Query Results and Filters sections below for more detail.\n\n\nMulti-Analysis\n------------\n\nMulti-analysis is a way to run multiple analyses over the same dataset. For more information about multi-analysis, see the [API documentation](https://keen.io/docs/api/#multi-analysis).\n\nTo perform multi-analysis, use the `KeenClient.QueryMultiAnalysis` family of methods.\n\n```\nIEnumerable\u003cMultiAnalysisParam\u003e analyses = new List\u003cMultiAnalysisParam\u003e()\n{\n    new MultiAnalysisParam(\"purchases\", MultiAnalysisParam.Metric.Count()),\n    new MultiAnalysisParam(\"max_price\", MultiAnalysisParam.Metric.Maximum(\"price\")),\n    new MultiAnalysisParam(\"min_price\", MultiAnalysisParam.Metric.Minimum(\"price\"))\n};\n\nvar result = keenClient.QueryMultiAnalysis(\"purchases\", analyses);\n\nvar purchases = int.Parse(result[\"purchases\"]);\nvar maxPrice = float.Parse(result[\"max_price\"]);\n```\n\n\nFunnel Analysis\n------------\n\nReturns the number of unique actors that successfully (or unsuccessfully) make it through a series of steps. “Actors” could mean users, devices, or any other identifiers that are meaningful to you. For more information about Funnels, see the [Funnel API documentation](https://keen.io/docs/api/#funnels).\n\nTo perform funnel analysis, `KeenClient` exposes the methods `QueryFunnel` and `QueryFunnelAsync`, which are used as follows:\n\n```\nIEnumerable\u003cFunnelStep\u003e funnelSteps = new List\u003cFunnelStep\u003e\n{\n    new FunnelStep\n    {\n        EventCollection = \"registered_users\",\n        ActorProperty = \"id\"\n    },\n    new FunnelStep\n    {\n        EventCollection = \"subscribed_users\",\n        ActorProperty = \"user_id\"\n    },\n};\n\nvar result = keenClient.QueryFunnel(funnelSteps);\n\nvar registeredUsers = result.ElementAt(0);\nvar registeredAndSubscribedUserCount = result.ElementAt(1);\n```\n\nTimeframes\n------------\n\nA timeframe can be specified for analysis using the `QueryRelativeTimeframe` and `QueryAbsoluteTimeframe` classes, along with an optional `timezone` parameter passed to the `KeenClient.Query` method when using `QueryRelativeTimeframe`. The `timezone` parameter must be one of the timezones supported by the Keen IO API as specified [here](https://keen.io/docs/api/#timezone).\n\nFor example:\n```\nvar relativeTimeframe = QueryRelativeTimeframe.ThisWeek();\nvar timezone = \"US/Pacific\"; // If not specified, timezone defaults to \"UTC\"\n\nvar countUnique = keenClient.Query(QueryType.CountUnique(), \"target_collection\", \"target_property\", relativeTimeframe, timezone: timezone);\n```\n\nHere's an example using an absolute timeframe. Note that timezone information is included in the DateTime struct, and therefore shouldn't be provided as an additional parameter.\n```\nvar absoluteTimeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddMonths(-1), DateTime.Now));\n\nvar countUnique = keenClient.Query(QueryType.CountUnique(), \"target_collection\", \"target_property\", absoluteTimeframe);\n```\n\n\nFilters\n------------\n\nAnalyses, multi-analysis, and funnel steps all support using filters to be more specific about the dataset being worked on. For simple analyses and multi-analyses, provide an `IEnumerable\u003cQueryFilter\u003e` to the `KeenClient.Query` or `KeenClient.QueryMultiAnalysis` method of choice. For funnel analysis, filters can be specified on each `FunnelStep` through the `FunnelStep.Filters` property.\n\n```\nvar filters = new List\u003cQueryFilter\u003e()\n{\n    new QueryFilter(\"field1\", QueryFilter.FilterOperator.GreaterThan(), \"1\")\n};\n\nvar result = keenClient.Query(QueryType.Count(), \"user_registrations\", null, filters: filters);\n```\n\nGrouped and Interval Query Results\n------------\n\nTo perform analysis or multi-analysis with results grouped by a column value, separated by a timeframe, or a combination of both, there are versions of the `KeenClient.Query` and `KeenClient.QueryMultiAnalysis` methods available. These include `KeenClient.QueryInterval`, `KeenClient.QueryGroup`, `KeenClient.QueryIntervalGroup` and their corresponding asynchronous methods for single-analysis. For multi-analysis, similar methods exist including `KeenClient.QueryMultiAnalysisGroup`, `KeenClient.QueryMultiAnalysisInterval`, `KeenClient.QueryMultiAnalysisIntervalGroup`, and the asynchronous versions of those methods. See the Keen IO [group by](https://keen.io/docs/api/#group-by) and [interval](https://keen.io/docs/api/#interval) API documentation for more about these types of analyses.\n\n\nScoped Keys\n------------\n\nScoped keys are customized API keys you can generate yourself. Each key has a defined scope of allowed operations (read/write), along with a set of predetermined filters that are applied to every request. See the [Keen IO API reference](https://keen.io/docs/api/#scoped-keys) for more information on scoped keys.\n\nThe .NET SDK includes methods for generating scoped keys. You'll find them under the `Keen.Core` namespace as `ScopedKey.Encrypt`, `ScopedKey.EncryptString`, and `ScopedKey.Decrypt`.\n\n\n```\n// Create a filter to apply when using the scoped key\nIDictionary\u003cstring, object\u003e filter = new ExpandoObject();\nfilter.Add(\"property_name\", \"account_id\");\nfilter.Add(\"operator\", \"eq\");\nfilter.Add(\"property_value\", 123);\n\ndynamic options = new ExpandoObject();\n// Set filters for the key\noptions.filters = new List\u003cobject\u003e() { filter };\n// Set read/write permissions for the key\noptions.allowed_operations = new List\u003cstring\u003e() { \"read\" };\n\n// Generate the key using the given master key and options\nvar scopedKey = ScopedKey.Encrypt(masterKey, (object)options);\n\n// Decrypt the key to get the key's filters and permissions\nvar decrypted = ScopedKey.Decrypt(masterKey, scopedKey);\nvar decryptedOptions = JObject.Parse(decrypted);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeenlabs%2Fkeen-sdk-net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkeenlabs%2Fkeen-sdk-net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkeenlabs%2Fkeen-sdk-net/lists"}