Livekit.Server.Sdk.Dotnet
| Livekit.Rtc.Dotnet
Use this SDK to add realtime video, audio and data features to your .NET app. By connecting to LiveKit Cloud or a self-hosted server, you can quickly build applications such as multi-modal AI, live streaming, or video calls with just a few lines of code.
API reference of both packages: https://pablofuente.github.io/livekit-server-sdk-dotnet/
This repository contains two complementary .NET packages for different LiveKit use cases:
Server-side management and authentication SDK for LiveKit. Use it to interact with all LiveKit server APIs, create access tokens, and handle webhooks.
-
Target framework:
netstandard2.0
Real-time communication SDK for .NET server applications. Use it to connect to LiveKit as a server-side participant, and to publish and subscribe to audio, video, and data.
-
Target framework:
netstandard2.1 -
Included native binaries: precompiled for Windows, Linux, macOS (x64 & ARM64)
dotnet add package Livekit.Server.Sdk.Dotnetusing Livekit.Server.Sdk.Dotnet;
// Generate access token
var token = new AccessToken("api-key", "api-secret")
.WithIdentity("user-123")
.WithName("John Doe")
.WithGrants(new VideoGrants { RoomJoin = true, Room = "my-room" });
var jwt = token.ToJwt();
// Manage rooms via API
var roomClient = new RoomServiceClient("https://my.livekit.instance", "api-key", "api-secret");
var rooms = await roomClient.ListRooms(new ListRoomsRequest());dotnet add package Livekit.Rtc.Dotnetusing LiveKit.Rtc;
// Connect to room as a participant
var room = new Room();
// Add room event handlers
room.ParticipantConnected += (sender, participant) =>
{
Console.WriteLine($"[ParticipantConnected] {participant.Identity}}");
};
await room.ConnectAsync("wss://my.livekit.instance", token);
// Publish audio track
var audioSource = new AudioSource(48000, 1);
var audioTrack = LocalAudioTrack.Create("audio", audioSource);
await room.LocalParticipant!.PublishTrackAsync(audioTrack);
// Handle events
room.TrackSubscribed += (sender, e) => {
Console.WriteLine($"Subscribed to track: {e.Track.Sid}");
};git clone --recurse-submodules https://github.com/pabloFuente/livekit-server-sdk-dotnet.git
cd livekit-server-sdk-dotnetNote: The
--recurse-submodulesflag is required to clone the necessary LiveKit protocol submodules.
# Build both packages
dotnet build
# Run tests for Server SDK
dotnet test LivekitApi.Tests/LivekitApi.Tests.csproj
# Run tests for RTC SDK
dotnet test LivekitRtc.Tests/LivekitRtc.Tests.csproj
# Build and install both packages locally
./build_local.sh
# Build the API reference into docs/_site and check it (same as CI)
dotnet tool restore && dotnet docfx docs/docfx.json --warningsAsErrors && python3 docs/check_api_docs.pyEvery public member of the two libraries needs a complete XML doc comment (summary, every
parameter, the return value): those comments are the published
API reference, so the build fails
without them. A new public type of Livekit.Server.Sdk.Dotnet also needs an entry in the sidebar of
the reference, docs/api-server/toc.yml; the check script fails until it
has one.
# Every test with coverage (needs Docker, like CI), then the report and the coverage gate
./coverage.sh
# A subset: the report is built, but the gate (set for the full suite) fails
./coverage.sh LivekitApi.Tests --filter "Category=Unit"Each test project measures only its own SDK with coverlet.collector, using the settings in
coverage/, which leave out the generated protobuf, Twirp and FFI code. coverage.sh
merges the results with ReportGenerator into coverage/report/: index.html (line and branch
coverage per SDK, class and source line), Cobertura.xml and a Markdown summary. The build job of
dotnet.yml runs it, adds the summary to the job summary page and
uploads coverage/report as the coverage-report artifact.
The gate fails when coverage falls below the minimums in
coverage/thresholds.json: line and branch minimums for each SDK, and
stricter ones for critical components such as token signing and verification, webhooks, the FFI
bridge or room connection. Each component lists its classes or methods and the test files that
cover them, and the check fails when one of them no longer exists. The minimums sit just below the
measured coverage, so they catch regressions: raise them when coverage grows (the check lists the
ones 10 points or more above their minimum) and never lower one without explaining why in the pull
request. New code comes with tests that assert its behavior. If the code is on a critical path, add
it to that component's code, and add any new test file that covers it to its tests.
python3 security/check_vulnerabilities.py (add --sources all for the native crates, which needs
the rust-sdks submodule and cargo) runs the vulnerability scan that CI runs. A critical or high
finding fails it until it is fixed or accepted in security/policy.json; see
SECURITY.md for what is scanned, the exception rules and how to report a
vulnerability.
Releases are automated through GitHub Actions thanks to the publish workflow. Both packages Livekit.Server.Sdk.Dotnet and Livekit.Rtc.Dotnet can be released independently. The workflow publishes with NuGet Trusted Publishing: nuget.org keeps a policy for this repository and publish.yml, scoped to the two package IDs, and the NUGET_USER repository secret holds the nuget.org user name; no API key is stored. After publishing, the workflow opens a pull request that moves the package validation baseline of the released package to the new version: approve its checks ("Approve workflows to run") and merge it before the next release of the same package. Checkout how to do so:
Tip
The /sync-protocol skill runs this whole procedure, including wrapping the new RPCs, and the sync-protocol workflow runs it on every new GA release and opens a pull request. See AI coding agents in the package README.
To upgrade the version of the livekit/protocol Git submodule:
cd protocol
git fetch --all
git checkout <COMMIT_HASH/TAG/BRANCH>
cd ..
git add protocol
git commit -m "Update livekit/protocol to <VERSION>"
git pushThen it may be necessary to re-generate the proto files to actually reflect the changes in livekit/protocol:
./generate_proto.shThen try packaging the SDK to test the validity of the changes in the protocol:
dotnet pack -c Debug -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkgThis command may throw an error if there are breaking changes in the protocol, as the SDK is configured in strict mode for package validation. The build check of every pull request runs the same command, so it fails the same way. The way to overcome these breaking changes is running the package command with option -p:GenerateCompatibilitySuppressionFile=true to generate file CompatibilitySuppressions.xml:
dotnet pack -c Debug -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -p:GenerateCompatibilitySuppressionFile=trueThis compatibility suppression file will allow packaging and publishing the SDK even with breaking changes. Once the new version is available in NuGet, the only thing left is to update in file LivekitApi.csproj property <PackageValidationBaselineVersion>X.Y.Z</PackageValidationBaselineVersion> to the new version (so the new reference for breaking changes is this new version), and delete CompatibilitySuppressions.xml (as it is no longer needed). Workflow publish.yml automatically opens a pull request that does this as last step.
The repository ships guidance and tooling for AI coding agents, so the procedures above can be delegated to them:
- CLAUDE.md (also reachable as
AGENTS.md) is the briefing an agent loads first: which files are generated and must never be edited by hand, how the submodules and the native binaries are coupled, the target framework constraints of each package, the build, format and test commands, and the changelog conventions. - .claude/settings.json pre-approves the routine commands (
dotnet build,testandpack, CSharpier,./generate_proto.sh, read-only git commands on the submodules), asks beforegit commit,git push,git taganddownload_ffi.sh, and deniesdotnet nuget pushandgh release. Two hooks block edits to generated code, native binaries and submodules, and run CSharpier on every edited.csor.csprojfile. - Two Claude Code skills automate the upgrade procedures end to end:
/sync-protocol [version]forlivekit/protocol(step by step in LivekitApi/README.md) and/sync-rust-sdks [version]forrust-sdks(step by step in LivekitRtc/README.md). Both regenerate, fix the build, surface the new upstream APIs, run the tests and write the changelog entry, then stop at a checkpoint for your decisions and leave the result uncommitted for review. Releases stay manual. - The sync-protocol and sync-rust-sdks workflows run those skills with Claude Code whenever
livekit/protocolorlivekit-ffipublishes a new GA release, and open a pull request whose checks run the full test suite and build the API reference.
Built with ❤️ by pabloFuente
| LiveKit Ecosystem | |
|---|---|
| Agents SDKs | Python · Node.js |
| LiveKit SDKs | Browser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++ · .NET (community) |
| Starter Apps | Python Agent · TypeScript Agent · React App · SwiftUI App · Android App · Flutter App · React Native App · Web Embed |
| UI Components | React · Android Compose · SwiftUI · Flutter |
| Server APIs | Node.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community) · .NET (community) |
| Resources | Docs · Docs MCP Server · CLI · LiveKit Cloud |
| LiveKit Server OSS | LiveKit server · Egress · Ingress · SIP |
| Community | Developer Community · Slack · X · YouTube |