I built a free Omegle alternative with Angular, Socket.io and WebRTC
When Omegle shut down in November 2023, a lot of people lost a simple thing: open a page, click a button, and you're talking to a random person. No account, no app, no profile. I wanted that back, so I built talktostran
When Omegle shut down in November 2023, a lot of people lost a simple thing: open a page, click a button, and you're talking to a random person. No account, no app, no profile.
I wanted that back, so I built talktostrangersnow.com, a free random text and video chat with no sign-up. This post walks through how it works, what was harder than expected, and a few decisions I'd make again.
The stack
- Front end: Angular (standalone components and signals), prerendered on the server so pages show up instantly and search engines can read them.
- Back end: a single Node.js process with Express and Socket.io.
- Video: WebRTC, browser to browser.
- Hosting: Render, behind Cloudflare.
No database. Everything that matters lives in memory for as long as a chat lasts.
Matchmaking in about 20 lines
Each mode (text and video) has a simple queue. When someone clicks Start, the server looks for a partner in this order:
- someone waiting who shares at least one of your interests,
- otherwise, whoever has been waiting the longest.
function enqueue(user) {
const q = queues[user.mode];
// Prefer someone with a shared interest, otherwise take whoever waited longest.
let idx = -1;
if (user.interests.length) {
idx = q.findIndex((id) => {
const other = users.get(id);
return other && other.interests.some((i) => user.interests.includes(i));
});
}
if (idx === -1) idx = q.findIndex((id) => users.has(id));
if (idx === -1) {
q.push(user.id); // nobody to pair with yet: wait
return;
}
const partner = users.get(q.splice(idx, 1)[0]);
startPair(user, partner);
}
That's really it. With few users online, a fancy scoring system just makes people wait longer, so "shared interest first, then anyone" turned out to be the right trade-off. Both people are told which interests they have in common, which gives them something to say first.
Video: the server never sees it
For video chats the server only does signaling: it passes the WebRTC offer, answer and network candidates between the two browsers over Socket.io. Once they've connected, the audio and video go directly from one browser to the other.
Two things I learned the hard way:
- STUN isn't enough for everyone. On strict mobile or corporate networks the two browsers can't reach each other directly, and the video stays black. A TURN server (which relays the media when a direct path fails) fixes that, so the server reads TURN settings from environment variables.
-
Switching camera mid-call doesn't need a new connection.
RTCRtpSender.replaceTrack()swaps the camera or microphone without renegotiating, so changing devices in the settings takes effect instantly.
Fast pages for a real-time app
The chat itself is interactive, but the pages around it (home, text chat, video chat, and pages in German, Spanish, French, Italian and Japanese) are prerendered to static HTML at build time. The browser gets real content on the first response, and the Angular app takes over from there.
A detail that helped: the Socket.io connection only opens when the visitor first moves the mouse, scrolls or taps. Visitors who just read the page never open a socket, and the page loads faster for them.
Moderating without recording anyone
This was the part I thought about the most. Random chat attracts people who break the rules, but I didn't want to record anyone.
What I ended up with:
- Video is never recorded. For video chats, the browser sends a small, low-quality snapshot only while a moderator actually has that chat on screen. When nobody is watching, nothing is sent.
- Text chats are not shown to moderators live. The last few messages are kept in memory while the chat lasts, and they're only saved if someone presses Report. Then a moderator can read them and ban the person who broke the rules.
- Reporting ends the chat right away for the person who reported, so they don't have to keep looking at whatever made them report it.
It's a balance between privacy and safety, and I'm sure it will keep changing.
What I'd do again
- Keep it one process until it actually needs more. Socket.io and Express in a single Node process are easy to reason about and cheap to run.
- Prerender everything that isn't the chat itself. Fast first load matters a lot for a "click and go" product.
- Small things matter: auto-join the next chat after a countdown, Esc to skip, a "Stranger is typingβ¦" line, a sound when someone connects. Those made it feel alive more than any big feature.
Try it
It's free, there are no ads, and there's nothing to sign up for: talktostrangersnow.com. It's new, so it's quieter at some times of day than others; text chat is the quickest way to get matched.
I'd love feedback, especially on video quality on your network and anything that feels broken. Thanks for reading!
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.