.NET
The Whisperr server-side SDK for .NET — for ASP.NET Core, workers, serverless handlers, and any backend that knows the end-user id.
dotnet add package WhisperrQuickstart
Section titled “Quickstart”using Whisperr;
var whisperr = new WhisperrClient(Environment.GetEnvironmentVariable("WHISPERR_API_KEY")!);
whisperr.Track( "user_8842", "payment_failed", new Dictionary<string, object?> { ["amount_cents"] = 4900, ["reason"] = "card_declined" });
whisperr.Identify("user_8842", new IdentifyOptions{ Email = "ada@example.com", Traits = new Dictionary<string, object?> { ["plan"] = "pro" }});
await whisperr.ShutdownAsync();The user id is always explicit. Pass the same external_user_id your app
uses everywhere else and backend events land on the
same timeline as frontend events.
ASP.NET Core
Section titled “ASP.NET Core”Install the companion package for dependency-injection wiring:
dotnet add package Whisperr.AspNetCoreAddWhisperr binds the Whisperr configuration section (falling back to the
WHISPERR_API_KEY environment variable) and registers WhisperrClient as a
singleton. The host disposes the singleton on shutdown, which runs a final
flush — you don’t manage the lifetime yourself.
using Whisperr.AspNetCore;
builder.Services.AddWhisperr(builder.Configuration, options =>{ options.OnError = error => Console.Error.WriteLine($"whisperr:{error.Code} {error.Message}");});{ "Whisperr": { "ApiKey": "wrk_...", "FlushInterval": "00:00:10" }}Inject WhisperrClient wherever you have the user id. Track/Identify
enqueue and return immediately — let the background flush deliver them
rather than awaiting FlushAsync on the request path (a flush can wait
through retry backoff):
app.MapPost("/billing/webhook", ( BillingWebhook webhook, WhisperrClient whisperr) =>{ whisperr.Track(webhook.UserId, "payment_failed", new Dictionary<string, object?> { ["amount_cents"] = webhook.AmountCents, ["provider"] = "stripe" });
return Results.Ok();});Request-scoped tracking
Section titled “Request-scoped tracking”For handlers that already authenticate a user, add the middleware after
authentication and use HttpContext.Whisperr(), which binds to the user id
from the NameIdentifier/sub claim (override via UseWhisperr(resolveUser)):
using Whisperr.AspNetCore;
app.UseAuthentication();app.UseWhisperr();
app.MapPost("/plan/upgrade", (HttpContext http) =>{ http.Whisperr().Track("plan_upgraded", new Dictionary<string, object?> { ["plan"] = "pro" }); return Results.Ok();});Reliability
Section titled “Reliability”Implements the full delivery contract: batching to
/v1/events/batch, snake_case validation before enqueue, a stable
$message_id per event across retries, retain-on-auth, bounded backoff on
transient failures, drop on malformed 4xx.
The queue is in-process, not crash-durable. Call FlushAsync or
ShutdownAsync before short-lived processes exit.
Runtime support
Section titled “Runtime support”- Targets:
net8.0andnetstandard2.0(covers .NET Framework 4.7.2+). The conformance suite runs on bothnet8.0andnet472in CI. - Long-lived hosts: hold one client for the process lifetime; in ASP.NET Core the DI singleton is flushed and disposed on shutdown.
- Short-lived / serverless:
await client.ShutdownAsync()(orFlushAsync()) before returning so buffered events aren’t lost. - Trimming / AOT: trimmed deployments are supported. The SDK uses
reflection-based
System.Text.Json, so Native AOT is not a v1 guarantee; prefer JIT/ReadyToRun runtimes for now.
Options
Section titled “Options”| Option | Default | Notes |
|---|---|---|
ApiKey |
— | App ingestion key (wrk_...). Required unless disabled. |
BaseUrl |
https://api.whisperr.net |
Whisperr ingestion API. |
FlushAt |
20 |
Flush when this many operations are queued. |
FlushInterval |
10s |
Background flush cadence. TimeSpan.Zero disables. |
MaxQueueSize |
10000 |
Oldest operations drop on overflow. |
MaxBatchSize |
500 |
Events per batch; backend cap is 500. |
MaxRetries |
6 |
Transient retries before retaining for a later flush. |
RequestTimeout |
10s |
Per-request timeout. |
Disabled |
false |
No-op client for tests and local modes. |
Debug |
false |
Diagnostic warnings to Logger or stderr. |
OnError |
— | Observability hook for auth, dropped, retry_exhausted. |
HttpClient |
private client | Pass your own for custom handlers or test capture. |