> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket Debugging

> Find out why a Solana WebSocket connection to OrbitFlare is rejected, silent, or dropping: handshake errors, subscriptions that never fire, idle disconnects, and keepalive.

Most WebSocket problems fall into three groups: the connection is refused, it connects but nothing arrives, or it works for a while and then drops. Work out which one you have first.

## Start with a known-good subscription

`slotSubscribe` fires every slot, about five times a second, so it shows almost immediately whether the connection itself works. Install [wscat](https://github.com/websockets/wscat) with `npm install -g wscat`, then:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
wscat -c "wss://fra.rpc.orbitflare.com?api_key=$ORBITFLARE_LICENSE_KEY"
> {"jsonrpc":"2.0","id":1,"method":"slotSubscribe"}
```

A working connection replies with a subscription ID, then a stream of notifications:

```json theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
{"jsonrpc":"2.0","result":332807,"id":1}
{"jsonrpc":"2.0","method":"slotNotification","params":{"result":{"slot":459760339,"parent":459760338,"root":459760337},"subscription":332807}}
```

If this works and your own subscription does not, the problem is the subscription, not the connection. Skip to [Connected but no updates](#connected-but-no-updates).

## Connection refused

Authentication happens during the WebSocket handshake. When it fails, the server answers the upgrade request with a normal HTTP error and a JSON body instead of switching protocols. Many WebSocket libraries only report "unexpected server response: 403" and drop the body, so check the handshake with curl to see the real reason:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
curl -i --http1.1 \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  "https://fra.rpc.orbitflare.com/?api_key=$ORBITFLARE_LICENSE_KEY"
```

`HTTP/1.1 101 Switching Protocols` means authentication passed. Otherwise:

| Status | Body | Fix |
| - | - | - |
| `401` | `{"code":-32401,"message":"missing API key"}` | Add `?api_key=YOUR_LICENSE_KEY` to the URL. Browsers cannot set headers on a WebSocket, so the query parameter is the reliable option |
| `403` | `{"code":-32402,"message":"invalid API key"}` | The key is wrong or was regenerated. Copy it again from the dashboard |
| `403` | `{"code":-32404,"message":"IP not whitelisted"}` | This machine's IP, or this region, is not allowed on your license. Add the IP in the dashboard, or connect to a region your license includes |

Other things to check:

* **The host resolves.** WebSocket runs on the RPC hosts: `wss://{region}.rpc.orbitflare.com`. There is no `wss://mainnet.rpc...` or `wss://global.rpc...` host. See [Infrastructure](/infrastructure) for the list.
* **The URL uses `wss://`.** Passing an `https://` URL to a WebSocket client fails before the request reaches OrbitFlare.
* **TypeScript only:** `Cannot find package 'ws'` means the optional peer dependency is missing. Run `npm install ws`.

## Connected but no updates

The server confirms every subscription with a numeric ID. If you never get one, the request was rejected, and the reply says why:

```json theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Request: Invalid pubkey provided"},"id":1}
```

Log every message the server sends, not just notifications, while you debug. Errors arrive on the same socket and are easy to miss.

If the subscription was accepted but stays silent:

* **The account is not changing.** `accountSubscribe` only fires when the account's data or lamports change. Test with an account you know is busy, such as `SysvarC1ock11111111111111111111111111111111`, which changes every slot.
* **The filter matches nothing.** For `programSubscribe` and `logsSubscribe`, an address that never appears in a transaction produces no events. Check the address on an explorer first.
* **The signature is old.** `signatureSubscribe` only knows about recent transactions. For anything older than a few minutes, call `getSignatureStatuses` with `searchTransactionHistory: true` instead. See [Wait for a transaction to confirm](/recipes#wait-for-a-transaction-to-confirm).

## Connections that drop

### Idle connections close without warning

A connection with no traffic is eventually dropped, and it is closed abruptly rather than with a close frame, so your client sees code `1006` with an empty reason. Keep it alive by sending WebSocket **ping frames** every 20 to 30 seconds:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
const ws = new WebSocket(`wss://fra.rpc.orbitflare.com?api_key=${process.env.ORBITFLARE_LICENSE_KEY}`);

const keepalive = setInterval(() => ws.ping(), 25_000);
ws.on("close", () => clearInterval(keepalive));
```

> [!WARNING]
>
> A JSON-RPC message such as `{"method":"ping"}` is not a keepalive. Solana has no `ping` RPC method, so the server answers with `-32601 Method not found`. Use the protocol-level ping frame your library provides.

The OrbitFlare SDKs send a ping frame every 10 seconds and reconnect after three missed pongs, so you do not need to do this yourself when using them.

### Subscriptions are gone after a reconnect

Subscriptions belong to a connection. When it drops, they are gone, and a new connection starts with none. Keep a list of what you subscribed to and send those requests again after reconnecting. Note that the subscription IDs change.

The SDKs track subscriptions and resubscribe automatically. Your `sub.next()` loop keeps running across reconnects.

### Unsubscribing fails

`Invalid subscription id.` means that ID does not exist on this connection. Usually the connection was replaced and the ID belongs to the old one. It is safe to ignore.

### Too many connections

Each IP can hold 50 concurrent WebSocket connections, shared with gRPC. Open one connection and put many subscriptions on it rather than one connection per subscription. See [connection limits](/authentication#data-streaming-connection-limits).

## Still stuck

Collect the region you connect to, the exact subscription request, every message the server sent back, and the close code. Then ask in [Discord](https://discord.gg/orbitflare). With those four things, most problems can be pinned down in one reply.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.