OpenTelemetry traces and metrics in the Supabase .NET SDK

Oct 14, 2026

What's new#

The .NET SDK emit traces and metrics through System.Diagnostics. Each client exposes its own ActivitySource and Meter, so you subscribe to them the same way you subscribe to any other .NET instrumentation. The SDK takes no dependency on the OpenTelemetry packages, and the clients stay silent until something subscribes, so there is no overhead when you are not collecting.

This covers the Auth, Postgrest, Storage, and Functions clients. Realtime is not yet instrumented. URLs are recorded with the query string stripped, and no token, credential, or payload is placed in a tag.

What you get#

ClientSpansMetrics
PostgrestOne per request ({METHOD} {path}), with a db.operation tag (select, insert, update, upsert, delete, count, rpc) to tell apart operations that share an HTTP verbsupabase.postgrest.http.request.duration
AuthOne per operation (gotrue.sign_in, gotrue.refresh_token, …), with a child span for the HTTP callsupabase.gotrue.http.request.duration
StorageOne per request, with a storage.transfer.direction tag on uploads and downloads; a resumable (TUS) upload is a single span for the whole transfersupabase.storage.http.request.duration, supabase.storage.transfer.duration, supabase.storage.transfer.size
FunctionsOne per invocation, with a faas.invoked_name tag; a relay error is a failed span even when the HTTP status succeedssupabase.functions.invoke.duration

How to use it#

Add the OpenTelemetry hosting package and an exporter alongside the SDK:


_10
<PackageReference Include="Supabase" Version="8.0.0" />
_10
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.19.1" />
_10
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.19.1" />

Then register the Supabase sources. Each client shares one name between its ActivitySource and its Meter, so you can register them all at once with SupabaseDiagnostics.SourceNames, or one client at a time by its own SourceName:


_20
using OpenTelemetry.Metrics;
_20
using OpenTelemetry.Trace;
_20
using Supabase;
_20
using Supabase.Postgrest;
_20
using Supabase.Gotrue;
_20
using Supabase.Storage;
_20
using Supabase.Functions;
_20
_20
builder.Services.AddOpenTelemetry()
_20
// All sources at once.
_20
.WithTracing(tracing => tracing
_20
.AddSource(SupabaseDiagnostics.SourceNames.ToArray())
_20
.AddOtlpExporter())
_20
// Or one client at a time.
_20
.WithMetrics(metrics => metrics
_20
.AddMeter(PostgrestDiagnostics.SourceName)
_20
.AddMeter(GotrueDiagnostics.SourceName)
_20
.AddMeter(StorageDiagnostics.SourceName)
_20
.AddMeter(FunctionsDiagnostics.SourceName)
_20
.AddOtlpExporter());

Swap AddOtlpExporter for AddConsoleExporter to print locally, or use any other exporter. Without the OpenTelemetry SDK, a raw ActivityListener or MeterListener works too. We have one README per-package which shows how to do it.

Why it matters#

You get the SDK's calls in the same traces as the rest of your app: which ran, how long they took, whether they failed. You write no instrumentation for it, and the SDK pulls in no OpenTelemetry dependency of its own.

Build in a weekend, scale to millions