Back

Blog details

How the IPFS Service Worker Gateway Works (inbrowser.link)

AIOZ Network
6 min readNovember 11, 2026
aioz-pin
AIOZ Pin cover: How the IPFS Service Worker Gateway Works

The IPFS service worker gateway is an IPFS gateway that runs inside your browser instead of on a server. At inbrowser.link, a tiny installer page registers a service worker that finds providers, fetches blocks, checks each one against its CID and builds the page locally.

TL;DR:

  • inbrowser.link is the hosted IPFS Service Worker Gateway, built on Helia and @helia/verified-fetch
  • Each CID gets its own subdomain, browser origin and service worker
  • Providers come from delegated routing; blocks come from peers, HTTPS providers or the fallback trustless-gateway.net
  • Your browser checks every block against the CID, so the server never vouches for the bytes
  • Only browser navigation benefits; apps and servers need verified-fetch or their own node

Browser visits to ipfs.io and dweb.link have gone to inbrowser.link since May 2026. Our post on the ipfs.io gateway changes covers that news; this one covers what your visitors' browsers do with the URL.

What is the IPFS service worker gateway?

A service worker is a script your browser runs between a page and the network. Once it is registered for an origin, it can intercept that origin's requests and answer them itself. The service worker gateway uses that hook to implement the IPFS HTTP gateway specs in the browser.

Per Shipyard's 2024 update, the gateway depends on Verified Fetch, which depends on Helia, the JavaScript implementation of IPFS, which depends on js-libp2p. inbrowser.link serves tagged releases, the latest being v3.5.1 from October 15, 2026, while inbrowser.dev serves staging builds. The README calls inbrowser.link a drop-in replacement for dweb.link.

The goal is no single HTTP backend between you and the content. Per the README, the host ships only static HTML and JS under 10 MiB, and the fetching, hash checks and reassembly happen on your machine.

Diagram of how inbrowser.link loads a CID in six steps: a path URL gets a 301 redirect to a CID subdomain, the subdomain serves a small installer page, a service worker registers with scope slash, it finds providers through delegated routing at delegated-ipfs.dev, fetches blocks from peers over Secure WebSockets or WebTransport, HTTPS trustless providers or the fallback trustless-gateway.net, then verifies each block against its CID and returns a Response

Traced from the source code, a first visit runs like this:

  1. Path to subdomain. A path URL such as inbrowser.link/ipfs/{cid} gets a permanent redirect to {cid}.ipfs.inbrowser.link. Path gateway support was removed in v3.
  2. Installer page. That hostname returns the same small HTML bootstrap for every URL. A comment in its source puts it plainly: "Your browser fetches and verifies this content, not this server."
  3. Registration. The bootstrap registers /ipfs-sw-sw.js with scope /, so the service worker controls every path on that origin from then on.
  4. Routing. The service worker asks a delegated routing endpoint, delegated-ipfs.dev in the production config, which peers hold the CID. DNSLink names resolve over DNS-over-HTTPS at the same host.
  5. Retrieval. Blocks come from peers over Bitswap on Secure WebSockets or WebTransport, or from HTTPS trustless gateway providers. If none answer, the config falls back to trustless-gateway.net, with a 30-second timeout per block.
  6. Verification. Each block is hashed and compared with its CID, the same check that lets IPFS skip trusting the gateway. The service worker then rebuilds the file or directory listing and returns an ordinary Response.

We ran step 1 on October 29, 2026 at 05:51 UTC with a desktop Chrome user agent ($UA), because a bare curl got a Cloudflare 403 (headers trimmed):

$ curl -sI -A "$UA" -H "Accept: text/html" \
    https://inbrowser.link/ipfs/bafkreicafxt3zr4cshf7qteztjzl62ouxqrofu647e44wt7s2iaqjn7bra
HTTP/2 301
location: https://bafkreicafxt3zr4cshf7qteztjzl62ouxqrofu647e44wt7s2iaqjn7bra.ipfs.inbrowser.link/
cache-control: public, max-age=31536000, immutable

The redirect is cached for a year as immutable, since a CID's subdomain never changes.

Why does every CID get its own subdomain?

Browsers wall sites off by origin, so one origin's scripts, cookies and storage can't read another's. If every CID shared one hostname, a page from one CID could read what a page from another CID had stored. So the gateway runs only in subdomain mode, and inbrowser.link, like dweb.link, sits on the Public Suffix List, so browsers treat each CID subdomain as a separate site. Our guide to how an IPFS gateway resolves a request compares path and subdomain gateways.

Diagram showing two CID subdomains on inbrowser.link as separate origins, each with its own service worker, its own Cache API and IndexedDB storage, an installer and registration on the first visit and local answers on later visits, separated by an origin boundary, while both use the same network sources: delegated-ipfs.dev, peers and trustless-gateway.net

A service worker registration also belongs to one origin, so registration happens once per CID subdomain, not once per gateway. Your first visit to a new CID downloads the installer and registers a fresh service worker, and repeat visits are answered locally. The project's denylist notes confirm it from the server side, since the edge only sees a visitor's first request to each host.

