Self-hosted service
miroslavpejic85/call-me avatar
miroslavpejic85/call-me

MiroTalk CME: self-hosted WebRTC click-to-call for your website

📞 Open-source, self-hosted WebRTC click-to-call solution for websites. Add a video Call-Me button and let visitors instantly connect with your team through browser-based video communication. Ideal for customer support, sales, consultations, and remote assistance.

763 stars90 forksJavaScriptAGPL-3.0

At a glance

What is it?
MiroTalk CME puts a Call-Me button on any page and routes visitors into a one-to-one WebRTC video call with your team, without a signup flow. The trade-off is that it is a single-purpose widget, not a contact-centre platform, and its AGPL-3.0 licence shapes what you can do with the code.
Who is it for?
Adopt MiroTalk CME if you want a browser-based one-to-one video call button on your own server and you accept the AGPL-3.0 obligations. Do not adopt it if you need multi-party conferencing, an agent queue, or a hosted SLA, because the README describes a room-based peer call, not a contact centre.
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 1 day 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 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem MiroTalk CME solves, and who it is for

Most sites that want a live conversation end up with one of two things: a text chat widget that stalls when the question needs a screen share, or a link to an external meeting tool that asks the visitor to install nothing but still leaves the page. MiroTalk CME targets the second gap. The README describes it as an "Open-source, self-hosted WebRTC click-to-call solution for websites", and the flow it enables is direct: a visitor opens a URL, enters a name, and calls a named recipient who is already connected.

The intended users are small support, sales and consultation teams that want the call to happen on their own infrastructure. The README names customer support, sales, consultations and remote assistance as the cases. The unit of interaction is one-to-one video, not a webinar and not a conference bridge, and the README's own walkthrough ends with "Enjoy your one-to-one video call". If your requirement is a room of eight people, this is not the shape of the tool.

How the call actually gets established

The application is a Node.js server built on Express and Socket.IO, with the browser handling media. package.json lists express, socket.io, helmet, cors and express-rate-limit as runtime dependencies, and the start script runs node app/server.js. That is the signalling layer: the server keeps track of who is connected, in which room, and relays the session setup between two browsers. The media itself is WebRTC peer-to-peer, which is why the repository carries a coturn directory. TURN is what makes a peer connection survive symmetric NAT and restrictive corporate firewalls, and if you self-host without a working TURN service, calls that succeed on your office Wi-Fi can fail for a visitor on a mobile network.

Rooms are the grouping mechanism. By default everyone lands in a room called Public. Adding a room parameter separates audiences, and the README is explicit that users "only see and can call others in the same room", with the note that "The call target must be in the same room as the caller." That is a routing rule, not an access-control boundary, and the README says so about per-room branding: it is "Visual only, not a security feature." If you need to stop strangers from joining a room, Host Protection with a password is the feature the README lists for that.

Installing it and placing a first call

The README gives two install paths. The Node.js path clones the repository, copies two template files, installs dependencies and starts the server. The config copy matters: public/config.template.js is the template and public/config.js is what the app reads, and the same pattern applies to .env.template. Run these commands from a shell and you should see the server start on port 8000.

bash
git clone https://github.com/miroslavpejic85/call-me.git
cd call-me
cp public/config.template.js public/config.js
cp .env.template .env
npm install
npm start

With the server running, open http://localhost:8000, join with a username, and you are in the default Public room. The click-to-call part is a URL contract rather than a JavaScript API. The README shows that appending user and call parameters to /join pre-fills the identity and targets a recipient, so a link on your page can drop a visitor straight into a call with a named agent.

text
http://localhost:8000/join?user=user2&call=user1
http://localhost:8000/join?user=user1&room=Support
http://localhost:8000/join?user=user2&call=user1&room=Support

The first link has user2 call user1 in the default room. The second joins user1 into a room named Support. The third does both, and only works because caller and target share the room. The repository also ships integration/widget.html as a worked example of embedding this, which is the file to read before writing your own button.

Docker, HTTPS and the port question

The Docker path is the same clone and config copy, then a compose file copied from docker-compose.template.yml, a pull of the mirotalk/cme image and docker-compose up. The Dockerfile is small and sensible: node:24-alpine, NODE_ENV set to production, npm ci with --only=production, and the process runs as the non-root node user. That last detail is worth noting because it is the kind of thing many self-hosted projects skip.

What the README does not spell out in the excerpt available is the production TLS story. httpolyglot is in the dependency list, which is the package used to serve HTTP and HTTPS on the same port, and the demo runs at an https:// URL. Browsers will not grant camera and microphone access on a plain http:// origin except for localhost, so a public deployment needs a certificate in front of it. Treat that as a deployment task you must plan for, not something the quick start hands you. The README's self-hosting section points at Ubuntu requirements and install scripts but the text is truncated in the excerpt, so the exact certificate steps are not something I can quote here.

The API and webhooks change what you can build

Two features push this past a demo widget. The README lists a REST API that can retrieve connected users, rooms, availability status, active calls and server stats, and can initiate a call. swagger-ui-express is a dependency, so the API surface is documented in the running app rather than only in prose. The second is webhooks for call lifecycle events: user joined, user left, call started, call ended with duration. The repository has a webhook directory for this.

