Skip to content

Using Your Own Bee Node

By default Swarm ID talks to the public gateway at https://api.gateway.ethswarm.org/. To use a node you run yourself, open the settings menu in the identity site, choose Network settings, and put your node’s API URL in Bee address. An application that embeds the identity site and runs the node itself can write that setting directly; Storage Layout has the key and the shape.

One thing has to be configured on the node itself: CORS. Requests reach Bee from a browser, and a node that does not allow the origin they come from rejects every one of them.

Why the iframe’s origin is the one that matters

Section titled “Why the iframe’s origin is the one that matters”

Swarm ID never hands your app a Bee URL to fetch from. When your app calls uploadData(), the call is posted to the hidden iframe served from the identity site’s origin, and the iframe makes the HTTP request to Bee. The browser therefore sends Origin: <identity site origin> — your app’s own origin never appears on a request to Bee at all.

So the origin to allow is the identity site’s, not your app’s. This is the part that is easy to get backwards: allowing https://my-app.example and nothing else leaves every upload and download blocked, no matter how many apps you add to the list.

The identity site also talks to Bee first-party — when you manage drives on it directly — but that is the same origin, so a single entry covers both paths.

In bee.yaml:

cors-allowed-origins:
- https://swarm-id.snaha.net
- https://swarm.snaha.net
- http://localhost:5500

The same setting is available as the BEE_CORS_ALLOWED_ORIGINS environment variable or the --cors-allowed-origins flag. Bee allows no origins at all by default, so a node you start yourself rejects browser requests until this is set. Restart the node after changing it.

List only the identity sites you actually use:

Identity site Origin to allow
Production https://swarm-id.snaha.net
GitHub Pages build (/id/) https://swarm.snaha.net
Local development (pnpm dev) http://localhost:5500

Entries are origins — scheme, host and port, with no path and no trailing slash. That is why the GitHub Pages entry is the bare host: the identity site is served under /id/, but a path is not part of an origin, so one entry also covers the per-PR previews under /pr-N/id/.

http://localhost:5500 is the identity site’s dev server, not the demo’s — the demo runs on port 3500 and, as above, never talks to Bee itself. If you serve the identity site from a domain of your own (see the SSH tunnel setup), add that origin instead.

A CORS rejection looks like a broken node rather than a misconfigured one. Uploads and downloads fail, the browser console reports the request as blocked by CORS policy, and the request shows up in the network tab with no usable response. Meanwhile curl against the very same URL succeeds — curl sends no Origin header, so nothing is checked. If the node answers your terminal but not the browser, this setting is the first thing to look at.

bee start --dev runs a node with no network, chain or postage, for trying the API. It serves only deferred uploads: a direct upload (deferred: false, the client’s default) is never answered and fails as Request timeout after 30000ms, which says nothing about the mode. Ask the node with getNodeInfo() and set deferred from beeMode === 'dev', the way the demo does. Neither the local cluster nor the public gateway is in dev mode.

The local Bee cluster started by pnpm dev:cluster:start already sets BEE_CORS_ALLOWED_ORIGINS: "*" on every node, so http://localhost:1633 works from the identity site with nothing further to configure. Only a node you run by hand needs the setting above.

A subsidised gateway is fetched by the same iframe, so it needs the same entry in its CORS configuration — the identity site’s origin, not the origins of the apps it serves.