npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opaque-fetch

v1.0.1

Published

Perform fetch requests from an opaque origin using a sandboxed iframe.

Readme

opaque-fetch

Perform fetch() requests from an opaque origin using a sandboxed iframe.

opaqueFetch() provides a fetch-like API while moving the actual request into a sandboxed browsing context with an opaque origin.

import { opaqueFetch } from 'opaque-fetch/index.js'

const response = await opaqueFetch('https://httpbin.org/get')

console.log(response.status)
console.log(await response.text())

Why?

A normal fetch() is performed from the origin of the document that calls it.

https://my-site.example
        │
        │ fetch()
        ▼
https://httpbin.org

Sometimes you want the request to originate from a separate, opaque origin instead.

opaqueFetch() use a sandboxed iframe without allow-same-origin:

<iframe sandbox="allow-scripts">

The document inside the iframe therefore receives an opaque origin.

When serialized by the browser, this origin is represented as:

null

The actual request becomes:

sandboxed iframe
origin: null
       │
       │ fetch()
       ▼
https://httpbin.org

How it works

The implementation consists entirely of standard browser APIs.

  1. A hidden sandboxed iframe is created.
  2. The iframe runs a small ES module-compatible script through srcdoc.
  3. The iframe receives fetch parameters through postMessage().
  4. The iframe performs the request using its own fetch().
  5. The response body is transferred back through a MessageChannel.
  6. opaqueFetch() reconstructs and returns a normal Response.

No proxy server or external service is involved.

API

opaqueFetch(url, options?)

const response = await opaqueFetch(url, options)

The API intentionally follows the standard Fetch API.

const response = await opaqueFetch(
  'https://httpbin.org/post',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      hello: 'world'
    })
  }
)

Return value

Returns a standard:

Promise<Response>

For example:

const response = await opaqueFetch(url)

if (!response.ok) {
  throw new Error(`${response.status} ${response.statusText}`)
}

const data = await response.json()

Request bodies

opaqueFetch() supports normal Fetch API request bodies as well as transferable streams and serialized browser types.

ReadableStream

Readable streams are transferred directly to the sandboxed iframe:

const response = await opaqueFetch(url, {
  method: 'POST',
  body: stream
})

FormData and URLSearchParams

FormData and URLSearchParams is serialized before crossing the iframe boundary and reconstructed inside the iframe:

const form = new FormData()

form.append('name', 'Alice')
form.append('message', 'Hello')

const response = await opaqueFetch(url, {
  method: 'POST',
  body: form
})

Response streaming

The response body is transferred from the iframe instead of being fully buffered first.

This allows the returned Response to retain a streaming body:

const response = await opaqueFetch(url)

for await (const chunk of response.body) {
  // Process Uint8Array chunk
  console.log(chunk)
}

Normal Response methods are available:

await response.text()
await response.json()
await response.arrayBuffer()
await response.blob()

Origin

The sandbox intentionally omits allow-same-origin:

<iframe sandbox="allow-scripts">

This causes the iframe document to have an opaque origin.

The browser serializes this origin as:

null

Consequently, requests made from the iframe are not associated with the origin of the parent document.

This is fundamentally different from attempting to set an Origin header manually. Origin is a browser-controlled request header and cannot simply be overridden by application JavaScript.

Referrer

Because the request originates from the sandboxed document rather than the parent document, the parent page's URL is not used as the request's normal document referrer.

This makes opaqueFetch() useful when the request should be decoupled from the page that initiated it.

CORS

The request still follows the browser's normal security model.

An opaque origin does not bypass CORS.

For example, a server may receive:

Origin: null

and can explicitly allow that origin:

Access-Control-Allow-Origin: null

If the server does not permit the request, the browser will still enforce CORS.

Credentials

Credentials follow the normal Fetch API rules.

If credentials should not be included, specify:

const response = await opaqueFetch(url, {
  credentials: 'omit'
})

The opaque origin itself should not be treated as a replacement for explicit credential configuration.

No dependencies

The package has no runtime dependencies.

It does not depend on:

  • Node.js APIs
  • Deno APIs
  • Bun APIs
  • third-party libraries
  • polyfills
  • proxy servers
  • external services

It uses standard browser APIs only.

Browser APIs

The implementation relies on standard Web APIs including:

  • fetch()
  • Response
  • Headers
  • FormData
  • URLSearchParams
  • ReadableStream
  • MessageChannel
  • postMessage()
  • HTMLIFrameElement
  • sandboxed iframes

Design goals

  • Native — built entirely on browser APIs.
  • Dependency-free — no runtime dependencies.
  • Fetch-compatible — familiar fetch()-style API.
  • Streaming — request and response streams can be transferred.
  • Isolated — requests execute in a separate opaque-origin browsing context.
  • Small — the implementation is intentionally minimal.
  • Browser-first — no assumptions about Node.js, Deno, Bun, or another JavaScript runtime.

Limitations

opaqueFetch() is specifically an origin isolation primitive.

It does not provide a network proxy, VPN, Tor connection, or IP address masking. The request still travels directly from the browser to the destination server.

The browser's normal security policies still apply, including CORS, CSP, cookie policies, and other Fetch API restrictions.

License

MIT