Skip to content

Instantly share code, notes, and snippets.

Last active Oct 28, 2022
What would you like to do?
Omegle protocol reverse-engineering

Let's reverse-engineer Omegle. PROPERLY!

I could not find a proper, detailed (and up-to-date) reverse-engineerment of Omegle's text chat protocol on the internet, so here, have one made by analyzing the web app (web requests and source code).
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 POST body which do not have to be URI-encoded.


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

I hereby declare this document Public Domain. If you find it helpful for a project of yours, I only ask you to provide a link to it in your source so others interested can learn from it too.

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
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36

Note that the headers X-Requested-With and X-Request are deliberately removed from requests by the JavaScript.


Pro-Tip: Fetch this first and then use one of the servers/subs listed for future connections (you can just connect to the main server here). You should switch to another one if your current one is not listed anymore.

GET http://[server]

Query String

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


    "count": 20840, // connection count, people say it's faked
    "force_unmon": true, // your IP was banned, see "Getting b&"
    "antinudeservers": [
        "", "", ""
    "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": [
        "", "", "",
        "", "", "",
        "", "", ""


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 (answer a question) and ask = blah for spyer mode (ask a question).

POST http://[server]

Query String

  • rcs = 1
  • firstevents = 1 (if 0 or not given, the response will not contain a statusInfo)
  • m = 1 (imitate a mobile connection, shouldn't really matter)
  • randid = CHPZGFFW (this is really just a random string containing 2-9 and A-Z, but excluding I and O)
  • spid = (some kind of ID from Adobe Stratus, never used though)
  • group = unmon (optional, join the unmonitored section instead)
  • lang = en (optional, two-char language code)
  • topics = ["foo", "bar", ...] (in default mode only)


  • wantsspy = 1 (for spyee mode)
  • ask = blah? (for spyer mode)
  • cansavequestion = 1 (optional, in spyer mode only, allow Omegle to reuse your question)

Camera Chat

  • webrtc = 1 (for camera chat)
  • camera = (probably just a flag, was " " for me in camera chat)

College Chat

  • college = ? (optional, TODO)
  • college_auth = ? (optional, TODO)
  • any_college = 1 (optional, TODO)


    "events": [
        // see section "Events"
    "clientID": "central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh", // needed for all subsequent requests
    "statusInfo": {...} // see section "Status"


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]

Form Data

  • id = [clientID]


    // see below
    ["event", "argument 1", ...],
    ["event", "argument 1", "argument 2", ...],
    // ...

Status events

  • ["waiting"] (the server is searching for strangers)
  • ["connected"] (you can start sending messages now)
  • ["statusInfo", {...}] (see section "Status")
  • ["count", 20900] (update the connection/online count, never encountered this one but it's in the source)


  • ["commonLikes", ["foo", "bar", ...]] (the shared topics from the ones you've passed)
  • ["partnerCollege", "Foobar College"] (chat partner goes to this college)
  • ["serverMessage", "blah"] (most likely You both speak the same language.)
  • ["recaptchaRequired", "ChALlEnGe"] (see section "ReCAPTCHAs")
  • ["recaptchaRejected", "ChALlEnGe"]
  • ["identDigests", "a,b,c"] (probably only used for sharing logs)

Error events (disconnects you)

  • ["error", "blah!"] (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?"] (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)

In camera chat

  • ["icecandidate", "blah"] (see section "Connecting to the WebRTC peer")
  • ["rtccall", "blah"] (TODO)
  • ["rtcpeerdescription"] (see section "Send WebRTC Peer description")

Send messages

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

POST http://[server]

Form Data

  • msg = lol
  • id = [clientID]



Set your "typing" status

The server might detect clients that do not send these.

POST http://[server]
POST http://[server]

Form Data

  • id = [clientID]



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 the client sends this. Use it after some time to stop the running search, ignore the topics and continue with connecting.

POST http://[server]

Form Data

  • id = [clientID]



Disconnect from the current chat

Simple as that. Always use this to end sessions gracefully, unless another event already ended the session. This can also be used to disconnect both strangers in the spyer mode.

POST http://[server]

Form Data

  • id = [clientID]



Send WebRTC Peer description


Send WebRTC ICE candidates

This is what you should do when your RTCPeerConnection fires the onicecandidate event. Basically, the Omegle client stores all received candidates in a list and then sets a 300ms timeout for more candidates to get pushed onto the list after which it sends the list to the server and clears it.

POST http://[server]

Form Data

  • id = [clientID]
  • candidate = %7B...%7D (url-encoded JSON representation of a candidate)
  • candidate = ... (multiple times)



Connecting to the WebRTC peer



If you run into an recaptchaRequired event, you must prove that you are a human by fetching the captcha using the URL-encoded passed code from[challenge] and sending the answer like this. Note that I haven't tried this yet.

POST http://[server]

Form Data

  • id = [clientID]
  • challenge = [challenge]
  • response = [answer]

Getting b&

If you got an antinudeBanned event, the modarating system banned you from the monitored section for "bad behaviour". From now on, the server status object (see section "Status") will have force_unmon set to true. You can switch to the unmonitored section by passing group = unmon to /start. They won't give you this mercy if you got your IP banned by connecting too rapidly or advertising, but bans don't last forever anyway.

Sharing logs

To upload your logs to Omegles server, use this.
Pro-Tip: You can actually pass any arbitrary text as the log. It's a JSON-encoded list containing lists that contain the strings. Oh, and HTML injection doesn't work, I tried.

These are the triggers that add some formatting:

  • ["*"] (smaller, bold font, gray)
  • ["* disconnected"] (as above)
  • ["Question to discuss:", "*"] (blue question box)
  • ["Stranger:", "*"] (large font, first item is red)
  • ["Stranger 1:", "*"] (as above)
  • ["Stranger 2:", "*"] (large font, first item is blue)
  • ["You:", "*"] (as above)
  • ["*", "*"] (normal font, first item is bold)


Form Data

  • log = [["You:", "blah"], ...] (JSON table of the plaintext chat, split in lines)
  • randid = CHPZGFFW (Your random ID)
  • topics = ["foo", "bar", ...] (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 in the format[id]. The log image can be fetched from[id].png.

Copy link

mynameisfashanu commented Dec 26, 2014

good guide!

Copy link

Murchurl commented Jan 15, 2015

I'm not entirely sure how this works, POST http://[server]

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

Copy link

nucular commented Feb 27, 2015

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

Copy link

tmerr commented Nov 4, 2015

I think the first field in the form data for should be log, not logs

Copy link

GiedriusS commented Dec 20, 2015

/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.

Copy link

freehuntx commented Dec 22, 2015

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:// and provide a proper omegle password. (6fd539b64a3ca859d410f2f6-ac89c5a8742e)

Copy link

alexbinary commented Oct 6, 2017

The server list in Status does not include :

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

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.

Copy link

pwall2222 commented Feb 6, 2021
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

Copy link

pwall2222 commented Feb 6, 2021


Copy link

isaackogan commented Jun 30, 2021

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

Copy link

diVineProportion commented Aug 23, 2021


where exactly does waw* (ex: 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


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.

Copy link

pwall2222 commented Oct 28, 2022

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

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