x.rt.ht, px.rt.ht and fp.cf.rt.ht

Three helper hosts fetch another URL for you, and they differ in what they forward and what they add. x.rt.ht takes the target as a base64 path and returns the answer unchanged. px.rt.ht rewrites request headers and forwards everything else. fp.cf.rt.ht adds CORS headers and forwards only a short list of safe request headers, so it does not leak the visitor.

Syntax

plain
https://x.rt.ht/<base64 of the URL>
https://px.rt.ht/?~=<URL>
https://via.elefunc.net/?~=<URL>
https://fp.cf.rt.ht/<host>/<path>?<query>
https://fp.cf.rt.ht/https://<host>/<path>?<query>
HostThe target is written asCORS headers addedRedirectsStatus
x.rt.htA base64 path.None.Followed.Experimental as a direct API
px.rt.ht, via.elefunc.netThe ~ query parameter.The request's Origin, or *.Not followed. The upstream Location comes back as it is.Experimental
fp.cf.rt.htThe path.The request's Origin, or *, and * for methods, headers and exposed headers.Not followed. Location is rewritten to go back through the proxy.Available

Parameters

x.rt.ht Experimental

<base64>

The path is the target URL, base64 encoded with the standard alphabet. The host decodes it with atob, and then as UTF-8. A missing = padding is accepted.

?u

Returns a JSON report of the fetch instead of the target: { b, i, o, "=" }. b is the base64 path, i the decoded URL, o the final URL after redirects, and "=" says whether i and o are equal.

?<base64>

A query parameter whose name equals the base64 path answers { b, i } without fetching. Write the = of a padded path as %3D in the query, or leave the padding off the path, and write a + as %2B. A / needs no escaping.

px.rt.ht and via.elefunc.net Experimental

via.elefunc.net runs the same proxy on another zone.

~=<URL>

The target. Without ~, the proxy answers 200 with an empty body.

-=<name>

Deletes a request header. You can repeat it. Without any -, the proxy deletes referer, origin and te. Any - replaces that list.

~<name>=<value>

Sets a request header.

+<name>=<value>

Appends a value to a request header. Write %2B for the + in a raw query, or build the query with URLSearchParams.

The proxy deletes first, then appends, then sets. It sends the request on with its method, its body and all remaining headers.

Warning: The remaining headers include the cookies that your browser sent to px.rt.ht and Cloudflare's visitor headers: cf-connecting-ip, cf-ipcity, cf-iplatitude, cf-iplongitude, cf-postal-code, cf-region and cf-timezone. The target sees them. Prefer fp.cf.rt.ht unless you need to control the headers.

fp.cf.rt.ht

/<host>/<path>?<query>

The target is https://<host>/<path>?<query>.

/https://<host>/<path>?<query>

A full URL after the slash, with https:// or http://.

The method and the body are forwarded. Of the request headers, only these are forwarded: accept, content-type, range, if-range, if-match, if-none-match, if-modified-since, if-unmodified-since and user-agent. Origin, Referer, cookies, sec-* headers, client hints and Cloudflare's visitor location headers never leave. Cloudflare itself adds cf-ray, cf-visitor, cdn-loop, cf-ew-via and accept-encoding to the outgoing request, and neither carries your IP address or location. WebPDF uses fp.cf.rt.ht for certificate revocation checks and AIA downloads.

Response

x.rt.ht

Deployments use x.rt.ht for social cards. For user agents that start with Twitter or Xbot, a deployed page gets <meta name=twitter:image content="https://x.rt.ht/<base64 of the og:image URL>">, unless the page writes its own og:image or twitter:image in its first 8192 characters. See Social previews and screenshots.

px.rt.ht

fp.cf.rt.ht

Examples

Read a page that has no CORS headers

The target goes after the proxy's slash, and only safe headers are forwarded.

html
<pre id=feed></pre>
<script type=module>
  const via = url => `https://fp.cf.rt.ht/${url}`;
  feed.textContent = await fetch(via('https://example.com/')).then(r => r.text());
</script>

Rewrite request headers on the way out Experimental

~ names the target, ~accept sets accept, +x-demo appends x-demo, and - deletes user-agent, which replaces the default list. The request is a simple GET without custom headers, so it needs no preflight.

html
<pre id=seen></pre>
<script type=module>
  const q = new URLSearchParams({ '~': 'https://httpbin.org/headers', '~accept': 'application/json', '+x-demo': '1', '-': 'user-agent' });
  seen.textContent = await fetch(`https://px.rt.ht/?${q}`).then(r => r.text());
</script>

Build an x.rt.ht URL and its report Experimental

The image uses the base64 path, and the link opens the ?u report. btoa works for ASCII URLs only. x.rt.ht sends no CORS headers, so use it as an image or link target, not with fetch() from a deployed page.

html
<img id=card alt="RTCode.io logo fetched through x.rt.ht" height=64>
<a id=report target=_x>What x.rt.ht fetched</a>
<script>
  const b = btoa('https://rtcode.io/.svg').replace(/=+$/, '');
  card.src = `https://x.rt.ht/${b}`;
  report.href = `https://x.rt.ht/${b}?u`;
</script>

CORS and limits

Status

fp.cf.rt.ht is available. px.rt.ht and via.elefunc.net are Experimental, and so is calling x.rt.ht yourself. Its role in twitter:image tags is available. Behavior was checked on 2026-10-04.

See also