An HTTP response playground for browser / web-security testing. Build any response from URL params, save it, capture incoming requests, or craft byte-exact malformed responses.
Every URL on the site can serve a custom HTTP response. The response is described entirely in the query string — no signup, no save required. Use this when you want a one-off fixture: a 302 to your attacker, an HTML page with a specific CSP, a JSON endpoint that returns slowly.
https://xss.cool/?status=302&redirect=https://example.com&h[X-Frame-Options]=DENY
This serves a 302 to example.com with an extra X-Frame-Options: DENY header. Tack &dryrun=1 on the end to see exactly what would be sent without firing the response.
| Param | What it does |
|---|---|
status | Status code, 200–599 (default 200). Aliases: statuscode, code. |
delay | Delay the response by N ms (max 300000). |
redirect | Sets Location. Alias: redir. Pair with status=302. |
html / script / js / text / json / body | Body. First defined wins (in this order). All sent raw and pick the matching Content-Type — except script, which wraps in <script>…</script>. html and body are functionally identical (both raw, text/html); body just sits at the end of the precedence chain. |
h[Header-Name]=value | Custom header (qs-style nesting). Repeat the same key for multiple values. Aliases: header[…], headers[…]. |
dryrun=1 | Don't send the response — return JSON describing what would have been sent. |
The home page is a live editor that builds the URL above as you type. The body editor (Monaco) handles HTML / JS / JSON with syntax highlighting; right-click for an encode/decode menu (URL-encode, base64, etc).
Switch between Body, Headers, and Captures with the tabs (⌘1 / ⌘2 / ⌘3; ? for the full shortcut list). The "Domain switcher" in the topbar picks which host the generated URLs target — important for cross-origin tests (see below).
Click Save in the topbar and you get back two URLs for the same saved state:
/s/<id> — the replay URL. Renders the saved response byte-for-byte every time. Hand this to a third party / writeup / test target./e/<id> — the editor URL. Opens the editor pre-filled with the saved state, ready to tweak. Hand this to a collaborator.Same id, both views. The "Mine" menu in the topbar lists everything you've saved with quick actions to copy the replay URL, open in the editor, submit to the public payload library, rename, or delete.
For raw mode the replay URL points at raw.<domain> (see below) and there is no editor view — /e/<id> returns 400 for raw shares.
The Captures tab creates a webhook-sink endpoint at /c/<id>. Anything that hits it (any method, any subpath) is logged with method, path, headers, body (1 MB cap), and source IP. The panel streams new requests live via Server-Sent Events.
Use it for exfil targets, oracle pings, or any "did this fire?" check. Captures expire after 7 days.
The Body editor toolbar has an "Insert capture URL" button that pastes a fresh capture URL at your cursor — handy when crafting an XSS payload that needs to call home.
The platform serves multiple host domains (xss.cool, marquee.lol, …) from one backend. Every share and capture is reachable on all of them. To set up a cross-origin PoC without standing up your own attacker server:
https://xss.cool/s/<id>.https://marquee.lol/?html=….frame-ancestors) even though they share a backend.Sometimes you need an HTTP response the standard server would refuse to emit: a lying Content-Length, mixed CRLF, an unparseable status line. Toggle Raw in the editor, build the bytes, save it, and replay over the raw.<domain> subdomain — e.g. https://raw.xss.cool/?raw=<id>. That subdomain is a TCP+TLS passthrough route: the bytes you save are exactly the bytes the client sees.
For machine consumers (LLMs, scripts, integrations) the canonical schema lives at /api/schema.json (versioned JSON) and the terse summary at /llms.txt.
| Endpoint | Notes |
|---|---|
POST /api/shares | Body: { mode: "sane"|"raw", state, name? }. Returns { id, name, mode, replayUrl, editorUrl?, curlExample, jsExample }. |
GET /api/shares/mine | Your own shares (owner cookie). |
GET /api/shares/:id | One share's JSON, owner-gated. Returns the stored state. |
PATCH /api/shares/:id | Rename / mark submitted. Body: { name?: string|null, submittedPayloadId?: string|null }. |
DELETE /api/shares/:id | Owner-gated. |
POST /api/captures | Returns { id, captureUrl, streamUrl, expiresAt }. |
ANY /c/:id (and subpaths) | Capture sink. Body capped at 1 MB. |
GET /c/:id/stream | SSE feed of incoming requests. |
GET /api/payloads | Public community-curated payload templates. |
GET /api/config | { domains: string[] } — the public hosts this deployment serves. |
xsscool_owner) lets you list / delete your captures and shares.For a one-screen reference suitable for LLMs, see /llms.txt.