Application Insights SDK vs the OpenTelemetry Distro: which to use and how to migrate
For a new .NET, Node.js or Python app, Microsoft recommends the Microsoft OpenTelemetry Distro; apps already on the Azure Monitor OpenTelemetry Distro need no action, and Java uses the Azure Monitor OpenTelemetry Distro through its agent. For an app on the classic .NET SDK 2.x, which retires on March 31, 2027, the shortest path is SDK 3.x, which keeps TelemetryClient but runs on OpenTelemetry; the alternative is a clean move to the Distro. Both write the same Application Insights tables, so most queries and dashboards survive, with differences in sampling, names and custom dimensions to check.
Application Insights now has two current instrumentation paths for .NET and Node.js, and the names make it easy to confuse them. This guide sorts out which is which, what each one changes, and how to move without losing the queries and alerts you rely on.
The current paths
| Path | Packages | Keeps the classic API | Best for |
|---|---|---|---|
| Microsoft OpenTelemetry Distro | Microsoft.OpenTelemetry, @microsoft/opentelemetry, microsoft-opentelemetry | No; OpenTelemetry APIs | New apps; teams standardising on OpenTelemetry |
| Application Insights SDK 3.x | Microsoft.ApplicationInsights* 3.x, applicationinsights@^3 | Mostly (TelemetryClient, TrackEvent, GetMetric) | Existing 2.x apps; classic ASP.NET on .NET Framework |
| Azure Monitor OpenTelemetry Distro | Azure.Monitor.OpenTelemetry.AspNetCore, @azure/monitor-opentelemetry, azure-monitor-opentelemetry | No | Apps already using it; Java (agent or native) |
All three use the Azure Monitor exporter underneath and write the same Application Insights tables. Microsoft’s runtime floors for the Distro are Node.js 22, Python 3.10, and for .NET a supported runtime (the package targets net8.0 and netstandard2.0); Java needs Java 8 or later.
Don’t combine them. Microsoft says not to initialize an OpenTelemetry distro alongside SDK 3.x, not to initialize both distros in one app, and not to mix 2.x and 3.x packages.
Classic SDK 2.x
The status of the classic SDKs, as Microsoft and its update notices state it:
- .NET 2.x: deprecated, retires on March 31, 2027. The last 2.x release is 2.23.0.
- Node.js 2.x: retired.
- Java 2.x: retired on September 30, 2025; the 3.x agent replaces it.
- Python (OpenCensus): retired on September 30, 2024.
- Instrumentation-key-only configuration: support for ikey ingestion ended on March 31, 2025; use connection strings.
Retirement ends fixes and support. And the extension points a 2.x app relies on (initializers, processors, channels, modules) don’t exist in the newer paths, so the move is a project rather than a package bump. Plan it before you need a fix.
Concept map: 2.x to OpenTelemetry
| Classic 2.x | SDK 3.x | Microsoft OpenTelemetry Distro |
|---|---|---|
TrackRequest, request module | Kept; requests are server spans | Activity with ActivityKind.Server, or framework instrumentation |
TrackDependency, DependencyCollector | Kept; built-in HTTP and SQL collection | Activity with Client; bundled HttpClient, SqlClient, Azure SDK |
TrackTrace, ILogger provider | ILogger (TrackTrace routes to it) | ILogger |
TrackEvent | Kept (no metrics dictionary) | ILogger with microsoft.custom_event.name |
GetMetric, TrackMetric | Simplified GetMetric; OpenTelemetry name rules | Meter: Counter, Histogram, Gauge |
TrackPageView | Removed | JavaScript SDK in the browser |
ITelemetryInitializer | OpenTelemetry processor, GlobalProperties | BaseProcessor<Activity>, resource attributes |
ITelemetryProcessor (filtering) | OpenTelemetry processor | Processor or sampler |
ITelemetryChannel, ServerTelemetryChannel | Azure Monitor exporter (StorageDirectory) | Azure Monitor exporter (StorageDirectory) |
| Adaptive sampling | TracesPerSecond (default 5) or SamplingRatio | TracesPerSecond (default 5) or SamplingRatio |
Cloud.RoleName, Component.Version | service.name, service.version | service.name, service.version |
ApplicationInsights.config | Flat applicationinsights.config, appsettings.json | Environment variables and options |
DeveloperMode | Removed | ExportTarget.Console for local checks |
| Operation ID, parent ID | Trace ID, span ID | Trace ID, span ID |
The guides on initializers and processors, channels and exporters, sampling and custom metrics go through each row in detail.
Today: choosing between SDK 3.x and the Distro
Choose SDK 3.x when the app calls TelemetryClient in many places, when it’s classic ASP.NET on .NET Framework (the Distro’s built-in request instrumentation is for ASP.NET Core), or when you want the migration in two steps: first runtime, later APIs. Microsoft describes 3.x as the way to minimise re-instrumentation; most Track* calls keep working through a mapping layer that emits OpenTelemetry signals.
Choose the Distro for new apps, for services where you’d like the option to export elsewhere (the .NET Distro can export to Azure Monitor and an OTLP endpoint at once, ExportTarget.AzureMonitor | ExportTarget.Otlp, though Microsoft notes it doesn’t officially support the OTLP exporter itself), and when you’re rewriting custom telemetry anyway.
What you give up, on either path: per-type sampling (one rate covers requests and dependencies, though logs can follow traces), TrackPageView in .NET, and every classic initializer, processor and module, which have to be rewritten. Microsoft also lists known issues of the OpenTelemetry exporters: the operation name is missing from dependency telemetry, which affects the Failures and Performance views for dependencies, and the device model is missing from requests and dependencies.
Migration steps for a .NET 2.x app
To SDK 3.x:
- Remove the packages with no 3.x version:
WindowsServer.TelemetryChannel,DependencyCollector,EventCounterCollector,PerfCounterCollector,WindowsServer,Microsoft.Extensions.Logging.ApplicationInsights,Log4NetAppender,TraceListener,DiagnosticSourceListener,EtwCollector,EventSourceListener. Check third-party packages that depend on 2.x, such as the Serilog sink. - Upgrade every remaining Application Insights package to 3.x together.
- Fix the breaking changes: a full connection string is required (3.x can fail at startup without one);
TelemetryConfiguration.Activeandnew TelemetryClient()becomeTelemetryConfiguration.CreateDefault(); metric names must start with a letter and use only letters, digits,_ . - /;TrackPageViewand the metrics-dictionary overloads go. - Rewrite initializers and processors as OpenTelemetry processors, and replace
EnableAdaptiveSamplingwithTracesPerSecondorSamplingRatio. - Validate with self-diagnostics and a console exporter before relying on Azure Monitor.
To the Distro: remove the Application Insights packages, add Microsoft.OpenTelemetry, register it at startup, and move custom telemetry to ActivitySource, Meter and ILogger.
The startup change for an ASP.NET Core app moving from 2.x to the Distro:
// Before (2.x)
builder.Services.AddApplicationInsightsTelemetry();
// After (Microsoft OpenTelemetry Distro)
builder.UseMicrosoftOpenTelemetry(options =>
{
options.Exporters = ExportTarget.AzureMonitor; // reads APPLICATIONINSIGHTS_CONNECTION_STRING
});
Node.js offers the same two choices: a clean install of @microsoft/opentelemetry (call useMicrosoftOpenTelemetry() before loading the libraries you want instrumented), or npm install applicationinsights@^3 to keep the classic API on OpenTelemetry. Python apps on OpenCensus uninstall the OpenCensus libraries, remove them from the code, and set up microsoft-opentelemetry. Java apps replace the 2.x SDK with the 3.x agent; 2.x initializers and processors don’t run under it.
Keep queries, dashboards and alerts working
Table and column names don’t change: requests are still in requests (AppRequests), with the same operation_Id and customDimensions. What changes is what’s inside them, so before switching production, run the new build in one environment and compare by application_Version:
union requests, dependencies
| where timestamp > ago(1d)
| summarize items = sum(itemCount), names = dcount(name) by itemType, application_Version, sdkVersion
Check four things. Names: request names follow the route template, and unmatched routes become just the method, as in how requests are named. Custom dimension keys: attribute names from OpenTelemetry instrumentation can differ from 2.x property names, so update queries that filter on them. Counts: sampling changes from adaptive to rate-limited at five traces per second, so alerts built on count() need sum(itemCount). Role names: set service.name so cloud_RoleName matches what dashboards expect.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Duplicate telemetry after migrating | Two pipelines active (2.x plus Distro, or two distros) | Keep one |
| 3.x app won’t start | No connection string | Set APPLICATIONINSIGHTS_CONNECTION_STRING |
| Custom properties gone | Initializers don’t run in 3.x or the Distro | Rewrite as processors |
| Metric missing after 3.x upgrade | Name not valid OpenTelemetry syntax | Rename the metric |
| Dependency rows lack operation name | Known exporter issue | Group by operation_Id or the parent request instead |
| Volume or counts changed | New sampling defaults | Check itemCount; tune TracesPerSecond |
Queries for this topic
-
Sampling rate in effect, per telemetry type
requestsdependenciespageViewsbrowserTimingsexceptionstracescustomEventsavailabilityResults cost
Returns: One row per telemetry type with the rows stored, the items they stand for, and the percentage of items kept by sampling over the last 24 hours.
-
Dependency calls per request, by operation
requestsdependencies dependencies
Returns: One row per request operation with its request count, the dependency calls made under that operation name and the average calls per request, chattiest first.
Frequently asked questions
Is the Application Insights SDK deprecated?
The .NET Classic API SDK 2.x is deprecated and retires on March 31, 2027; the Node.js 2.x SDK is already retired. The classic packages continue as SDK 3.x, built on OpenTelemetry, for .NET and Node.js. The Java 2.x SDK was retired on September 30, 2025, and OpenCensus for Python on September 30, 2024.
Do I have to move to the Microsoft OpenTelemetry Distro if I use the Azure Monitor OpenTelemetry Distro?
No. Microsoft's guidance for apps already on the Azure Monitor OpenTelemetry Distro is "No action needed". Don't initialize both distros in the same app. Because both use the same OpenTelemetry APIs, switching later is mostly a package and startup change.
Will my KQL queries and dashboards still work after migrating?
Mostly. Both paths write the same requests, dependencies, traces, exceptions and customMetrics tables. Check request and dependency names, custom dimension keys, role names and counts: sampling defaults change to five traces per second, so weight counts with itemCount.
Sources, checked
- Enable OpenTelemetry in Application Insights (which path to use)
- Migrate Application Insights Classic API SDKs to OpenTelemetry
- Monitor .NET and Node.js applications with Application Insights (Classic API 2.x)
- Migration guidance from 2.x to 3.x (ApplicationInsights-dotnet)
- Configure OpenTelemetry in Application Insights
- Add and modify OpenTelemetry in Application Insights
- Troubleshoot OpenTelemetry issues in .NET (known issues)
- Microsoft.OpenTelemetry (Microsoft OpenTelemetry Distro for .NET, README)