Skip to content

Instantly share code, notes, and snippets.

@nucular
Last active January 10, 2025 16:58
Show Gist options
  • Save nucular/e19264af8d7fc8a26ece to your computer and use it in GitHub Desktop.
Save nucular/e19264af8d7fc8a26ece to your computer and use it in GitHub Desktop.
Omegle protocol reverse-engineering

Let's reverse-engineer Omegle. PROPERLY!

I didn't manage to find a proper, detailed (and up-to-date) reverse-engineerment of Omegle's text chat protocol on the interwebs, so here, have one!
The responses are beautified and the query strings split up and URI-decoded for readability.
Note that "query string" refers to parameters encoded into the URL and "form data" to parameters in the request body, which don't have to be encoded.

TODO:

  • Find out how college authorization works
  • Find out how WebRTC video streaming works
  • Generally phrase things better

Used Request Headers:

Accept: application/json
Accept-Encoding: gzip,deflate
Accept-Language: en-US;q=0.6,en;q=0.4
Connection: keep-alive
DNT: 1
Host: front9.omegle.com
Origin: http://www.omegle.com
Referer: http://www.omegle.com/
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36

Status

Pro-Tip: Fetch this first and then use one of the servers listed for future connections. You can just connect to the main server here.

GET http://[server].omegle.com/status

Query String:

  • nocache = 0.4695589093025774 (optional, random nonce to prevent cached responses from being sent)
  • randid = CHPZGFFW (optional, see section "Start")

Response:

