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.
TODO:
- 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
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
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].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, // your IP was banned, see "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"
]
}
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].omegle.com/start
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)
Spyer/Spyee
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)
Response
{
"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].omegle.com/events
Form Data
id = [clientID]
Response
[
// see below
["event", "argument 1", ...],
["event", "argument 1", "argument 2", ...],
// ...
]
["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 likelyYou both speak the same language.
)["recaptchaRequired", "ChALlEnGe"]
(see section "ReCAPTCHAs")["recaptchaRejected", "ChALlEnGe"]
["identDigests", "a,b,c"]
(probably only used for sharing logs)
["error", "blah!"]
(general error message)["connectionDied"]
(some technical error)["antinudeBanned"]
(see section "Getting b8")
["typing"]
(the stranger started typing)["stoppedTyping"]
(...stopped typing)["gotMessage", "blah"]
(...sent a message)["strangerDisconnected"]
(...decided to disconnect)
["question", "blah?"]
(the question you'll discuss with the stranger)
["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)
["icecandidate", "blah"]
(see section "Connecting to the WebRTC peer")["rtccall", "blah"]
(TODO)["rtcpeerdescription"]
(see section "Send WebRTC Peer description")
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 = [clientID]
Response
win
The server might detect clients that do not send these.
POST http://[server].omegle.com/typing
POST http://[server].omegle.com/stoppedtyping
Form Data
id = [clientID]
Response
win
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].omegle.com/stoplookingforcommonlikes
Form Data
id = [clientID]
Response
win
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].omegle.com/disconnect
Form Data
id = [clientID]
Response
win
TODO
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].omegle.com/icecandidate
Form Data
id = [clientID]
candidate = %7B...%7D
(url-encoded JSON representation of a candidate)candidate = ...
(multiple times)
Response
win
TODO
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
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 = [clientID]
challenge = [challenge]
response = [answer]
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.
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)
POST http://logs.omegle.com/generate
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 theidentDigests
event)host = 1
Response: 302 Found, the Location
header contains the log link in the format
http://logs.omegle.com/[id]
. The log image can be fetched from
http://l.omegle.com/[id].png
.
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.