Whisperr 1.0.0

dotnet add package Whisperr --version 1.0.0
                    
NuGet\Install-Package Whisperr -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Whisperr" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Whisperr" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Whisperr" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Whisperr --version 1.0.0
                    
#r "nuget: Whisperr, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Whisperr@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Whisperr&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Whisperr&version=1.0.0
                    
Install as a Cake Tool

Whisperr .NET SDK

Server-side SDK for .NET - reliable churn-signal event tracking for ASP.NET Core, workers, serverless handlers, and any backend that knows the end-user id.

dotnet add package Whisperr

Quick Start

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 that your app uses everywhere else, and backend events land on the same Whisperr timeline as frontend events.

ASP.NET Core

Install the companion package for dependency-injection wiring:

dotnet add package Whisperr.AspNetCore

AddWhisperr binds the Whisperr configuration section and falls back to the WHISPERR_API_KEY environment variable, then registers WhisperrClient as a singleton. The host disposes the singleton on shutdown, which runs a final flush, so you do not need to manage the lifetime yourself.

using Whisperr.AspNetCore;

builder.Services.AddWhisperr(builder.Configuration, options =>
{
    options.OnError = error => Console.Error.WriteLine($"whisperr:{error.Code} {error.Message}");
});
// appsettings.json
{
  "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 and host-shutdown 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

For request 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();
});

Behavior

  • Track and Identify enqueue in memory and return immediately.
  • Events flush in batches to /v1/events/batch; identity updates flush to /v1/identify.
  • Requests use X-API-Key.
  • event_type must be lowercase snake_case; invalid events are dropped before they can poison a batch.
  • Each event gets a stable $message_id idempotency key in context; retries reuse the same id.
  • 401/403 retain the batch and surface auth.
  • 429, 5xx, timeouts, and network failures retry with bounded backoff; after retries are exhausted, the batch is retained and retry_exhausted is surfaced.
  • Other 4xx responses drop the offending batch and surface dropped.

The queue is in-process, not crash-durable. Call FlushAsync or ShutdownAsync before short-lived processes exit.

Runtime support

  • Targets: net8.0 and netstandard2.0 (the latter covers .NET Framework 4.7.2+ and other netstandard2.0 hosts). The conformance suite runs on both net8.0 and net472 in CI.
  • Long-lived hosts: hold one client for the process lifetime. In ASP.NET Core the DI singleton is disposed (and flushed) on shutdown.
  • Short-lived / serverless: the background timer cannot guarantee delivery before the runtime freezes — await client.ShutdownAsync() (or FlushAsync()) before returning so buffered events aren't lost.
  • Trimming / AOT: standard server apps (including trimmed deployments) are supported. The SDK uses reflection-based System.Text.Json, so Native AOT is not a v1 guarantee; prefer the JIT/ReadyToRun runtimes for now.

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. Use TimeSpan.Zero to disable.
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 Emits 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.

Development

The tests consume whisperr-spec fixtures. In this workspace the sibling ../whisperr-spec repo is picked up automatically. In CI or another checkout:

export WHISPERR_SPEC_PATH=/path/to/whisperr-spec/conformance/wire.json
dotnet test

Build and pack:

dotnet test -c Release
dotnet pack src/Whisperr/Whisperr.csproj -c Release -o artifacts

Publish to NuGet. Releases are cut by pushing a v*.*.* tag (the workflow derives the package version from the tag), but you can also push locally:

dotnet nuget push artifacts/Whisperr.*.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key "$NUGET_API_KEY" \
  --skip-duplicate

Whisperr - predict churn, automate interventions, recover revenue. whisperr.net

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Whisperr:

Package Downloads
Whisperr.AspNetCore

ASP.NET Core integration for the Whisperr .NET SDK: dependency-injection registration and request-scoped event tracking.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 133 7/3/2026