Storage splits the same way. Blocks live in IndexedDB and responses in the Cache API, and browsers scope both to the origin, so a second CID starts with an empty cache. DNSLink sites follow the same rule: Shipyard's example loads blog.ipfs.tech from blog-ipfs-tech.ipns.inbrowser.link, using the record that DNSLink uses to point a domain at IPFS content.

Costs and limits of in-browser retrieval

The model trades server work for browser work, and a few limits follow. Native ipfs:// links are a separate topic, covered in which browsers support ipfs:// links.

  • The first load is slower. Shipyard calls it "an initial upfront cost of fetching and installing the Service Worker", and each new CID pays it again.
  • It only helps top-level navigation. A service worker handles requests from pages it controls, so an <img> tag on another site that points at inbrowser.link only gets the installer page back.
  • No WebRTC. WebRTC isn't available inside service workers, so peers need Secure WebSockets, WebTransport or HTTPS, or the fallback gateway does the fetching.
  • Someone must provide the CID. If no node announces your blocks, routing finds nobody and no gateway can load them.
  • Blocked CIDs stop at the edge. Hosts on the BadBits denylist get 410 Gone instead of the installer.

So the right tool depends on who requests the CID, as the IPFS docs split it:

Who requests the CIDWhat should handle itWhy
A person opening a link in a browserinbrowser.linkThe service worker verifies in that browser
Your web app's own fetch calls@helia/verified-fetchSame verification, no navigation needed
A server, script or mobile appYour own node or a gatewayNo browser, so no service worker

For your own app, the IPFS docs show the same library with the public routing and fallback endpoints swapped for yours (quoted, not run):

import { createVerifiedFetch } from '@helia/verified-fetch'

const verifiedFetch = await createVerifiedFetch({
  gateways: ['https://rainbow-gateway.example.net'],
  routers: ['https://someguy-routing.example.net']
})

const res = await verifiedFetch('ipfs://bafy.../path/to/file')

How AIOZ Pin handles it

A service worker gateway only reads, so it needs a provider that holds your blocks. AIOZ Pin covers that provider side. Our docs say pinned content "becomes available on the public IPFS network", where any IPFS node can fetch it by CID. Pinning a file takes one request, as the docs give it (not run):

curl --location --request POST 'https://api.aiozpin.network/api/pinning/' \
--header 'pinning_api_key: KEY' \
--header 'pinning_secret_key: SECRET' \
--form 'file=@"/test.png"'

Share the returned cid as an inbrowser.link URL for browsers, and serve apps and servers from our gateways: the public gateway for testing and very low volume, or premium gateways on 200+ edge-caching locations. On the free plan, premium gateways serve single files like images and video, not HTML or scripts.

What the docs don't cover yet: whether AIOZ Pin's nodes accept browser connections over Secure WebSockets or WebTransport, appear in delegated routing results, or answer trustless block requests. So you can't tell from the docs whether inbrowser.link pulls your blocks from AIOZ directly or through its fallback gateway.

Next step: pin your first file with the AIOZ Pin pinning API docs.

Frequently Asked Questions

Is inbrowser.link trustless?
For the content, yes, because your browser checks every block against the CID. You still run the gateway code that inbrowser.link serves, so your trust moves to that installer.

Why is the first visit to a CID slow?
Your browser must download the installer and register a service worker for that CID's subdomain before it fetches anything.

Does the service worker gateway work offline?
For pages you already visited, it can, because Shipyard says visited pages are cached in the Cache API.

How do I remove the service worker?
Add ?ipfs-sw-unregister=true to any URL it controls, and per the README it unregisters itself and tries to reload the open tabs.

Can I run my own service worker gateway?
Yes, it runs locally with npm install and npm start, but the developer notes warn against path-only deployments for anything with keys or wallets.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

IPFS Implementations Explained: Kubo, Helia, Boxo, Rainbow

IPFS implementations are the nodes and libraries that speak IPFS. See what Kubo, Helia, Boxo and Rainbow each do, how they fit together and which you need.

7 min readNovember 13, 2026
blog thumbnail

How the IPFS Service Worker Gateway Works (inbrowser.link)

The IPFS service worker gateway runs in your browser. See how inbrowser.link registers a service worker per CID, finds providers and verifies every block.

6 min readNovember 11, 2026
blog thumbnail

What Is MFS in IPFS? The Mutable File System Explained

IPFS MFS (the Mutable File System) lets you edit files by path while IPFS updates the CIDs. Learn the ipfs files commands and how MFS differs from pins.

6 min readNovember 09, 2026
blog thumbnail

What Is a Multiaddr? Peer IDs and Addresses in IPFS

A multiaddr is a network address that names every protocol it uses, like /ip4/.../tcp/4001/p2p/ and a peer ID. Learn to read one and how IPFS peer IDs work.

7 min readNovember 06, 2026
blog thumbnail

IPFS Bootstrap Nodes and How a New Node Finds Its Peers

IPFS bootstrap nodes are the first peers a new node dials to join the Amino DHT. See how Kubo uses them, who runs them after Shipyard, and how to edit the list.

6 min readNovember 04, 2026
blog thumbnail

ipfs.io Gateway Not Working? What Changed and Who Runs It

The ipfs.io gateway now returns HTTP 429 to scripts and servers and sends browsers to inbrowser.link. See who runs the public IPFS services and what to change.

6 min readNovember 02, 2026