Selkies 2.1 · screen cleanup perfected, the stream follows the link, sessions survive a dropped connection, 10-bit video

A Linux desktop in the browser that feels like a local monitor.

Selkies streams X11 desktops, Wayland desktops, and single applications to any web browser at 60+ frames per second. H.264, H.265, VP8, VP9, or AV1 over WebSockets or WebRTC, encoded on the GPU, damage-aware, and free forever. Not a screen-scraper. Not just a video stream. The best of both, built for the modern web.

  • Chromium
  • Firefox
  • Safari
  • X11
  • Wayland
  • NVIDIA
  • Intel
  • AMD
https://desktop.example.internal
  • 0+FPS at 1080p, even on a software encoder
  • 0TCP port, through any reverse proxy
  • 0client installs, plugins, or agents
  • 0codecs, H.264, H.265, VP8, VP9, and AV1
  • MPL‑2.0open source, free forever
How it works

Not a video stream. Not VNC. Both, and better.

VNC chops the screen into tiny rectangles, JPEG-encodes each one on the CPU, and can never go back to clean up what it drew. Off-the-shelf game streaming is a pixel cannon: every frame encoded whether anything moved or not, and 50 to 100 Mbps before it looks good. Selkies drives a real video codec tuned for desktop work, with full motion there on demand when the screen calls for it. Only the region that moved is spent on, nothing is sent when nothing moves, and the moment motion stops, the codec's own rate control is turned to cleaning the screen up. A presentable desktop fits under 10 Mbps, and under one if you can wait a moment for it to sharpen, without giving up frame rate.

Only the motion pays

Rotate a model in a viewport and the codec spends its bits on the viewport. The toolbars, panels, and text around it are never hit with a low-quality keyframe, so everything that held still stays legible while the motion runs. That is a video codec steered by motion, not a screen cut into rectangles.

No motion, no frames

A still screen costs nothing. Capture is damage-gated on both X11 and Wayland, a blinking cursor costs its own few pixels and nothing more, and audio silence is dropped before it is ever encoded.

Paint-over: the cleanup

The moment motion stops, the stream is refined to paint-over quality: crisp text at CRF 18, 4:4:4 chroma, 10-bit where you ask for it. Capped at 1 Mbps, the same happens: the stream fills its ceiling with cleanup frames until the screen is clean, then stops. A blinking cursor does not undo it.

A still screen costs nothing. Play the animation and only the viewport is encoded. Pause it and the stream drops back to zero.
ApproachFull motionStill screenText clarityBandwidthSystem load
Classic VNC / TightSlideshowCheapGood, never refinedSpikes on motionCPU: rectangles and JPEG
Off-the-shelf video streamSmoothEncodes anywaySmeared, keyframe blocks50 to 100 Mbps to look goodGPU, never idle
Selkies60+ FPSZero framesPaint-over, 4:4:4, 10-bitUnder 10 Mbps, under 1 if you waitGPU, CPU barely touched

Add 4:4:4 chroma and 10-bit color on top and the case for JPEG rectangles is gone: the same codec carries crisp text, true color, and full-motion video, on one connection. With a GPU encoding, the CPU is essentially idle on both ends, since the browser hardware-decodes the stream. Without one, a 1080p 60 FPS software stream runs at roughly 60% of a single core, and ordinary desktop work sits around 10 to 20%.

The total package

Everything a desktop does. From any browser.

Selkies is not a viewer with a few extras bolted on. Every capability below ships in the core, works on both transports, and needs nothing installed on the client.

Webcam forwarding

Your browser's camera becomes a real V4L2 device inside the session. Video calls, OBS, OpenCV, all of it, decoded off the GIL with zero copies in Python.

Microphone uplink

Opus-encoded audio from your mic shows up as an ordinary PulseAudio source. Applications record it like any capture device.

Any language, any layout

Full IME composition streaming, non-Latin layouts, and modifier healing across browsers. Type Japanese, Korean, Arabic, or Dvorak and it just works.

Dual monitors

One click adds a second screen as a companion browser window. Drag it to your other physical monitor and you have a real extended desktop.

Gamepads, real and touch

Browser gamepads are injected as kernel-style joysticks that Steam and Proton see. On phones and tablets, a customizable on-screen touch gamepad fills in.

Two-way clipboard, text and images

Copy and paste in both directions, including binary image clipboards. Large payloads are chunked automatically across Chromium, Firefox, and Safari.

File uploads and downloads

Drag files into the session or browse and pull them out. Transfers are paced against the video stream end to end, so a big upload never stalls your desktop.

Session sharing

Hand out viewer links, or player 2 through 4 links that drive their own gamepad slot. Roles are enforced on the server, not trusted from the page.

Gaming mode

Fullscreen with the pointer and keyboard held, raw mouse motion with no acceleration curve, and Escape, Alt+Tab, and every chord delivered to the game.

Surround audio

Full-band Opus with silence gating and optional redundancy. Mono, stereo, 5.1, and 7.1 layouts that Chromium decodes natively.

Secure by design

HTTPS out of the box, HTTP Basic auth or any reverse proxy in front, and a token-based Secure Mode that provisions per-session roles. Every exposed interface has been through a security review, and the parsers for what a peer sends are fuzzed.

Built for AI agents

A Computer Use API dumps screenshots and drives keyboard and mouse, so agents can operate a full desktop through the same pipeline you watch.

Printing

The session has a printer. Anything printed to it lands in your browser's print dialog, or as a PDF in the side menu, with no privilege and nothing under /etc.

Audit trail

Every clipboard transfer, file upload, download, print, connect, and recording posted as JSON to a webhook you name. Metadata only, never content.

Operator API

Start and stop MP4 recordings, take a PNG screenshot, list and close connected pages, over HTTP with the master token. Automate the session from outside.

Several pages, one session

Open the same session in a second tab or another browser and it joins beside the first, both streaming and both driving input, instead of taking over.

  • Pointer lock
  • Fullscreen
  • Trackpad mode for touch
  • Gamepad rumble
  • Virtual keyboard
  • HiDPI pixel-perfect
  • Dynamic resize and presets
  • Turbo mode
  • Live encoder, bitrate, CRF, and FPS
  • Live CPU, GPU, and bitrate gauges
  • Watermarking
  • MP4 recording
  • In-session app manager
  • Per-setting UI locking
  • Subfolder reverse proxies
  • Embeddable in any page
  • Two dashboards to fork
  • 10-bit color
  • pip install selkies
  • aarch64 and Jetson wheels
  • Webcam and mic on demand
  • Translated UI
  • Kubernetes-ready
  • No root required
  • No systemd required
Under the hood

From pixels to your browser in one hop.

A single Python application orchestrates two small Rust extensions. The performance-critical path never touches the interpreter, on a GPU, X11 or Wayland, never touches system RAM at all, and none of it links FFmpeg.

Selkies streaming pipeline Display X11 DRI3 dmabuf Wayland dmabuf pixelflux damage tracking NVENC · VA-API · Tegra H.264 · H.265 · VP8 · VP9 · AV1 Transport WebRTC · WebSockets swappable mid-session Browser WebCodecs decode zero-copy canvas Audio PulseAudio PipeWire-Pulse pcmflux Opus · silence gate up to 7.1 surround Same socket one connection one port Speakers Web Audio Mic returns uplink clipboard · input · mic · webcam · files return on the same connection Selkies (Python, aiohttp) orchestrates, never copies a pixel Rust (PyO3) extensions carry the hot path
Zero copy on X11

On NVIDIA, NvFBC composites the screen straight into video memory and NVENC encodes that buffer in place: 2.5 ms a frame on a V100 where a readback took 5.2. Elsewhere the X server draws on the GPU and each frame is one DRI3 blit into a dmabuf the encoder owns.

Zero copy on Wayland

Frames flow as dmabufs from the compositor's GBM buffers straight into the hardware encoder. The CPU never sees a pixel, and encoded bytes reach Python through the buffer protocol, uncopied.

Hardware first, always a fallback

NVENC on NVIDIA, VA-API on Intel and AMD, Tegra on a Jetson, then x264, x265, libvpx, or SVT-AV1 in software, with JPEG kept around for browsers too old for WebCodecs. Something always works.

Hardware decode in the browser

WebCodecs on WebSockets, the native RTC decoder on WebRTC. Either way the browser hardware-decodes the codec it negotiated, your laptop stays cool, and there is no plugin to install.

Codecs

Five codecs, one ladder, and the browser's own menu.

Every session offers the codecs this host encodes and this browser decodes. A codec the browser cannot play stays in the menu, greyed out and named as the browser's limit, so a missing H.265 or AV1 never reads as a server option left out. When a codec cannot be served, the session steps down one ladder on both transports: hardware codecs most efficient first, then software by encode time, then striped H.264, and JPEG last.

Full color 4:4:4 on H.264, H.265, and VP9, and 10-bit on H.265, VP9, and AV1, are offered only where both the encoder and the decoder carry them, and the stream says which it got.

  • H.264 NVENC · VA-API · Tegra · x264
  • H.265 NVENC · VA-API · Tegra · x265
  • VP8 VA-API · libvpx
  • VP9 VA-API · libvpx
  • AV1 NVENC · VA-API · Tegra · SVT-AV1
  • JPEG striped, no WebCodecs needed
The encoder menu in Video Settings: H.264, H.265, VP8, VP9, AV1, and JPEG
GPU support

Mount the card in. We figure out the rest.

Pass a DRM render node or the NVIDIA runtime into the container and Selkies detects the GPU, picks the encoder, and brings up hardware OpenGL through DRI3 on the vendor's own driver. Multi-GPU hosts, mixed vendors, and containers with no GPU at all are all handled without a config file.

  • NVIDIA NVENC with High 4:4:4, ARGB-direct encode, and multi-GPU containers, CUDA 11 through 13.
  • Intel and AMD VA-API with VA-VPP conversion and per-device 4:4:4 negotiation.
  • Jetson the Tegra encoder through the vendor V4L2 interface, with aarch64 wheels on every release.
  • No GPU x264 or OpenH264 with multi-threaded striping still hits 60 FPS at 1080p on modest CPUs.
  • X11 an XLibre Xvfb whose screen pixmap lives on the GPU, so capture is a DRI3 blit into the encoder and never a readback.
  • Wayland a headless Smithay compositor owned by Selkies, or capture of a running wlroots, KDE, or COSMIC session.
docker run -d --name selkies --shm-size=2g -p 8080:8080 \
  --gpus 1 --runtime nvidia \
  ghcr.io/selkies-project/selkies/desktop:latest-ubuntu26.04
The Stats panel: encoder VA-API H.264, capture Wayland zero-copy, decoder hardware, connection WebSockets, with frame rate, bandwidth, and latency graphs and the per-stage timings below
Transport

WebSockets by default. WebRTC when you want it.

Out of the box Selkies streams over plain WebSockets: one TCP port, straight through nginx, Traefik, Caddy, a load balancer, or a Kubernetes ingress, with no STUN, TURN, UDP, or VPN in the picture. It is why a session works anywhere a web page loads, and why noVNC deployments switch without touching anything in front. On either transport the stream starts in CBR with congestion control on and backs its bitrate off to what the link carries, and a proxy that drops long-lived sockets no longer ends the session.

Selkies was born on WebRTC, and it is one flag away: the lowest latency the web can offer, its own congestion control, and every VNC-style trick Selkies does, damage gating, paint-over, on-demand keyframes, carried across the RTC standard. Same encoders, same damage logic, same client. Enable dual mode and users hot-swap between the two from the side menu without dropping the session.

WebSockets default, one port WebRTC opt-in, lowest latency Dual mode swap live
Who it's for

Productivity, enterprise, research, and full-motion gaming.

One stack, tuned so that any performance problem a cloud gaming platform would care about is treated as a bug. That bar makes everything else effortless.

01

Web-native VDI

Replace virtual machines with containers. No special devices, no root, no systemd. Hundreds of desktops per host, each behind one URL.

02

Remote browser isolation

Open links, files, and downloads in a throwaway container instead of on the endpoint. The pixels come back; the malware does not.

03

Research and HPC

GUI tools on SLURM clusters through Apptainer, and selkies session is how Jupyter, Coder, and Open OnDemand start it. Born at Google, matured at UC San Diego's National Research Platform.

04

Cloud gaming

Steam, Proton, and Wine at 60+ FPS with gamepad passthrough, pointer lock, and couch co-op links for players two through four.

05

Creative and 3D work

Blender, FreeCAD, DaVinci-class workloads with real GPU acceleration and 4:4:4 color, streamed like a local monitor.

06

AI agents and automation

A Computer Use API and text control plane let agents see and drive a full desktop while you watch the same stream.

See it move

Full-motion gaming, in a browser tab.

Low latency, 60 frames per second, gamepads, pointer lock, and a dashboard that stays out of the way. Games run on the server and play in a browser tab, with no native client and no proprietary codec license.

And when the scene stops moving, the encoder stops too. That is the part a video stream cannot do and the part a VNC never could.

Read the design rationale →
Ecosystem

One core. A whole platform built on it.

Selkies is the engine. Around it, a family of projects across multiple organizations turns that engine into containers, app stores, isolation platforms, and mobile apps.

core

Selkies

The streaming platform itself: the Python runtime, the WebCodecs web client, the dashboards, the interposers, and the container images.

selkies-project/selkies
▦rust

pixelflux

The pixel pipeline. Zero-copy X11 and Wayland capture, damage tracking, H.264, H.265, VP8, VP9, AV1, and JPEG on NVENC, VA-API, Tegra, or in software, a virtual camera, a recorder, and a Computer Use API.

selkies-project/pixelflux
♫rust

pcmflux

The audio pipeline. PulseAudio capture to Opus with silence detection, RED redundancy, surround layouts, and microphone playback for the uplink.

selkies-project/pcmflux
platform

Sealskin

Your browser is your new computer. Self-hosted browser isolation and app streaming with browser extensions, iOS and Android apps, and collaboration rooms.

sealskin.app
☰linuxserver.io

Selkies base images

The LinuxServer.io base for every web-native desktop container: GPU auto-detection, hardening presets, watermarks, subfolder proxies, DinD, and more.

linuxserver/docker-baseimage-selkies
⛶linuxserver.io

Webtop and 100+ apps

Full desktops in KDE, XFCE, MATE, i3, and more, plus a library of single-application containers. Hundreds of millions of pulls across the family.

linuxserver/docker-webtop
☷catalog

Sealskin app store

The manifest of every launchable application, its file associations, GPU flags, and autostart scripts, in X11 and Wayland flavors.

linuxserver/sealskin-apps
portable apps

PRoot Apps and proot-next

A growing catalog of desktop applications, each bundled with its toolchain, installed into the home directory with no privileges and carried between containers. Built on proot-next, PRoot rewritten from the ground up in Rust.

linuxserver/proot-apps
✎docs

Documentation

Getting started, native installs and AppImages, every setting with its flag and default, firewall guidance, secure mode, and the developer reference.

docs.selkies.io

Every one of these runs on Selkies today.

Lineage

Not an overnight project. Years of streaming, several organizations.

  1. Born inside Google

    Started by Google engineers as a reference for GPU-accelerated streaming over WebRTC on Kubernetes.

  2. Open-sourced and adopted by research

    Developed by academic researchers for HPC and scientific workloads.

  3. LinuxServer.io goes all in

    The LinuxServer.io community replaced its VNC base images with Selkies across every desktop container, bringing a massive user base and a second engineering organization.

  4. Rebuilt for 2.0

    Rust capture and encode pipelines, native Wayland through Smithay, WebSockets by default, WebCodecs decode, and a web client rewritten around them.

  5. 2.1, today

    Congestion-controlled CBR by default on both transports, sessions that ride over a cut connection, several pages on one display, 10-bit video, gamepad rumble, and a security review and fuzzing of every exposed interface. Nothing in the capture stack links FFmpeg any more.

Get started

Running in under a minute.

Pick a flavor. Every one lands you in a desktop at a URL with nothing installed on the client.

The reference LXQt desktop with Firefox and Chrome, an embedded TURN server, and a snakeoil HTTPS certificate. Add --device /dev/dri for an Intel or AMD GPU.

docker run --name selkies -it -d --rm --shm-size=2g -p 8080:8080 \
    ghcr.io/selkies-project/selkies/desktop:latest-ubuntu26.04

Then open https://localhost:8080 and log in as ubuntu with mypasswd, or set -e PASSWD=. Add -e SELKIES_MODE=webrtc for the WebRTC transport, or -e SELKIES_ENABLE_DUAL_MODE=true to offer both. Full walkthrough in Getting Started.

Open source. Always free. Built by people who use it every day.

Selkies is licensed under the Mozilla Public License 2.0 and maintained by contributors across the Selkies project, LinuxServer.io, academia, and the wider community. We can never have too much help.