UsageWatch.Client
1.0.0
dotnet add package UsageWatch.Client --version 1.0.0
NuGet\Install-Package UsageWatch.Client -Version 1.0.0
<PackageReference Include="UsageWatch.Client" Version="1.0.0" />
<PackageVersion Include="UsageWatch.Client" Version="1.0.0" />
<PackageReference Include="UsageWatch.Client" />
paket add UsageWatch.Client --version 1.0.0
#r "nuget: UsageWatch.Client, 1.0.0"
#:package UsageWatch.Client@1.0.0
#addin nuget:?package=UsageWatch.Client&version=1.0.0
#tool nuget:?package=UsageWatch.Client&version=1.0.0
UsageWatch.Client
ASP.NET Core middleware and client SDK for reporting API usage to UsageWatch — an API analytics and observability platform. Drop it into your API to see who's calling it, which endpoints they use, latency percentiles (P50–P99), error rates, and whether clients are retrying or putting your API under pressure.
Delivery is fully non-blocking: every request is recorded to an in-memory queue and shipped to UsageWatch by a background service, so a slow or unreachable UsageWatch instance can never add latency to your API.
Install
dotnet add package UsageWatch.Client
Quick start
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddUsageWatch(options =>
{
options.ApiKey = builder.Configuration["UsageWatch:ApiKey"]!;
options.IngestBaseUrl = "https://your-usagewatch-deployment.example.com";
options.Environment = "production";
});
var app = builder.Build();
app.UseRouting();
app.UseUsageWatch(); // after UseRouting, before endpoints
app.MapControllers();
app.Run();
That's it — every request is now automatically tracked: route template
(normalized, so /orders/123 and /orders/456 aggregate as
/orders/{id}), method, status code, response time, and response size.
Manual tracking
Inject IUsageWatchClient anywhere you want to record a usage event outside
the normal HTTP pipeline — background jobs, gRPC calls, or an endpoint you
want tracked under a specific client identifier:
public class OrderJob(IUsageWatchClient usageWatch)
{
public async Task RunAsync()
{
var sw = Stopwatch.StartNew();
// ... do work ...
usageWatch.Track(
endpoint: "/jobs/process-orders",
method: "JOB",
statusCode: 200,
responseTimeMs: sw.ElapsedMilliseconds,
clientIdentifier: "acme-corp");
}
}
Identifying clients
UsageWatch breaks usage down per calling client, but there's no universal way to know who's calling your API — it depends entirely on how your app identifies callers. Nothing is guessed or auto-detected; configure one (or more, in priority order) of the following:
builder.Services.AddUsageWatch(options =>
{
options.ApiKey = "...";
options.IngestBaseUrl = "...";
// 1. Highest priority — full control over resolution.
options.ClientIdentifierResolver = ctx => ctx.Items["TenantId"]?.ToString();
// 2. Request header (default: "X-Client-Id").
options.ClientIdHeaderName = "X-Client-Id";
// 3. Query string parameter, e.g. ?client_id=acme-corp (off by default).
options.ClientIdQueryParamName = "client_id";
// 4. Claim on the authenticated user (off by default).
options.ClientIdClaimType = "client_id";
});
If none of the configured strategies resolve a value for a given request, the call is still tracked and counted toward quota — just not attributed to a specific client.
Configuration reference
All options are set via AddUsageWatch(options => { ... }).
| Option | Default | Description |
|---|---|---|
ApiKey |
(required) | API key from your UsageWatch project, sent as X-Api-Key on every ingestion call. |
IngestBaseUrl |
https://localhost:5001 |
Base URL of your UsageWatch instance. Events post to {IngestBaseUrl}/api/ingest/usage. |
ExcludedPathPrefixes |
/health, /swagger, /favicon.ico, /_framework |
Path prefixes that are never tracked. |
SamplingRate |
1.0 |
Fraction of requests to record (0.0–1.0). Useful for very high-traffic APIs. |
MaxQueueSize |
10,000 |
Max buffered events before new ones are dropped, to protect your app's memory if UsageWatch is unreachable. |
MaxRetryAttempts |
3 |
Retries per event, with exponential backoff (200ms, 400ms, 800ms, ...). |
RetryBaseDelay |
200ms |
Base delay for exponential backoff. |
RequestTimeout |
5s |
HTTP timeout per delivery attempt. |
ShutdownFlushTimeout |
5s |
How long to keep draining the queue on app shutdown before giving up. |
Environment |
production |
Deployment label attached to every event. |
Region |
null |
Optional deployment metadata, e.g. us-east-1. |
Service |
null |
Optional, e.g. orders-service, if one project covers multiple services. |
Version |
null |
Optional API version/build identifier, e.g. v2.4.1. |
RequestIdHeaderNames |
X-Request-ID, X-Correlation-ID |
Headers checked, in order, for an existing request id. |
GenerateRequestIdIfMissing |
false |
Generate a GUID request id when none of the above headers are present. |
IdempotencyHeaderName |
Idempotency-Key |
Header read for retry/duplicate detection. Set to null to disable. |
ClientIdentifierResolver |
null |
Custom function, highest priority for resolving the calling client. |
ClientIdHeaderName |
X-Client-Id |
Header checked next for the client identifier. |
ClientIdQueryParamName |
null |
Query parameter checked next (off by default). |
ClientIdClaimType |
null |
Claim type checked last, for authenticated requests (off by default). |
How delivery works
- Every tracked request is written to a bounded in-memory channel — never blocking the request thread.
- A background hosted service (
UsageWatchDispatcher) drains the channel and POSTs each event to{IngestBaseUrl}/api/ingest/usage. - If the queue is full, new events are dropped rather than slowing down your API.
- Failed deliveries retry with exponential backoff up to
MaxRetryAttempts. A429response (project quota exceeded) is treated as delivered — no retry. - On graceful shutdown, the dispatcher keeps draining the queue for up to
ShutdownFlushTimeoutso in-flight events aren't lost on deploy/restart.
Requirements
- .NET 8
- An ASP.NET Core application (the package references
Microsoft.AspNetCore.App) - A UsageWatch instance and project API key — see usagewatch.onrender.com
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 108 | 9/4/2026 |