The build
StrangR is a React single-page app. The document on Vercel is a root div and two asset tags. The script checked here is /assets/index-BxW-GTpl.js (799,651 bytes) and the stylesheet is /assets/index-CNvNqFzM.css (100,766 bytes). A request for the source map returned 403. No public repository turned up for this host or for the string "StrangR Protection."
Two hosts
- Page: https://strangr93.vercel.app/, served by Vercel. The response headers on 3 October 2026 included
server: Vercelandlast-modified: Sat, 03 Oct 2026 18:12:29 GMT. - API and websocket:
https://strangr-90k3.onrender.comandwss://strangr-90k3.onrender.com/ws. Responses includedx-render-origin-server: Renderand Cloudflarecf-rayheaders. The hostname is Render's default project URL.
Vercel Web Analytics is mounted at the root of the React tree. The bundle loads https://va.vercel-scripts.com/v1/script.debug.js and sends a pageview. Chat text goes to Render. Pageviews go to Vercel. The homepage does not mention either.
The viewport meta tag sets maximum-scale=1.0 and user-scalable=no, so the page asks mobile browsers to disable pinch zoom.
The account you did not fill in
Choosing a gender, or skipping, runs this from the client. t is an optional location string. Gender for "skip" is a single space.
POST /api/auth/initialize
{"gender":" ","location":"..."}
A real response on 3 October 2026, with the username shortened to its shape:
{
"user": {
"username": "<10 hex characters>",
"name": "Shrek",
"gender": " ",
"age": null,
"country": null,
"location": "",
"topic": null,
"points": 0
},
"is_new_user": true
}
Other display names handed out the same day, to sessions that sent no name, included Tom, Joker, Batman, Sailor Moon, and Wolverine. The name is a profile field you can edit later. Until you do, that is the name other people see. GET /api/users/me without the cookie returns 401 {"error":"Unauthorized"}. With the cookie it returns the same user fields and nothing else: no email column in the JSON.
The cookie is strangr_session, a UUID, HttpOnly, Secure, SameSite=None, Max-Age=2592000. Cross-site cookies are how a page on vercel.app stays logged into an API on onrender.com. It is also a 30-day id for a product whose checklist says no account is required.
Password is marked "optional" in Settings. The help text says "Set a password to secure your account and log in from other devices." Login is username plus password. If you never set one, the cookie is the login.
The logout button is labeled "Log out of your account on this device." The handler calls POST /api/auth/logout, then localStorage.clear() and sessionStorage.clear() for the whole origin, then calls initialize again, saves the new user, and navigates to /login. Leaving mints the next account.
What the room receives
On user_joined, the client keeps:
username, name, age, gender, country, topic
The subtitle function pushes age, then gender (Male, Female, or nothing if the value is a space), then country, joined with middle dots. If that list is empty it prints "Anonymous." Topic chips offered in Settings are Gaming, Coding, Music, Cricket, Anime, Movies, Tech, Books, Art, and Travel, and the topic string is capped at 300 characters. Country and location are separate free-text fields.
Gender at the door is two buttons, Male and Female, plus "Prefer not to say (Skip)." In Settings the third button is labeled "Private." Both skip values are the same space character.
Rooms
| Room | How you get there | Copy in the client |
|---|---|---|
1-on-1 match. Room ids in this mode start with m_. |
The client sends {type:"enter_random"} on the websocket. |
"You're connected!" Composer footer: "Encrypted in transit · Anonymous." |
#general and any other /r/:room_id that is not a match id and not a private id. |
Nav link to /r/general. The homepage also says you can "join open general lounge." |
"This is the #… open public room where anyone can join and chat." Footer: "Public channel · Be kind." |
Friend room. Ids start with prv_. |
A private-room invite the other person accepts. | "Only authorized friends can join this conversation." Footer: "Private conversation · Friends only." |
Matching copy on the wait screen cycles through "Scanning for an active stranger...", "Matching you with someone ready to chat...", "Widening search to find someone online...", and "Still looking." The client does not show a live count of people online.
Messages
Text events are JSON objects, for example send_message with content, message_id, and optional reply and mention fields. Typing notifications are typing_start and typing_stop. The server can refuse a send with RATE_LIMITED ("Please wait before sending another message."), PAYLOAD_TOO_LARGE, or INVALID_MEDIA.
Images and voice notes use a binary frame: a type byte, a JSON header, then the raw bytes. The client understands type 2 as an image (default MIME image/webp) and type 4 as audio (default audio/webm). The server has to understand that layout to relay it. That is the opposite of a sealed end-to-end blob.
There is no /api/messages in the client. History shown in a room is whatever the websocket delivers during the connection. Reports are the path that clearly writes message text into a database: the moderator screen says so.
Points
The user record has a points number. The websocket event points_updated overwrites it. The client blocks the image picker and the microphone until the number is at least 930, and shows:
"You need at least 930 points before you can send images or voice notes. Keep chatting to earn more points."
The formula is not in the client. A new account is at 0, so text works and pictures do not. The gate is a grind, and it is not a review of the picture.
Reports and bans
Report categories in the bundle:
- Harassment / Bullying: "Bullying, threats, or intimidation."
- Inappropriate Media: "Unsolicited sexual or explicit content."
- Hate Speech: "Discrimination or targeted hate."
- Spam / Scams: "Commercial links, bots, or phishing."
- Underage Content: "Minors or underage behavior."
- Other: "Violates community guidelines."
The underage category is an admission that the product expects the case. The homepage badge still says 18+ Only, and the age box still starts at 13.
After a report, the dialog says "Moderation will review this log immediately." The dashboard behind /moderation says "Review user-submitted reports, resolve safety violations, and enforce bans." A non-moderator sees "Moderator privileges are required." GET /api/moderation/status with no cookie returned {"is_moderator":false} and HTTP 200. GET /api/moderation/reports with no cookie returned 401. The ban form asks for a username and a "Reason for ban (recorded in audit log)."
Friends can be poked. The client calls that "Poke / Whisper a Friend" and can open a private room from the friends list.
The guidelines link
The only legal sentence on the homepage is "By chatting, you agree to our Community Guidelines. Be respectful and protect your personal data." The link target is /terms-and-conditions. That path is not a route. Searching the bundle for a privacy policy, a retention period, or an operator name returns nothing. There is no contact address.