Understanding and Managing .NET CLI Telemetry: A Comprehensive Guide

The .NET SDK includes a telemetry feature that collects usage data and sends it to Microsoft when you use .NET CLI commands. This data collection includes information about exceptions if the .NET CLI crashes. The .NET CLI, which comes with the .NET SDK, is a set of commands that allows you to build, test, and publish your .NET applications. Telemetry data helps the .NET team understand how these tools are used, enabling them to improve the developer experience. Crash information is particularly valuable, assisting the team in diagnosing problems and fixing bugs.

The data collected is published in aggregate under the Creative Commons Attribution License. Some of the collected data is publicly available at .NET CLI Telemetry Data.

Scope of Telemetry Collection

The dotnet command serves two main purposes: running applications and executing CLI commands. Telemetry is not collected when you use dotnet to start applications in the following format:

  • dotnet [path-to-app].dll

Telemetry is collected when you use any of the .NET CLI commands, such as:

  • dotnet build
  • dotnet pack
  • dotnet run

How to Opt-Out of .NET CLI Telemetry

The .NET SDK telemetry feature is enabled by default in Microsoft distributions of the SDK. To opt out of this telemetry collection, you need to set the environment variable DOTNET_CLI_TELEMETRY_OPTOUT to 1 or true.

A single telemetry event is also sent by the .NET SDK installer upon successful installation. To opt out of this installer telemetry, set the DOTNET_CLI_TELEMETRY_OPTOUT environment variable before you install the .NET SDK.

Important: To opt out after you have already started the installer, you must close the installer, set the environment variable, and then run the installer again with the variable set.

Telemetry Disclosure

The .NET SDK displays a message similar to the following the first time you run one of the .NET CLI commands (for example, dotnet build). The exact text might vary slightly depending on the SDK version you are using. This “first-time use” experience is how Microsoft informs you about data collection:

Telemetry --------- The .NET tools collect usage data in order to help us improve your experience. The data is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell. Read more about .NET CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry

To suppress this message and the .NET welcome message, set the environment variable DOTNET_NOLOGO to true. Note that this variable only affects the messages and does not impact the telemetry opt-out setting.

Data Points Collected by .NET CLI Telemetry

Protecting your privacy is a priority for us. The telemetry feature does not collect personal data such as usernames or email addresses. It does not scan your code or extract project-level data like names, repositories, or authors. It also does not extract the contents of any data files accessed or created by your applications, memory dumps of your application objects, or clipboard content. Data is securely transmitted to Microsoft servers using Azure Monitor technology, stored under restricted access, and published under strict security controls within secure Azure Storage systems.

If you suspect that telemetry is collecting sensitive data or data that is handled insecurely or inappropriately, please raise an issue in the dotnet/sdk repository or send an email to for investigation.

The telemetry feature collects the following data points:

SDK Version Data Collected
All Invocation timestamp.
All Invoked command (e.g., “build”), hashed starting from 2.1.
All Truncated IP address (three octets) used to determine geographic location.
All Operating system and version.
All Runtime ID (RID) where the SDK is running.
All .NET SDK version.
All Telemetry profile: an optional value used only with explicit user opt-in and used internally at Microsoft.
>=2.0 Command arguments and options: certain arguments and options are collected (not arbitrary strings). See collected options. Hashed after 2.1.300.
>=2.0 Whether the SDK is running in a container.
>=2.0 Target framework (from TargetFramework event), hashed starting from version 2.1.
>=2.0 Hashed Media Access Control (MAC) address (SHA256).
>=2.0 Current working directory hashed.
>=2.0 Installation success report, with hashed installer exe filename.
>=2.1.300 Kernel version.
>=2.1.300 Libc version/release.
>=3.0.100 Whether output is redirected (true or false).
>=3.0.100 On CLI/SDK crash, exception type and stack trace (only CLI/SDK code is included in the stack trace sent). For more information, see Crash exception telemetry.
>=5.0.100 Hashed TargetFrameworkVersion used for the build (MSBuild property)
>=5.0.100 Hashed RuntimeIdentifier used for the build process (MSBuild property)
>=5.0.100 Hashed SelfContained used for compilation (MSBuild property)
>=5.0.100 Hashed UseApphost used for build (MSBuild property)
>=5.0.100 Hashed OutputType used for build (MSBuild property)
>=5.0.201 Hashed PublishReadyToRun used for build (MSBuild property)
>=5.0.201 Hashed PublishTrimmed used for build (MSBuild property)
>=5.0.201 Hashed PublishSingleFile used in the build process (MSBuild property)
>=5.0.202 Elapsed time from process start to entering the CLI program’s main method, measuring host and runtime startup time.
>=5.0.202 Elapsed time for the step that adds .NET Tools to the path on first execution.
>=5.0.202 Elapsed time to display the first-time usage notification on first execution.
>=5.0.202 Elapsed time for ASP.NET Certificate creation on first run.
>=5.0.202 Time taken to parse CLI input.
>=6.0.100 Operating System Architecture
>=6.0.104 Hashed PublishReadyToRunUseCrossgen2 used for build (MSBuild property)
>=6.0.104 Hashed Crossgen2Pack Version used for build (MSBuild property)
>=6.0.104 “Hashed CompileListCount” used for build (MSBuild property)
>=6.0.104 Hashed _ReadyToRunCompilationFailures used in the build process (MSBuild property)
>=6.0.300 Whether the CLI is invoked from a Continuous Integration environment. For more information, see Continuous Integration Detection.
>=7.0.100 MSBuild property ‘Hashed PublishAot’ used for build
>=7.0.100 Hashed Publish Protocol used for build (MSBuild property)
>=8.0.100 Hashed TargetPlatformIdentifier used for build (MSBuild property)
>=8.0.100 Hashed HybridGlobalization used for build (property in MSBuild)
>=8.0.100 Whether the .NET Blazor WebAssembly SDK is used.
>=8.0.100 Whether the .NET WebAssembly SDK is used.
>=8.0.100 Whether .NET MAUI is used.
>=8.0.100 Whether the .NET mobile SDK is used.
>=8.0.100 Whether other mobile SDKs are used (like: Avalonia, Uno).
>=8.0.100 Whether Mono AOT is used.
>=8.0.100 Whether IL strip feature on Mono AOT framework is used?
>=8.0.100 Whether Mono interpreter is used.
>=8.0.100 Whether library mode for mobile is used.
>=8.0.100 Whether NativeAOT is used.
>=8.0.100 Mono runtime package version used.

Collected Options and Arguments

Certain commands send additional data. A subset of commands sends the first argument:

Command First Argument Data Sent
dotnet help Help command being looked up.
dotnet new Template name (protected by hashing).
dotnet add The word package or reference.
dotnet remove The word package or reference.
dotnet list The word package or reference.
dotnet sln The word add, list, or remove.
dotnet nuget The word delete, locals, or push.
dotnet workload The words install, update, list, search, uninstall, repair, restore and workload name (hashed).
dotnet tool The words install, update, list, search, uninstall, run and dotnet tool name (hashed).

A subset of commands sends selected options if they are used, along with their values:

Option Commands
--verbosity All commands
--language dotnet new
--configuration dotnet build, dotnet clean, dotnet publish, dotnet run, dotnet test
--framework dotnet build, dotnet clean, dotnet publish, dotnet run, dotnet test, dotnet vstest
--runtime dotnet build, dotnet publish
--platform dotnet vstest
--logger dotnet vstest
--sdk-package-version dotnet migrate

When the SDK fails to execute a built-in command, any command resolver that successfully resolves the command sends the hashed name of the command along with the type name of the command resolver.

Except for --verbosity and --sdk-package-version, all other values are hashed starting with the .NET Core 2.1.100 SDK.

Telemetry for Template Instantiation

The dotnet new template instantiation command collects additional data for Microsoft-authored templates, starting with .NET Core 2.1.100 SDK:

  • --framework
  • --auth

Crash Exception Telemetry in .NET CLI

If the .NET CLI/SDK experiences a crash, it collects the exception name and stack trace from the CLI/SDK code. This information is gathered to help assess issues and improve the quality of the .NET SDK and CLI. This section provides details about the data collected and offers guidance for users building their own versions of the .NET SDK to avoid unintentional disclosure of personal or sensitive information.

The .NET CLI only collects information for CLI/SDK exceptions, not exceptions within your applications. The data collected includes the exception name and the stack trace, which originates from the CLI/SDK code.

The following example illustrates the type of data collected during a crash:

System.IO.IOException at System.ConsolePal.WindowsConsoleStream.Write(Byte[] buffer, Int32 offset, Int32 count) at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder) at System.IO.StreamWriter.Write(Char[] buffer) at System.IO.TextWriter.WriteLine() at System.IO.TextWriter.SyncTextWriter.WriteLine() at Microsoft.DotNet.Cli.Utils.Reporter.WriteLine() at Microsoft.DotNet.Tools.Run.RunCommand.EnsureProjectIsBuilt() at Microsoft.DotNet.Tools.Run.RunCommand.Execute() at Microsoft.DotNet.Tools.Run.RunCommand.Run(String[] args) at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, ITelemetry telemetryClient) at Microsoft.DotNet.Cli.Program.Main(String[] args)

Continuous Integration Detection

To detect if the .NET CLI is running within a Continuous Integration environment, the .NET CLI checks for the presence and values of several well-known environment variables set by common CI providers.

The complete list of environment variables and how their values are handled is shown below. Note that in each case, the value of the environment variable is never collected, only used to set a boolean flag.

Variable Provider Action
TF_BUILD Azure Pipelines Parses boolean value
GITHUB_ACTIONS GitHub Actions Parses boolean value
APPVEYOR Appveyor Parses boolean value
CI Many/Most Parses boolean value
TRAVIS Travis CI Parses boolean value
CIRCLECI Circle CI Parses boolean value
CODEBUILD_BUILD_ID, AWS_REGION Amazon Web Services CodeBuild Checks if all present and non-empty
BUILD_ID, BUILD_URL Jenkins Checks if all present and non-empty
BUILD_ID, PROJECT_ID Google Cloud Build Checks if all present and non-empty
TEAMCITY_VERSION TeamCity Checks if present and non-null
JB_SPACE_API_URL JetBrains Space Checks if present and non-null

Preventing Unintentional Information Disclosure

.NET contributors and anyone running self-built versions of the .NET SDK should be mindful of the path to their SDK source code. If a crash occurs while using a .NET SDK that is a custom debug build or configured with custom build symbol files, the SDK source file paths from the build machine are collected as part of the stack trace and are not hashed.

Therefore, custom builds of the .NET SDK should not be located in directories where the path names expose personal or sensitive information.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *