MiroTalk C2C is a self-hosted two-person video call you can embed
📹 Open-source, self-hosted WebRTC 1-to-1 video calling for private real-time communication. Build secure browser-based consultations, coaching, support, telehealth, and other video call experiences with peer-to-peer communication and screen sharing.
At a glance
- What is it?
- miroslavpejic85/mirotalkc2c is an AGPL-3.0 WebRTC application for 1-to-1 cam-to-cam calls with screen sharing, end-to-end encryption, browser-side camera backgrounds and an iframe integration for embedding a call into your own site. It is a signalling server plus a browser client, and the two are what set its limits.
- Who is it for?
- Adopt MiroTalk C2C if you need a two-person call embedded in a product you already own, or a private consultation link that never touches a third-party meeting service, and you are willing to run a Node server and handle TLS yourself. Do not adopt it for group calls or for a product where AGPL-3.0 source obligations are a problem, since the licence reaches networked use and the tool is built for two participants.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One call, two people, no third party in the middle
MiroTalk C2C is described as a self-hosted, open-source WebRTC platform for cam-to-cam peer-to-peer video calls and screen sharing, with full end-to-end encryption and an iframe integration so it can be dropped into any website.
The scope is deliberately narrow. This is not a meeting platform with rooms, breakout areas, chat history and participant lists. It is 1-to-1. The use cases the description lists, consultations, coaching, support and telehealth, all describe a conversation between two people where the interesting property is that the media never passes through a vendor's infrastructure.
That last part is the differentiator and the reason the project is worth looking at separately from a general conferencing tool. In a WebRTC call, the video and audio travel directly between the two browsers. What the server does is signal: it introduces the two peers, relays the session description and the ICE candidates, and then gets out of the way. For a telehealth or counselling deployment, that means the party operating the service is not in a position to decrypt the conversation, which is a materially different claim from a cloud meeting service with end-to-end encryption on top of a recording feature.
The AGPL-3.0 licence is the other headline. For a self-hosted tool you run yourself, that is not a burden. If you embed it in a hosted product, it is, and the README links the licence terms directly.
The project also publishes a live demo at c2c.mirotalk.com, a privacy page, and a Discord community, and the last push to the repository was on 2026-10-18, with no GitHub releases, so the running version is whatever the branch holds.
Five commands from clone to a call on localhost:8080
The quick start is short enough to trust, which is a good sign for a project of this size.
git clone https://github.com/miroslavpejic85/mirotalkc2c.git
cd mirotalkc2c
cp .env.template .env
npm install
npm startAfter that you open `http://localhost:8080` and you are done. The copy of `.env.template` to `.env` matters more than it looks: the template exists so that the configuration file is yours to edit rather than something baked into the image, and the same template is copied into the Docker image at build time, so the file you supply is the file the server reads.
The npm scripts confirm how thin the runtime is. `start` runs `node backend/server.js` and `dev` runs the same file under `node --watch`. Tests are Mocha over `tests/*.js`, and linting is `npx prettier --write .`.
The repository layout shows a two-part application: a `backend/` directory and a `frontend/` directory, plus a `Dockerfile`, `docker-compose.template.yml`, `install.sh`, `docs/` and a `cotrun/` directory. There is also a `docker-compose-mailpit.yml`, which suggests a Mailpit container for catching outbound mail in development rather than sending it, and a `.env.template` at the top level.
One detail to note: the package version in the manifest is 1.4.81, which is a patch-level numbering on a long-lived 1.x line. The repository has no GitHub releases, so the version in `package.json` is the version you get, and it tells you the project is iterated on continuously rather than cut at milestones.
Docker path, and the non-root detail in the image
The Docker route needs Docker Engine and Docker Compose, and the image is published on Docker Hub as `mirotalk/c2c`.
git clone https://github.com/miroslavpejic85/mirotalkc2c.git
cd mirotalkc2c
cp .env.template .env
cp docker-compose.template.yml docker-compose.yml
docker-compose pull # optional: pull official image
docker-compose up # add -d to run in backgroundThe compose file is a template you copy and edit, which is the same pattern as the environment file: the repository ships working defaults, and what you deploy is what you configured. The README notes you should edit `.env` and `docker-compose.yml` to customise the setup.
The `Dockerfile` is worth reading because it makes a few decisions explicit. It is built on `node:24-bookworm-slim`, with a comment explaining that Debian slim was chosen for more reliable multi-arch builds under emulation. The working directory is `/src`, `NODE_ENV` is set to production, and dependencies are installed with `npm ci --omit=dev --silent`, which installs exactly the lockfile and skips dev dependencies, with the npm cache and apt lists cleaned afterwards.
The part that matters for a service exposed to the internet is the user. The application code is copied with `--chown=node:node` and the container then switches to the non-root `node` user that ships with the base image, uid and gid 1000, and the default command is `npm start`. Running as an unprivileged user in a container that processes untrusted media negotiation is a small thing, but it is the right small thing, and it is the kind of detail that distinguishes a project that has been run in production from one that has only been built on a laptop.
The npm scripts also cover the image lifecycle, with tags to build, push, pull, remove, run and stop the container, and a variant that mounts `.env`, `frontend/` and `backend/` as read-only volumes for development against the containerised runtime.
Camera backgrounds that never leave the browser
The camera background feature is the most detailed part of the README, and the detail is mostly about failure modes, which is a good sign.
In Settings, under Video, then Background, you choose Off, Blur or Image. PNG, JPEG and WebP images up to 10 MB are processed locally in your browser and are not uploaded. The effect appears in the camera preview, in outgoing camera video and in camera recordings, and screen sharing is unaffected, with the effect resuming when you return to the camera. Background changes are blocked while a recording is in progress.
The constraints are stated plainly. Effects need WebGL2 and canvas stream capture, and blur also needs canvas filter support. MediaPipe Tasks Vision 0.10.21 and its WASM files are lazy-loaded from jsDelivr, and the selfie segmentation model, version 1, is loaded from Google Storage. Those hosts must be reachable and must be allowed by any custom Content Security Policy, including WASM execution. When processing fails, the app falls back to the original camera.
That fallback sentence is the important one. A background effect that silently disappears is much less bad than a call that breaks, and the design says so explicitly.
The performance envelope is also given: output is capped at 1280 x 720 and 15 FPS, performance varies by device, background tabs may throttle rendering, and image selections are not persisted across page reloads. The requirement that a third-party host be reachable for a privacy feature is worth noting on its own. The images stay local, but the segmentation model and the WASM runtime do not, which means a deployment that blocks jsDelivr or Google Storage will not get backgrounds at all.
The iframe integration is the actual product for most users
The description lists consultations, coaching, support and telehealth as the target use cases, and the integration documentation is given the same weight as the self-hosting guide.
The claim is that the call can be embedded into any website via a simple iframe integration, with a dedicated integration page in the documentation and a separate guide for direct room join. The homepage being a hosted demo at c2c.mirotalk.com and the existence of a REST API section and a Direct Room Join page in the documentation index together suggest a shape: you host the service, you generate or share a room link, and either the user joins in a full page or the call renders inside your own interface.
That is the scenario where this project beats a general meeting service. If you already have a product with users, and a customer needs to talk to a specialist, you can put the call inside your application, on your own domain, with your own authentication in front of it, and no third party learns who spoke to whom.
The alternative is the same WebRTC building blocks assembled yourself, or embedding an existing meeting provider through its own SDK. The difference in approach is that here you operate the signalling server, so you control where session metadata goes, and you accept the operational work that comes with it. The documentation list also includes pages for configurations, automation scripts and Ngrok, which is a strong hint at what the operational profile looks like: running a signalling server behind NAT, and using a tunnel during development.
What the README does not document is the relay path. A WebRTC call between two peers behind restrictive NATs needs a TURN server, and the README given here does not say how MiroTalk C2C handles that or whether one must be supplied. That is the first thing to check in the self-hosting guide before you promise a call will connect.
Maintenance, licensing and the shape of the dependencies
The repository is not archived, the last push was on 2026-10-18, and there are no GitHub releases, so the project is developed continuously on the default branch with the version tracked in `package.json`, currently 1.4.81.
The licence is AGPL-3.0, and the README links it directly. For self-hosting for your own team, the practical requirement is that if you modify it and offer it over a network, you offer the corresponding source. If you embed it in a commercial product for your customers, you need to read the terms carefully, because the network use clause is what makes AGPL different from GPL for a hosted deployment. This is the point where a legal review earns its keep, and the README is not the place to get that answer.
The dependency list starts to show the shape of the project. The manifest includes `@mattermost/client` at 11.9.0 and `@ngrok/ngrok`, and the keywords list `socket.io`, `ngrok`, `webrtc`, `video`, `audio` and `cam2cam`. So the signalling layer is Socket.IO, there is a Mattermost client for a chat integration, and there is built-in support for exposing a local instance through an Ngrok tunnel, which is the standard way to test a WebRTC server on a laptop without buying a public IP address.
The presence of Ngrok support in a self-hosted privacy tool is a reasonable feature, since the alternative for local development is port forwarding, but it is worth being deliberate about when a tunnel is in use.
The project also ships a `SECURITY.md` and a `CODE_OF_CONDUCT.md`, and the Docker image runs as a non-root user, which together suggest a project that treats its operational surface with some care. Those are small signals, but they are the signals you have when there is no release history to inspect.
Editorial conclusion
Adopt MiroTalk C2C if you need a two-person call embedded in a product you already own, or a private consultation link that never touches a third-party meeting service, and you are willing to run a Node server and handle TLS yourself. Do not adopt it for group calls or for a product where AGPL-3.0 source obligations are a problem, since the licence reaches networked use and the tool is built for two participants. Before you deploy, read the self-hosting guide, decide how the signalling server will be reached from the public internet, and set your own TURN or relay expectations, because the README does not document the relay behaviour it falls back to.
Frequently asked questions
How do I self-host MiroTalk C2C?
Clone the repository, copy `.env.template` to `.env`, run `npm install` and then `npm start`, and open `http://localhost:8080`. The Docker route copies `docker-compose.template.yml` to `docker-compose.yml` and runs `docker-compose up`, with the image published as `mirotalk/c2c` on Docker Hub.
Is MiroTalk C2C encrypted end to end?
The project describes itself as offering full end-to-end encryption for peer-to-peer cam-to-cam calls with screen sharing. The media travels directly between the two browsers, and the server handles signalling rather than carrying the call.
Can I embed a MiroTalk C2C call in my own website?
Yes. The README states the call can be embedded into any website via an iframe integration, and the documentation includes a dedicated integration page along with a Direct Room Join guide and REST API documentation.
Do camera background effects upload my images?
No. PNG, JPEG and WebP images up to 10 MB are processed locally in your browser and are not uploaded. The MediaPipe WASM files and the selfie segmentation model are lazy-loaded from jsDelivr and Google Storage, so those hosts must be reachable and allowed by your Content Security Policy, or the effect falls back to the original camera.
What licence is MiroTalk C2C released under?
AGPL-3.0, as stated in the README and in the package manifest, with a LICENSE file in the repository. The network use clause matters if you offer a modified version as a service, so read the licence before embedding it in a hosted product.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/miroslavpejic85-mirotalkc2c)Was this useful?