That combination is what makes the tool integrable. A support team can poll availability before rendering the Call-Me button, and a CRM can receive a call-ended event with a duration and write it against a contact record. The limitation is that the README describes the events, not a delivery guarantee. There is no mention of retries, signing, or ordering. If a webhook consumer is down when a call ends, the excerpt gives no indication of what happens to that event, so do not design a billing or SLA process on top of it without reading the webhook code first.

Where MiroTalk CME is the wrong tool

The clearest failure mode is scale of conversation. Every call in the README is between two parties. There is no described mechanism for adding a third participant, no waiting queue, no routing rules that pick the least-busy agent, and no supervisor view. A team that needs any of those is looking at a different class of product, and stretching this one will not get there.

The second is the security model. Rooms group people; they do not authenticate them. The README's own note that per-room branding is "Visual only, not a security feature" is a fair warning about how to read the room parameter generally. Anyone with the URL and the room name can join that room unless Host Protection is enabled with a password. For a public support room that is acceptable. For a consultation with a specific client, it means the room name is effectively the shared secret, and you should treat link distribution accordingly.

The third is operational. There are no retrieved releases for this repository, so there is no changelog to read before upgrading. The last push was on 2026-09-06, which is recent, but a version number in package.json (1.5.35) is not a release process. You are tracking a branch.

Alternatives and how they differ

The obvious comparison is a hosted video API such as the Daily or Twilio Video style of service, where you get an SDK, a managed TURN infrastructure and a status page, and you pay per minute. The difference in approach is who owns the media path. With MiroTalk CME you run the signalling server and the TURN service yourself, so a network problem is your problem, but no per-minute meter runs and no call metadata leaves your infrastructure. With a hosted API you write less infrastructure code and inherit someone else's outage page.

The second comparison is a text live-chat widget. Those are cheaper to run and easier to staff, and for many pre-sales questions they are enough. The reason to move to video is the case where a screen share or a face resolves the question faster than typing, which is precisely the case the README's feature list addresses with screen sharing and file sharing during a call.

A third option is running the wider MiroTalk family of projects, since this repository is part of that set and shares the author. If your need grows from one-to-one into a meeting room, that is the direction to look rather than adding participants to this codebase.

Licence and the cost of staying current

The licence is AGPL-3.0, stated in package.json and in LICENSE.md. The practical consequence of the AGPL for a web application is the network clause: if you modify the software and let users interact with it over a network, the licence requires you to offer those users the corresponding source. Running it unmodified as a service is a different question from forking it and shipping your own version, and the two should be discussed with someone qualified to give legal advice rather than decided from a README.

Upgrade cost is the other line item. There are no retrieved releases, so the upgrade signal is the commit history on the default branch. The .env.template and public/config.template.js files are the two places your local configuration diverges from upstream, which means every pull has the potential to conflict there. Keeping your changes confined to config.js and .env, and leaving app/ and public/ otherwise untouched, is the cheapest way to stay close enough to pull. The npm test script runs node --test, so there is a test suite to run after an upgrade, and test/ exists in the repository layout.

Editorial conclusion

Adopt MiroTalk CME if you want a browser-based one-to-one video call button on your own server and you accept the AGPL-3.0 obligations. Do not adopt it if you need multi-party conferencing, an agent queue, or a hosted SLA, because the README describes a room-based peer call, not a contact centre. Before you commit, verify that your deployment is reachable over HTTPS, that the coturn directory in the repository matches your network, and that you have read the AGPL-3.0 terms in LICENSE.md.

Frequently asked questions

What is MiroTalk CME?

It is an open-source, self-hosted WebRTC click-to-call solution for websites, described in the README as a way to add a video Call-Me button so visitors connect with your team through browser-based video. It is built on Node.js with Express and Socket.IO for signalling, with media carried peer-to-peer over WebRTC.

How do I install MiroTalk CME?

The README gives two paths. With Node.js you clone the repository, copy public/config.template.js to public/config.js and .env.template to .env, run npm install, then npm start. With Docker you copy docker-compose.template.yml to docker-compose.yml, run docker-compose pull, then docker-compose up.

What port does MiroTalk CME listen on?

The README's quick start tells you to open your browser and visit http://localhost:8000 after starting the application, so that is the port used in the documented local setup.

Can MiroTalk CME handle a call with more than two people?

The README describes one-to-one video calls throughout, and its walkthrough ends with a one-to-one call. There is no described mechanism for adding a third participant to an existing call.

How do I make a click-to-call link with MiroTalk CME?

The README shows that the /join route accepts a user parameter to set the identity and a call parameter to target a recipient, for example /join?user=user2&call=user1. A room parameter can be added to group users, but the call target must be in the same room as the caller.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. miroslavpejic85/call-me on GitHub
  4. Project website
  5. README
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/miroslavpejic85-call-me.svg)](https://hysenlabs.com/projects/miroslavpejic85-call-me)