{
    "count": 20840, (connection count, people say it's faked)
    "force_unmon": true, (see section "Getting b&")
    "antinudeservers": [
        "waw3.omegle.com", "waw2.omegle.com", "waw1.omegle.com"
    ],
    "antinudepercent": 1.0,
    "spyQueueTime": 0.0, (if spyQueueTime is larger, there are more spies than spyees online, which the client uses to suggest a mode)
    "spyeeQueueTime": 2.173300027847,
    "timestamp": 1409233880.7561221,
    "servers": [
        "front5.omegle.com", "front1.omegle.com", "front2.omegle.com",
        "front9.omegle.com", "front6.omegle.com", "front7.omegle.com",
        "front8.omegle.com", "front4.omegle.com", "front3.omegle.com"
    ]
}

Start

This actually starts the chat and gets us our client ID. If you want to start a question/spy chat, send wantsspy = 1 for spyee mode and ask = blah for spyer mode.

POST http://[server].omegle.com/start

Query String:

  • rcs = 1
  • firstevents = 1
  • m = 1 (imitate a mobile connection, shouldn't really matter)
  • lang = en (two-char language code)
  • randid = CHPZGFFW (this is really just a random string containing 2-9 and A-Z)
  • spid = (some kind of ID from Adobe Stratus, never used though)
  • topics = ["asdf", "test", ...] (optional, for default mode)
  • wantsspy = 1 (for spyee mode)
  • ask = blah question? (for spyer mode)
  • cansavequestion = 1 (Omegle may reuse your question)
  • group = unmon (join the unmonitored section instead)

Response:

{
    "events": [
        ...see section "Events"...
    ],
    "clientID": "central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh" (needed for all subsequent requests)
}

Events

This one uses long polling, which means that the server will be blocking the connection until an event happens. You can handle this with some async magic and long timeouts.

POST http://[server].omegle.com/events

Form Data:

  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Response:

[
    [...see below...], ...
]

Status events

  • ["waiting"] (the server is searching for strangers)
  • ["connected"] (you can start sending messages now)
  • ["statusInfo", {...stripped...}] (see section "Status")

Notifications

  • ["commonLikes", ["asdf", "test", ...]] (the shared topics from the ones you've passed)
  • ["serverMessage", "blah"] (most likely You both speak the same language.)
  • ["recaptchaRequired", "[challenge]"] (see section "ReCAPTCHAs")
  • ["recaptchaRejected", "[challenge]"]
  • ["identDigests", "blah,blah,blah"] (probably just used for sharing logs)

Error events (disconnects you)

  • ["error", "blah blah error text!"] (general error message)
  • ["connectionDied"] (some technical error)
  • ["antinudeBanned"] (see section "Getting b8")

Chat events

  • ["typing"] (the stranger started typing)
  • ["stoppedTyping"] (...stopped typing)
  • ["gotMessage", "blah"] (...sent a message)
  • ["strangerDisconnected"] (...decided to disconnect)

In spyee mode

  • ["question", "blah?"] (the question you'll discuss with the stranger)

In spyer mode

  • ["question", "blah question?"] (your question)
  • ["spyTyping", "Stranger <1/2>"] (Stranger 1/2 started typing)
  • ["spyStoppedTyping", "Stranger <1/2>"] (...stopped typing)
  • ["spyMessage", "Stranger <1/2>", "blah"] (...sent a message)
  • ["spyDisconnected", "Stranger <1/2>"] (...decided to disconnect)

Send messages

I'm not sure about the Unicode support, but it should work in most cases.

POST http://[server].omegle.com/send

Form Data:

  • msg = lol
  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Response:

win

Set your "typing" status

The server may detect clients that don't send these.

POST http://[server].omegle.com/typing
POST http://[server].omegle.com/stoppedtyping

Form Data:

  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Response:

win

Stop looking for common topics

If you've passed topics to /start, the server will send the waiting event and then search for people with the same topics until this gets posted. Use this to stop the running search, ignore the topics and continue with connecting.

POST http://[server].omegle.com/stoplookingforcommonlikes

Form Data:

  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Response:

win

Disconnect from the current chat

Simple as that. Always use this to end sessions gracefully, unless noted beneath events.

POST http://[server].omegle.com/disconnect

Form Data:

  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Response:

win

ReCAPTCHAS

If you run into an recaptchaRequired event, you must prove that you're a human by fetching the captcha using the URL-encoded passed code from http://www.google.com/recaptcha/api/image?c=[challenge] and sending the answer like this. Note that I haven't tried this yet.

POST http://[server].omegle.com/recaptcha

Form Data:

  • id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh
  • challenge = [challenge]
  • response = [answer]

Getting b&

If you got an antinudeBanned event, chances are that the moderators banned you from the monitored section for "bad behaviour". This also applies if the server status object (see section "Status") has force_unmon set as true. You can retry by passing group = unmon to /start. That won't work if you got your IP banned because of too rapid connecting or advertising, though.

Sharing logs

To upload your logs to Omegles server, use this.
Pro-Tip: You can actually pass any arbitrary text as the log (note the double brackets though). The first item is always the header, ("You're chatting with a random stranger on Omegle!") and the last the footer ("You have disconnected."). If the second item is "Question to discuss:", it will be styled with the third item to resemble the question box on the web client. Lines starting with "You:" and "Stranger:" will be coloured blue/red.

POST http://logs.omegle.com/generate

Form Data:

  • logs = [["blah",...]] (JSON table of the plaintext chat, split in lines)
  • randid = CHPZGFFW (Your random ID)
  • topics = ["asdf", "test", ...] (optional, the shared topics)
  • identdigests = blah,blah,blah (the most recent data from the identDigests event)
  • host = 1

Response: 302 Found, the Location header contains the log link.

@mynameisfashanu
Copy link

good guide!

@mitchelljeffery
Copy link

I'm not entirely sure how this works, POST http://[server].omegle.com/disconnect?id=central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh

Is the client ID encrypted or something, because everytime I call this I get fail. Same goes for events except it returns null.

@nucular
Copy link
Author

nucular commented Feb 27, 2015

Are you using the client ID you got from http://[server].omegle.com/start?
Also, sorry for the late reply, I didn't get any notification about your comment.

@tmerr
Copy link

tmerr commented Nov 4, 2015

I think the first field in the form data for http://logs.omegle.com/generate should be log, not logs

@GiedriusS
Copy link

/start may not have firstevents necessarily set to 1. If it's 0 or non-existant then statusInfo will not exist and you will have to call /status explicitly. Also, missing section about college mode.

@freehuntx
Copy link

the spid at start is the next rtmfp rendevouz server id i think.
Its needed for rtmfp p2p communication (video).

You get it, if you connect to the p2p rtmfp server (rtmfp://p2p.rtmfp.net) and provide a proper omegle password. (6fd539b64a3ca859d410f2f6-ac89c5a8742e)

@alexbinary
Copy link

The server list in Status does not include .omegle.com :

  "servers":  ["front6", "front1", "front13", "front8", "front9", "front15"]

@algj
Copy link

algj commented Dec 19, 2018

"recaptchaRequired", "recaptchaRejected" events are no longer working. Omegle now uses reCAPTCHA v2 (or v3, not quite sure). That means if you need to enter captcha(which you need to do every hour or two hours, not sure about this too), an event "error" will be sent.

@pwall2222
Copy link

https://gist.github.com/nucular/e19264af8d7fc8a26ece#send-webrtc-peer-description
This part gets the session created with WebRTC and then sends it with a form data containing
id = [clientID]
desc = [sessionInfo]
It will be a answer session if you alredy got the "rtcpeerdescription" event, and it will be a offer session if you only got the "rtccall" event

@pwall2222
Copy link

FlowChart:
image

@isaackogan
Copy link

What a sexy Gist! Thanks a bunch. Really been a help

@diVineProportion
Copy link

diVineProportion commented Aug 23, 2021

@pwall2222

where exactly does waw*.omegle.com (ex: waw2.omegle.com) fit into your chart? Not sure what the OPTIONS request does, but I'm interested in the POST that has the camera, num_frames_frame_delay and randid query parameters.

I keep getting banned when trying to use many can to stream my face while I play musical instruments or when attempting to use FaceRig.

It says it in one of the omegle information pages, but they send screencaps on first connection or all connections (not sure) to the moderators and I'm not sure if its the camera name that is causing the ban or the grabs from my connected camera. I thought about using a proxy to alter the requests but haven't got that far yet

image

@rosemash
Copy link

rosemash commented Oct 28, 2022

I figured out what "identDigests" is. It's 2 pairs of 128-bit hashes separated by commas (for a total of 4 hashes) where each pair is first a conversation participant's IP address, then a token unique to their browser session, in that order. The order of the pairs isn't guaranteed, so sometimes the first pair is you, and sometimes it's the stranger.

For example it seems like: [hash1],[hash2],[hash3],[hash4] is actually two pairs, [user1hash1],[user1hash2],[user2hash1],[user2hash2] where [userXhash1] is IP address and [userXhash2] is a browser session token.

@pwall2222
Copy link

@rosemash If thats true it would just make so much sense, I will be annotating that and playing with it, thanks!

@axelabbas
Copy link

@rosemash could you explain how did you find that please? Identifying the hash seems to be MD5 hash type, and when encoding my ip address it doesn't seem to match any of the hashes in identDigests

@rosemash
Copy link

rosemash commented Jan 16, 2023

@rosemash could you explain how did you find that please?

I inferred it by experimenting with different devices and looking at the behavior of the response. It still might not be true, but you can try for yourself, one of the hashes will always be the same as long as you're on the same network, and another will be the same unless you clear your browser's cookies/storage. When you connect to a new stranger, if they have a predictable opening, you can see the same behavior in their pair of hashes.

Identifying the hash seems to be MD5 hash type, and when encoding my ip address it doesn't seem to match any of the hashes in identDigests

It's almost definitely salted, there is no way to know what algorithm is being used.

@axelabbas
Copy link

@rosemash Oh I see, thanks a lot!

@Kyeya
Copy link

Kyeya commented Jan 23, 2023

@rosemash @axelabbas

For example it seems like: [hash1],[hash2],[hash3],[hash4] is actually two pairs, [user1hash1],[user1hash2],[user2hash1],[user2hash2] where [userXhash1] is IP address and [userXhash2] is a browser session token.

what you are calling userXhash2 is a hash of the randid passed to the start url, this will be some sort of hash of the ID you pass if it is a valid randid, anything else results in a default '2ac2f44c3ea3b8578fe95311b141a0b4' hash

userXhash1 is definitely related to the network you are on but if you connect to someone on the same network they will both have different hashes, userXhash2 will always be the same even if the other stranger has the same randid

you also now need to provide a 'cc' param to the start request which is the returned value from a post request to the "check" endpoint using one of the antinude servers subdomains you receive from querying the status endpoint

@axelabbas
Copy link

Omegle also disallows connection to the same stranger again after disconnecting for some time, using the userXhash2 (randId hash), So to meet the same stranger twice you'll have to change your randid value in the Start endpoint, and it'll allow it.

@bigwhitedog1
Copy link

how would I go about bypassing the omegle ban with this? Is there a way I can run javascript through console to unban myself? I'm new to coding so I have no idea.

@axelabbas
Copy link

@bigwhitedog1 you can't really do that.

@lppedd
Copy link

lppedd commented Sep 30, 2023

Thanks for the gist! And thanks everyone for the additional comments.
I've just used it to document my Kotlin implementation.
https://github.com/lppedd/komeglem

I'm missing the spyee and spyer modes, so if somebody wants to open PRs, they're welcomed.
Edit: seems they got removed lol

@Kyeya
Copy link

Kyeya commented Sep 30, 2023

@lppedd was just about to comment that they were disabled a few years ago

@lppedd
Copy link

lppedd commented Sep 30, 2023

@Kyeya yup read about it. I had left the implementation incomplete in 2021, and they got removed at the same time.

Anyway, it would be nice to have a mobile/desktop client with features like auto-skip, filters, censoring, etc. Currently, all the solutions involve injecting scripts into the webpage, which is still subpar.

@pwall2222
Copy link

pwall2222 commented Sep 30, 2023

@lppedd

Currently, all the solutions involve injecting scripts into the webpage, which is still subpar.

My project replaces the webpage entirely though and I don't think it'd be that hard to port to native, it's in typescript.
https://github.com/pwall2222/omclient
(also it's broken but just bcs /start params need to be updated)

@lppedd
Copy link

lppedd commented Oct 1, 2023

@pwall2222 thanks! Looks like you also fiddle with WebRTC, which is something I haven't looked at yet, since running it on a desktop app doesn't seem to be straightforward.

I'll try to give Compose Multiplatform a shot.

@pg-bug
Copy link

pg-bug commented Aug 29, 2024

How about reverse-engineering Ome.tv script. It bans everything that's not a face, any way around it?

@kamerali-chat
Copy link

Can you do the same for the Omegla.Chat site?

@djkapilesh
Copy link

does anyone have the source code or something similar of that type?

@djkapilesh
Copy link

i would like to learn more about webrtc and how omegle worked. and make a similar app to the above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment