{"id":13621259,"url":"https://github.com/livekit/egress","last_synced_at":"2026-05-28T19:00:55.651Z","repository":{"id":37103604,"uuid":"458046250","full_name":"livekit/egress","owner":"livekit","description":"Export and record WebRTC sessions and tracks","archived":false,"fork":false,"pushed_at":"2026-05-20T22:39:29.000Z","size":5699,"stargazers_count":333,"open_issues_count":50,"forks_count":155,"subscribers_count":17,"default_branch":"main","last_synced_at":"2026-05-20T23:51:47.787Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://blog.livekit.io/livekit-universal-egress-launch/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/livekit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-02-11T04:32:38.000Z","updated_at":"2026-05-20T22:39:31.000Z","dependencies_parsed_at":"2024-02-18T02:24:02.099Z","dependency_job_id":"ad2e3e2e-f0d6-4ced-8748-810ae80120aa","html_url":"https://github.com/livekit/egress","commit_stats":{"total_commits":661,"total_committers":22,"mean_commits":"30.045454545454547","dds":0.2708018154311649,"last_synced_commit":"dd1694d79e4943cb957a3059427996e260e9155f"},"previous_names":["livekit/livekit-egress"],"tags_count":90,"template":false,"template_full_name":null,"purl":"pkg:github/livekit/egress","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/livekit%2Fegress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/livekit%2Fegress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/livekit%2Fegress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/livekit%2Fegress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/livekit","download_url":"https://codeload.github.com/livekit/egress/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/livekit%2Fegress/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33622070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T21:01:04.072Z","updated_at":"2026-05-28T19:00:55.632Z","avatar_url":"https://github.com/livekit.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003c!--BEGIN_BANNER_IMAGE--\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"/.github/banner_dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"/.github/banner_light.png\"\u003e\n  \u003cimg style=\"width:100%;\" alt=\"The LiveKit icon, the name of the repository and some sample code in the background.\" src=\"https://raw.githubusercontent.com/livekit/egress/main/.github/banner_light.png\"\u003e\n\u003c/picture\u003e\n\n\u003c!--END_BANNER_IMAGE--\u003e\n\n# LiveKit Egress\n\n\u003c!--BEGIN_DESCRIPTION--\u003e\nWebRTC is fantastic for last-mile media delivery, but interoperability with other services can be challenging.\nAn application may want to do things like store a session for future playback, relay a stream to a CDN, or process a track through a transcription service – workflows where media travels through a different system or protocol.\nLiveKit Egress is the solution to these interoperability challenges. It provides a consistent set of APIs that gives you\nuniversal export of your LiveKit sessions and tracks.\n\u003c!--END_DESCRIPTION--\u003e\n\n## Capabilities\n\n1. **Room composite** for exporting an entire room.\n2. **Web egress** for recordings that aren't attached to a single LiveKit room.\n3. **Track composite** for exporting synchronized tracks of a single participant.\n4. **Track egress** for exporting individual tracks.\n\nDepending on your request type, the egress service will either launch Chrome using a web template\n(room composite requests) or a supplied url (web requests), or it will use the Go SDK directly (track and track composite requests).\nIrrespective of method used, when moving between protocols, containers or encodings, LiveKit's egress service will automatically transcode streams for you using GStreamer.\n\n## Supported Output\n\n| Egress Type     | MP4 File | OGG File | WebM File | HLS (TS Segments) | RTMP(s) Stream | SRT Stream | WebSocket Stream | Thumbnails (JPEGs) |\n|-----------------|----------|----------|-----------|-------------------|----------------|------------------|------------------|--------------------|\n| Room Composite  | ✅        | ✅        |           | ✅                 | ✅              | ✅              |                  | ✅                  |\n| Web             | ✅        | ✅        |           | ✅                 | ✅              | ✅              |                  | ✅                  |\n| Track Composite | ✅        | ✅        |           | ✅                 | ✅              | ✅              |                  | ✅                  |\n| Track           | ✅        | ✅        | ✅         |                   |                |               | ✅                |                    |\n\nFiles can be uploaded to any S3 compatible storage, Azure, or GCP.\n\n## Documentation\n\nFull docs available [here](https://docs.livekit.io/guides/egress/)\n\n### Config\n\nThe Egress service takes a yaml config file:\n\n```yaml\n# required fields\napi_key: livekit server api key. LIVEKIT_API_KEY env can be used instead\napi_secret: livekit server api secret. LIVEKIT_API_SECRET env can be used instead\nws_url: livekit server websocket url. LIVEKIT_WS_URL can be used instead\nredis:\n  address: must be the same redis address used by your livekit server\n  username: redis username\n  password: redis password\n  db: redis db\n\n# optional fields\nhealth_port: port used for http health checks (default 0)\ntemplate_port: port used to host default templates (default 7980)\nprometheus_port: port used to collect prometheus metrics (default 0)\ndebug_handler_port: port used to host http debug handlers (default 0)\nlogging:\n  level: debug, info, warn, or error (default info)\n  json: true\ntemplate_base: can be used to host custom templates (default http://localhost:\u003ctemplate_port\u003e/)\nbackup_storage: files will be moved here when uploads fail. location must have write access granted for all users\nenable_chrome_sandbox: if true, egress will run Chrome with sandboxing enabled. This requires a specific Docker setup, see below.\ncpu_cost: # optionally override cpu cost estimation, used when accepting or denying requests\n  room_composite_cpu_cost: 3.0\n  web_cpu_cost: 3.0\n  track_composite_cpu_cost: 2.0\n  track_cpu_cost: 1.0\nsession_limits: # optional egress duration limits - once hit, egress will end with status EGRESS_LIMIT_REACHED\n  file_output_max_duration: 1h\n  stream_output_max_duration: 90m\n  segment_output_max_duration: 3h\n\n# file upload config - only one of the following. Can be overridden per request\nstorage:\n  s3:\n    access_key: AWS_ACCESS_KEY_ID env or EMPTY if using IAM Role or instance profile\n    secret: AWS_SECRET_ACCESS_KEY env or EMPTY if using IAM Role or instance profile\n    session_token: AWS_SESSION_TOKEN env or EMPTY if using IAM Role or instance profile\n    region: AWS_DEFAULT_REGION env or EMPTY if using IAM Role or instance profile\n    endpoint: (optional) custom endpoint\n    bucket: bucket to upload files to\n    # the following s3 options can only be set in config, *not* per request, they will be added to any per-request options\n    proxy_config:\n      url: (optional) proxy url\n      username: (optional) proxy username\n      password: (optional) proxy password\n    max_retries: (optional, default=3) number or retries to attempt\n    max_retry_delay: (optional, default=5s) max delay between retries (e.g. 5s, 100ms, 1m...)\n    min_retry_delay: (optional, default=500ms) min delay between retries (e.g. 100ms, 1s...)\n    aws_log_level: (optional, default=LogOff) log level for aws sdk (LogDebugWithRequestRetries, LogDebug, ...) \n  azure:\n    account_name: AZURE_STORAGE_ACCOUNT env can be used instead\n    account_key: AZURE_STORAGE_KEY env can be used instead\n    container_name: container to upload files to\n  gcp:\n    credentials_json: GOOGLE_APPLICATION_CREDENTIALS env can be used instead\n    bucket: bucket to upload files to\n    proxy_config:\n      url: (optional) proxy url\n      username: (optional) proxy username\n      password: (optional) proxy password\n  alioss:\n    access_key: Ali OSS AccessKeyId\n    secret: Ali OSS AccessKeySecret\n    region: Ali OSS region\n    endpoint: (optional) custom endpoint\n    bucket: bucket to upload files to\n\n# dev/debugging fields\ninsecure: can be used to connect to an insecure websocket (default false)\ndebug:\n  enable_profiling: create and upload pipeline dot file and pprof file on pipeline failure\n  s3: upload config for dotfiles (see above)\n  azure: upload config for dotfiles (see above)\n  gcp: upload config for dotfiles (see above)\n  alioss: upload config for dotfiles (see above)\n```\n\nThe config file can be added to a mounted volume with its location passed in the EGRESS_CONFIG_FILE env var, or its body can be passed in the EGRESS_CONFIG_BODY env var.\n\n### Filenames\n\nThe below templates can also be used in filename/filepath parameters:\n\n| Egress Type     | {room_id} | {room_name} | {time} | {utc} | {publisher_identity} | {track_id} | {track_type} | {track_source} |\n|-----------------|-----------|-------------|--------|-------|----------------------|------------|--------------|----------------|\n| Room Composite  | ✅         | ✅           | ✅      | ✅     |                      |            |              |                |\n| Web             |           |             | ✅      | ✅     |                      |            |              |                |\n| Track Composite | ✅         | ✅           | ✅      | ✅     | ✅                    |            |              |                |\n| Track           | ✅         | ✅           | ✅      | ✅     | ✅                    | ✅          | ✅            | ✅              |\n\n* If no filename is provided with a request, one will be generated in the form of `\"{room_name}-{time}\"`.\n* If your filename ends with a `/`, a file will be generated in that directory.\n* For 1/2/2006, 3:04:05.789 PM, {time} format would display \"2006-01-02T150405\", and {utc} format \"20060102150405789\"\n\nExamples:\n\n| Request filename                         | Resulting filename                                |\n|------------------------------------------|---------------------------------------------------|\n| \"\"                                       | testroom-2022-10-04T011306.mp4                    |\n| \"livekit-recordings/\"                    | livekit-recordings/testroom-2022-10-04T011306.mp4 |\n| \"{room_name}/{time}\"                     | testroom/2022-10-04T011306.mp4                    |\n| \"{room_id}-{publisher_identity}.mp4\"     | 10719607-f7b0-4d82-afe1-06b77e91fe12-david.mp4    |\n| \"{track_type}-{track_source}-{track_id}\" | audio-microphone-TR_SKasdXCVgHsei.ogg             |\n\n### Running locally\n\nThese changes are **not** recommended for a production setup.\n\nTo run against a local livekit server, you'll need to do the following:\n\n- open `/usr/local/etc/redis.conf` and comment out the line that says `bind 127.0.0.1`\n- change `protected-mode yes` to `protected-mode no` in the same file\n- find your IP as seen by docker\n  - `ws_url` needs to be set using the IP as Docker sees it\n  - on linux, this should be `172.17.0.1`\n  - on mac or windows, run `docker run -it --rm alpine nslookup host.docker.internal` and you should see something like\n    `Name: host.docker.internal Address: 192.168.65.2`\n\nThese changes allow the service to connect to your local redis instance from inside the docker container.\n\nCreate a directory to mount. In this example, we will use `~/egress-test`.\n\nCreate a config.yaml in the above directory.\n\n- `redis` and `ws_url` should use the above IP instead of `localhost`\n- `insecure` should be set to true\n\n```yaml\nlog_level: debug\napi_key: your-api-key\napi_secret: your-api-secret\nws_url: ws://192.168.65.2:7880\ninsecure: true\nredis:\n  address: 192.168.65.2:6379\n```\n\nThen to run the service:\n\n```shell\ndocker run --rm \\\n    -e EGRESS_CONFIG_FILE=/out/config.yaml \\\n    -v ~/egress-test:/out \\\n    livekit/egress\n```\n\nYou can then use our [cli](https://github.com/livekit/livekit-cli) to submit egress requests to your server.\n\n### Chrome sandboxing\n\nBy default, Room Composite and Web egresses run with Chrome sandboxing disabled. This is because the default docker security settings prevent Chrome from\nswitching to a different kernel namespace, which is needed by Chrome to setup its sandbox.\n\nChrome sandboxing within Egress can be reenabled by setting the the `enable_chrome_sandbox` option to `true` in the egress configuration, and launching docker using the [provided\nseccomp security profile](https://github.com/livekit/egress/blob/main/chrome-sandboxing-seccomp-profile.json):\n\n```shell\ndocker run --rm \\\n    -e EGRESS_CONFIG_FILE=/out/config.yaml \\\n    -v ~/egress-test:/out \\\n    --security-opt seccomp=chrome-sandboxing-seccomp-profile.json \\\n    livekit/egress\n```\n\nThis profile is based on the [default docker seccomp security profile](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json) and allows\nthe 2 extra system calls (`clone` and `unshare`) that Chrome needs to setup the sandbox.\n\nNote that kubernetes disables seccomp entirely by default, which means that running with Chrome sandboxing enabled is possible on a kubernetes cluster with\nthe default security settings.\n\n## FAQ\n\n### Can I store the files locally instead of uploading to cloud storage?\n- Yes, you can mount a volume with your `docker run` command (e.g. `-v ~/livekit-egress:/out/`), and use the mounted\ndirectory in your filenames (e.g. `/out/my-recording.mp4`). Since egress is not run as the root user, write permissions\nwill need to be enabled for all users.\n\n### I get a `\"no response from egress service\"` error when sending a request\n\n- Your livekit server cannot connect to an egress instance through redis. Make sure they are both able to reach the same redis db.\n- If all of your egress instances are full, you'll need to deploy more instances or set up autoscaling.\n\n### I get a different error when sending a request\n\n- Make sure your egress, livekit, server sdk, and livekit-cli are all up to date.\n\n### Can I run this without docker?\n\n- It's possible, but not recommended. To do so, you would need to install gstreamer along with its plugins, chrome, xvfb,\n  and have a pulseaudio server running.\n\n## Testing and Development\n\nTo run the test against your own LiveKit rooms, a deployed LiveKit server with a secure websocket url is required.\nFirst, create `egress/test/config.yaml`:\n\n```yaml\nlog_level: debug\napi_key: your-api-key\napi_secret: your-api-secret\nws_url: wss://your-livekit-url.com\nredis:\n  address: 192.168.65.2:6379\nroom_only: false\nweb_only: false\ntrack_composite_only: false\ntrack_only: false\nfile_only: false\nstream_only: false\nsegments_only: false\ndot_files: false\nshort: false\n```\n\nJoin a room using https://example.livekit.io or your own client, then run `mage integration test/config.yaml`.\nThis will test recording different file types, output settings, and streams against your room.\n\n\u003c!--BEGIN_REPO_NAV--\u003e\n\u003cbr/\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\u003cth colspan=\"2\"\u003eLiveKit Ecosystem\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\u003ctd\u003eAgents SDKs\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit/agents\"\u003ePython\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/agents-js\"\u003eNode.js\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eLiveKit SDKs\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit/client-sdk-js\"\u003eBrowser\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-swift\"\u003eSwift\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-android\"\u003eAndroid\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-flutter\"\u003eFlutter\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-react-native\"\u003eReact Native\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/rust-sdks\"\u003eRust\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/node-sdks\"\u003eNode.js\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/python-sdks\"\u003ePython\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-unity\"\u003eUnity\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-unity-web\"\u003eUnity (WebGL)\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-esp32\"\u003eESP32\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/client-sdk-cpp\"\u003eC++\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eStarter Apps\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit-examples/agent-starter-python\"\u003ePython Agent\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-node\"\u003eTypeScript Agent\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-react\"\u003eReact App\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-swift\"\u003eSwiftUI App\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-android\"\u003eAndroid App\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-flutter\"\u003eFlutter App\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-react-native\"\u003eReact Native App\u003c/a\u003e · \u003ca href=\"https://github.com/livekit-examples/agent-starter-embed\"\u003eWeb Embed\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eUI Components\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit/components-js\"\u003eReact\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/components-android\"\u003eAndroid Compose\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/components-swift\"\u003eSwiftUI\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/components-flutter\"\u003eFlutter\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eServer APIs\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit/node-sdks\"\u003eNode.js\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/server-sdk-go\"\u003eGolang\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/server-sdk-ruby\"\u003eRuby\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/server-sdk-kotlin\"\u003eJava/Kotlin\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/python-sdks\"\u003ePython\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/rust-sdks\"\u003eRust\u003c/a\u003e · \u003ca href=\"https://github.com/agence104/livekit-server-sdk-php\"\u003ePHP (community)\u003c/a\u003e · \u003ca href=\"https://github.com/pabloFuente/livekit-server-sdk-dotnet\"\u003e.NET (community)\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eResources\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://docs.livekit.io\"\u003eDocs\u003c/a\u003e · \u003ca href=\"https://docs.livekit.io/mcp\"\u003eDocs MCP Server\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/livekit-cli\"\u003eCLI\u003c/a\u003e · \u003ca href=\"https://cloud.livekit.io\"\u003eLiveKit Cloud\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eLiveKit Server OSS\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://github.com/livekit/livekit\"\u003eLiveKit server\u003c/a\u003e · \u003cb\u003eEgress\u003c/b\u003e · \u003ca href=\"https://github.com/livekit/ingress\"\u003eIngress\u003c/a\u003e · \u003ca href=\"https://github.com/livekit/sip\"\u003eSIP\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eCommunity\u003c/td\u003e\u003ctd\u003e\u003ca href=\"https://community.livekit.io\"\u003eDeveloper Community\u003c/a\u003e · \u003ca href=\"https://livekit.io/join-slack\"\u003eSlack\u003c/a\u003e · \u003ca href=\"https://x.com/livekit\"\u003eX\u003c/a\u003e · \u003ca href=\"https://www.youtube.com/@livekit_io\"\u003eYouTube\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c!--END_REPO_NAV--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivekit%2Fegress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flivekit%2Fegress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivekit%2Fegress/lists"}