From 28889dc2376488c893de04835723bb9dd079e7ed Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 20 Feb 2026 20:46:45 +0000
Subject: [PATCH 1/3] Initial plan
From 23efef3ae16d59af09666184596cefe3628c8465 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 20 Feb 2026 20:53:46 +0000
Subject: [PATCH 2/3] Add Blazor WASM telemetry section and post-deployment
telemetry docs
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
---
.../config/sidebar/dashboard.topics.ts | 4 +
.../dashboard/enable-browser-telemetry.mdx | 137 +++++++++++++
.../dashboard/telemetry-after-deployment.mdx | 190 ++++++++++++++++++
3 files changed, 331 insertions(+)
create mode 100644 src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
diff --git a/src/frontend/config/sidebar/dashboard.topics.ts b/src/frontend/config/sidebar/dashboard.topics.ts
index 45f5f773e..53316000b 100644
--- a/src/frontend/config/sidebar/dashboard.topics.ts
+++ b/src/frontend/config/sidebar/dashboard.topics.ts
@@ -221,5 +221,9 @@ export const dashboardTopics: StarlightSidebarTopicsUserConfig = {
},
slug: 'dashboard/microsoft-collected-dashboard-telemetry',
},
+ {
+ label: 'Telemetry after deployment',
+ slug: 'dashboard/telemetry-after-deployment',
+ },
],
};
diff --git a/src/frontend/src/content/docs/dashboard/enable-browser-telemetry.mdx b/src/frontend/src/content/docs/dashboard/enable-browser-telemetry.mdx
index ede8144ac..8b2b5d225 100644
--- a/src/frontend/src/content/docs/dashboard/enable-browser-telemetry.mdx
+++ b/src/frontend/src/content/docs/dashboard/enable-browser-telemetry.mdx
@@ -306,7 +306,144 @@ The bundling and minification of the JavaScript code is beyond the scope of this
For the complete working example of how to configure the JavaScript OTEL SDK to send telemetry to the dashboard, see the [browser telemetry sample](https://github.com/dotnet/aspire/tree/main/playground/BrowserTelemetry).
+## Blazor WebAssembly integration
+
+Blazor WebAssembly (WASM) apps run entirely in the browser using a .NET runtime compiled to WebAssembly. Like other browser apps, Blazor WASM apps use the [JavaScript OTEL SDK](https://opentelemetry.io/docs/languages/js/getting-started/browser/) to send telemetry to the Aspire dashboard via JavaScript interop. The dashboard configuration for [OTLP HTTP](#otlp-configuration) and [CORS](#cors-configuration) described earlier in this article applies to Blazor WASM apps as well.
+
+### Provide OTEL configuration to the browser
+
+Blazor WASM apps can't read server-side environment variables directly. When the app is hosted by an ASP.NET Core server (for example, a Blazor Web App or hosted Blazor WASM project), expose the OTEL configuration through an API endpoint on the server:
+
+```csharp title="C# — Program.cs (Server)"
+app.MapGet("/api/telemetry-config", () => new
+{
+ Endpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ?? string.Empty,
+ Headers = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS") ?? string.Empty,
+ ResourceAttributes = Environment.GetEnvironmentVariable("OTEL_RESOURCE_ATTRIBUTES") ?? string.Empty
+})
+.AllowAnonymous();
+```
+
+
+
+### Initialize OTEL from a Blazor component
+
+In the Blazor WASM app, call the JavaScript `initializeTelemetry` function using `IJSRuntime` after the component has rendered. Add the [JavaScript OTEL SDK initialization code](#example-browser-telemetry-code) to a JavaScript file bundled with your app, then call it from a Razor component:
+
+```razor title="Razor — TelemetryInitializer.razor (Client)"
+@inject IJSRuntime JS
+@inject HttpClient Http
+
+@code {
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ var config = await Http.GetFromJsonAsync("/api/telemetry-config");
+ if (config is { Endpoint.Length: > 0 })
+ {
+ await JS.InvokeVoidAsync(
+ "initializeTelemetry",
+ config.Endpoint,
+ config.Headers,
+ config.ResourceAttributes);
+ }
+ }
+ }
+
+ private sealed record TelemetryConfig(
+ string Endpoint,
+ string Headers,
+ string ResourceAttributes);
+}
+```
+
+Include this component in your `App.razor` or another top-level component so that telemetry is initialized when the app loads.
+
+### Backend-to-frontend trace correlation
+
+To correlate browser spans with server-side traces, include the current trace context in the server-rendered HTML. When the Blazor WASM app is hosted within a server-rendered page (such as a Blazor Web App with prerendering), the server can write the `traceparent` meta tag during prerender:
+
+```razor title="Razor — App.razor (Server prerender)"
+@using System.Diagnostics
+
+
+
+ @if (Activity.Current is { } currentActivity)
+ {
+
+ }
+
+
+```
+
+The JavaScript OTEL SDK reads this `traceparent` value automatically when `DocumentLoadInstrumentation` is registered, linking the browser spans to the originating server trace.
+
+### Authenticated OTEL proxy
+
+When the Aspire dashboard's OTLP API key must not be exposed to the browser, route telemetry through a server-side proxy endpoint. The browser sends telemetry to the proxy, and the proxy forwards it to the dashboard with the API key included as a server-side secret:
+
+```csharp title="C# — Program.cs (Server proxy endpoint)"
+// Register an HttpClient for the OTEL proxy
+builder.Services.AddHttpClient("otel-proxy");
+
+// ...
+
+app.MapPost("/api/telemetry/{**path}", async (
+ string path,
+ HttpContext context,
+ IHttpClientFactory httpClientFactory) =>
+{
+ var dashboardEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT");
+ if (string.IsNullOrEmpty(dashboardEndpoint))
+ {
+ return Results.NotFound();
+ }
+
+ var client = httpClientFactory.CreateClient("otel-proxy");
+
+ // Copy OTLP API key from server environment to forwarded request
+ var headersEnv = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS") ?? string.Empty;
+ foreach (var header in headersEnv.Split(',', StringSplitOptions.RemoveEmptyEntries))
+ {
+ var parts = header.Split('=', 2);
+ if (parts.Length == 2)
+ {
+ client.DefaultRequestHeaders.TryAddWithoutValidation(parts[0].Trim(), parts[1].Trim());
+ }
+ }
+
+ using var requestBody = new StreamContent(context.Request.Body);
+ requestBody.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue
+ .Parse(context.Request.ContentType ?? "application/x-protobuf");
+
+ var response = await client.PostAsync(
+ $"{dashboardEndpoint.TrimEnd('/')}/{path}",
+ requestBody);
+
+ context.Response.StatusCode = (int)response.StatusCode;
+ await response.Content.CopyToAsync(context.Response.Body);
+ return Results.Empty;
+});
+```
+
+Configure the JavaScript OTEL SDK in the Blazor WASM app to point to the proxy endpoint instead of the dashboard directly:
+
+```javascript title="JavaScript — telemetry.js (Client)"
+export function initializeTelemetry(resourceAttributes) {
+ const otlpOptions = {
+ url: '/api/telemetry/v1/traces' // Proxy endpoint, same origin - no CORS needed
+ };
+ // ... rest of SDK initialization
+}
+```
+
+This pattern eliminates the need for CORS configuration on the dashboard because the browser communicates only with the same-origin server. The API key stays on the server and is never visible to the browser.
+
## See also
- [Aspire dashboard configuration](/dashboard/configuration/)
- [Standalone Aspire dashboard](/dashboard/standalone/)
+- [Telemetry after deployment](/dashboard/telemetry-after-deployment/)
diff --git a/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx b/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
new file mode 100644
index 000000000..3eecfdf64
--- /dev/null
+++ b/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
@@ -0,0 +1,190 @@
+---
+title: Telemetry after deployment
+description: Understand how telemetry and the Aspire dashboard work after you deploy your app, and how to configure production-grade observability.
+---
+
+import { Aside, Steps } from '@astrojs/starlight/components';
+import LearnMore from '@components/LearnMore.astro';
+
+The Aspire dashboard is designed for local development and short-term diagnostics. It stores telemetry in memory, which means telemetry is lost when the dashboard restarts and there are built-in limits on how much data it retains. After deploying your app to a production environment, you need to configure a persistent telemetry backend.
+
+This article explains what changes when you deploy your app, how to configure production telemetry with Azure Monitor, and how to access the Aspire dashboard if it's included in your deployment.
+
+## Development vs. production telemetry
+
+During development, Aspire automatically starts the dashboard and configures your app's OTEL environment variables to send telemetry to it. This works well for local diagnostics but is not suitable for production for the following reasons:
+
+| | Aspire dashboard | Production telemetry backend |
+|---|---|---|
+| **Storage** | In-memory only | Persistent (database, cloud service) |
+| **Retention** | Lost on restart | Configurable (days, months, indefinitely) |
+| **Telemetry limits** | Default 10,000 log entries, 10,000 traces | Configurable or unlimited |
+| **Access** | Local or private | Secured, multi-user |
+| **Alerting** | None | Configurable alerts and dashboards |
+
+After deploying, configure your app to send telemetry to a persistent backend. Azure Monitor with Application Insights is the recommended production telemetry solution for Azure-hosted apps.
+
+## Configure Azure Monitor for production telemetry
+
+[Azure Monitor](https://learn.microsoft.com/azure/azure-monitor/overview) collects, analyzes, and responds to telemetry data from your cloud applications. Aspire has built-in support for Azure Application Insights, which is the Azure Monitor feature for application telemetry.
+
+### Add Application Insights to your AppHost
+
+Add the Application Insights resource to your AppHost project:
+
+```csharp title="C# — AppHost.cs"
+var builder = DistributedApplication.CreateBuilder(args);
+
+var insights = builder.AddAzureApplicationInsights("app-insights");
+
+builder.AddProject("apiservice")
+ .WithReference(insights);
+
+builder.AddProject("webfrontend")
+ .WithReference(insights)
+ .WithExternalHttpEndpoints();
+
+builder.Build().Run();
+```
+
+When you reference Application Insights, Aspire automatically configures the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable for each service. The `Microsoft.Extensions.Azure` OTEL integration reads this variable and sends telemetry to Application Insights.
+
+
+
+### Use OpenTelemetry with Azure Monitor
+
+Add the [📦 Azure.Monitor.OpenTelemetry.AspNetCore](https://www.nuget.org/packages/Azure.Monitor.OpenTelemetry.AspNetCore) package to each service project to enable OTEL-based export to Azure Monitor:
+
+```csharp title="C# — Program.cs (service)"
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults();
+
+// Add Azure Monitor OTEL export when connection string is available
+builder.Services.AddOpenTelemetry()
+ .UseAzureMonitor();
+```
+
+Aspire's service defaults already configure OpenTelemetry. The `UseAzureMonitor()` call adds Azure Monitor as an additional exporter. When the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable is set (which Aspire does automatically when the resource is referenced), telemetry flows to Azure Monitor.
+
+
+For more information, see [Azure Monitor OpenTelemetry documentation](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable).
+
+
+## Troubleshoot missing logs after deployment
+
+If some or all logs don't appear in your telemetry backend after deployment, check the following common causes.
+
+### OTEL environment variables not set
+
+Verify that the OTEL environment variables are correctly set in your deployed containers. When deploying to Azure Container Apps, Aspire sets these variables automatically when you use `WithReference` for Application Insights or when the OTEL endpoint is configured.
+
+Check for these environment variables in your deployed container:
+
+- `OTEL_EXPORTER_OTLP_ENDPOINT`: The OTLP endpoint receiving telemetry.
+- `OTEL_EXPORTER_OTLP_HEADERS`: Headers including the API key (if required).
+- `APPLICATIONINSIGHTS_CONNECTION_STRING`: Application Insights connection string (when using Azure Monitor).
+
+For Azure Container Apps deployments, verify variables in the [Azure Portal](https://portal.azure.com) by navigating to your Container App → **Containers** → **Environment variables**.
+
+### Telemetry not exported from the app
+
+Verify that your app is configured to export telemetry. All service projects should call `AddServiceDefaults()` in their `Program.cs`, which sets up OpenTelemetry:
+
+```csharp title="C# — Program.cs"
+var builder = WebApplication.CreateBuilder(args);
+
+// This configures OpenTelemetry with logging, metrics, and tracing
+builder.AddServiceDefaults();
+```
+
+If you're not using Aspire service defaults, ensure your app is configured with the OpenTelemetry SDK and an appropriate exporter.
+
+### Telemetry sampled out
+
+The OpenTelemetry SDK may sample traces, meaning not every request produces a trace. By default, Aspire's service defaults configure 100% sampling for development. In production, check your sampling configuration.
+
+### Transport protocol mismatch
+
+The Aspire dashboard supports both gRPC OTLP (port 18889) and HTTP OTLP (port 18890). Most cloud-hosted OTLP endpoints require HTTP. Verify that the protocol in `OTEL_EXPORTER_OTLP_PROTOCOL` matches the endpoint:
+
+- Use `grpc` for the Aspire dashboard's gRPC OTLP endpoint.
+- Use `http/protobuf` for HTTP OTLP endpoints (required for browser apps and many cloud services).
+
+## Dashboard access after deployment
+
+When you deploy an Aspire app to Azure Container Apps using `aspire deploy`, the Aspire dashboard is included as a container app in your deployment. This gives you a familiar UI for viewing telemetry from your deployed app.
+
+
+
+### Find the dashboard URL
+
+After a successful `aspire deploy`, the dashboard URL is included in the deployment output. It typically appears as a Container App URL, for example:
+
+```plaintext data-disable-copy
+Dashboard URL: https://aspire-dashboard.wonderfulcoast-abc12345.eastus.azurecontainerapps.io
+```
+
+You can also find the URL in the [Azure Portal](https://portal.azure.com) by navigating to your resource group, locating the Container App named `aspire-dashboard` (or similar), and finding its **Application URL** on the Overview page.
+
+### Authenticate with the login token
+
+The deployed dashboard requires a login token, just like the standalone dashboard. The token is displayed in the dashboard container's logs.
+
+
+
+1. In the Azure Portal, navigate to your `aspire-dashboard` Container App.
+
+2. Select **Monitoring** → **Log stream** from the left navigation.
+
+3. Look for a log line containing `login?t=`, for example:
+
+ ```plaintext data-disable-copy
+ Login to the dashboard at https://aspire-dashboard.example.com/login?t=abc123...
+ ```
+
+4. Copy the token value (the part after `t=`) and use it to log in at the dashboard URL.
+
+
+
+### Configure a fixed login token
+
+By default, the dashboard generates a new token each time it starts. To set a fixed token, configure the `Dashboard:Frontend:BrowserToken` setting using an environment variable:
+
+```csharp title="C# — AppHost.cs"
+var dashboard = builder.AddAzureContainerAppEnvironment("aspire-env")
+ .WithDashboard();
+```
+
+Or set the environment variable directly on the dashboard container app after deployment using the Azure CLI:
+
+```azurecli title="Azure CLI — Set dashboard token"
+az containerapp update \
+ --name aspire-dashboard \
+ --resource-group my-resource-group \
+ --set-env-vars "DASHBOARD__FRONTEND__BROWSERTOKEN=my-secret-token"
+```
+
+
+
+### Use OpenID Connect authentication
+
+For team access to the deployed dashboard, configure OpenID Connect (OIDC) authentication instead of browser token auth. This allows multiple users to log in with their organizational identity provider.
+
+
+For more information on configuring OIDC, see [Aspire dashboard configuration: Frontend](/dashboard/configuration/#frontend).
+
+
+## See also
+
+- [Aspire dashboard configuration](/dashboard/configuration/)
+- [Aspire dashboard security considerations](/dashboard/security-considerations/)
+- [Enable browser telemetry](/dashboard/enable-browser-telemetry/)
+- [Deploy using the Aspire CLI](/deployment/azure/aca-deployment-aspire-cli/)
+- [Azure Monitor OpenTelemetry documentation](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable)
From a88f5f8cb23e9e208d0d368e1b689e977e979f18 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 23 Feb 2026 17:15:10 +0000
Subject: [PATCH 3/3] Fix doc-tester issues: remove fictional API, fix package
attribution, improve URL guidance
Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com>
---
.../dashboard/telemetry-after-deployment.mdx | 27 +++++++++----------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx b/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
index 3eecfdf64..7baf645e7 100644
--- a/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
+++ b/src/frontend/src/content/docs/dashboard/telemetry-after-deployment.mdx
@@ -47,7 +47,7 @@ builder.AddProject("webfrontend")
builder.Build().Run();
```
-When you reference Application Insights, Aspire automatically configures the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable for each service. The `Microsoft.Extensions.Azure` OTEL integration reads this variable and sends telemetry to Application Insights.
+When you reference Application Insights, Aspire automatically configures the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable for each service. The `Azure.Monitor.OpenTelemetry.AspNetCore` package (via `UseAzureMonitor()`) reads this variable and sends telemetry to Application Insights.