How iceFetch works

iceFetch reads the ICE candidates a Minecraft Bedrock server advertises over NetherNet — the WebRTC-based transport that replaced RakNet. It does this purely at the signaling layer, from a Cloudflare Worker.

What is NetherNet?

Modern Minecraft Bedrock Dedicated Server (BDS) can run with transport=nethernet instead of the classic RakNet UDP protocol. NetherNet is built on WebRTC: the actual game data flows over an encrypted SCTP-over-DTLS data channel, and connections are negotiated with SDP offers/answers and ICE candidates, exactly like a browser peer connection.

The negotiation (signaling) happens over a small HTTP server that BDS opens on its TCP port (e.g. 19132). A client discovers the server, then performs one HTTP request to exchange session descriptions.

The signaling endpoint, as used by real clients:
GET  /v1/join                 → { name, protocol, version, players, maxPlayers, … }
POST /v1/join/{networkId}     → an SDP answer (Content-Type: application/sdp)

What are ICE candidates?

An ICE candidate is one possible network address a peer can be reached at — an IP, a port, and a type (host for a local/interface address, srflx for a NAT-reflexive public address, relay for a TURN relay). During negotiation each side lists its candidates in the SDP; the two peers then probe the pairs to find a route that works.

When you send an offer to a NetherNet server, its SDP answer contains the candidates the server is reachable at — the real UDP endpoints its game traffic uses. That is what iceFetch extracts and shows you.

What iceFetch actually does

  1. It builds a valid Minecraft identity assertion (an a=identity SDP attribute) backed by a real Microsoft/Xbox account, because BDS rejects offers without one.
  2. It hand-crafts an SDP offer with no ICE candidates of its own — it only needs to ask, not to connect.
  3. It sends that offer to POST /v1/join/{networkId} over a raw TCP (or TLS) connection from a Cloudflare Worker.
  4. It parses the SDP answer and returns the server's ICE candidates as JSON.

Why it cannot "join" a server

A Cloudflare Worker has no UDP, no DTLS, and no WebRTC stack. iceFetch can complete the signaling handshake, but never the media handshake — so it can read a server's candidates, but it can never open a game session. It is a diagnostic / reconnaissance tool, not a client.

Using the JSON API

EndpointWhat it returns
GET /api/info?host=&port=the server's /v1/join metadata
POST /api/offer{ candidates[], answer, iceUfrag, … }
curl -X POST https://icefetch.tools.kt04.com/api/offer \
  -H 'content-type: application/json' \
  -d '{"host":"play.example.net","port":19132}'

Body fields: host (required), port (default 19132), networkId (optional decimal uint64), tls (auto-detected — set true/false to force), fresh (bypass cache).

Rate limits & caching

FAQ

Does this work on any Bedrock server?

Only on servers running NetherNet (BDS 1.21.60+ with transport=nethernet, or networks that front their servers with it). Pure RakNet (UDP-only) servers have no HTTP signaling endpoint to query.

Why did I get 0 candidates?

A 200 response with an empty candidate list means the server's UDP port pool is currently exhausted — too many pending signaling sessions. It recovers after those sessions time out.

Is the returned IP the server's "real" address?

The candidates are the endpoints the server itself advertises for gameplay. For large networks these are often the backend game-node IPs behind a proxied hostname.

About the operator

iceFetch is an independent, ad-supported utility. For any enquiry, contact kaito@kt04.com.

ToolLearnArticlesPrivacyTerms · iceFetch is not affiliated with Mojang or Microsoft.