How to Test WebSocket Connections Through a Proxy

Browser traffic crossing a proxy relay to an Internet service with bidirectional WebSocket heartbeat signals

A normal HTTP probe can pass while a WebSocket workflow still fails. The opening request may receive a successful upgrade, yet the connection can later break because the proxy closes idle tunnels, the exit changes during a reconnect, a worker does not send heartbeats, DNS is resolved in the wrong place, or a direct fallback bypasses the intended route.

For authorized chat, telemetry, browser automation, live pricing, and application QA, test the WebSocket as a lifecycle rather than as one status code. A useful result must prove the upgrade, both traffic directions, connection survival, controlled closure, and predictable recovery.

Define one test identity

Before sending traffic, assign the run a non-secret test ID and record:

  • browser or client version;
  • proxy protocol and gateway label;
  • requested region and exit-cohort label;
  • DNS owner: local, browser, gateway, or SOCKS remote DNS;
  • address family;
  • connection start and end time;
  • opening status, close code, message counts, and heartbeat times;
  • expected content marker and final result.

Do not record proxy passwords, authorization headers, cookies, reusable session tokens, or message bodies containing personal data. Use a test endpoint you control or an application you are authorized to assess.

Verify the opening handshake

For a standard WebSocket connection, the client begins with an HTTP request that asks the server to switch protocols. Confirm that:

  1. the request actually traverses the configured proxy;
  2. the target host, port, and scheme match the plan;
  3. the server returns a valid protocol upgrade rather than a cached page, redirect loop, login page, or block page;
  4. required subprotocol negotiation succeeds;
  5. the proxy does not remove required upgrade headers;
  6. TLS hostname validation remains correct for secure WebSockets.

Do not mark a test successful solely because a browser reports the socket as open. Correlate the client timestamp with a gateway-side observation using the same non-secret test ID.

Prove both message directions

An open socket can still be half-broken. Send a small, unique test message and require the controlled server to echo or acknowledge it. Then have the server send an independent message that the client must validate.

Record send time, receive time, direction, byte count, and a harmless message hash. Keep the original payload out of long-term logs. Run the test at concurrency one first so one connection cannot be confused with another.

If client-to-server traffic works but server-to-client traffic stops, investigate proxy buffering, intermediary timeouts, browser or worker lifecycle, and application subscription state. Do not rotate the exit until the failing boundary is known.

Measure the real idle timeout

Many proxies, load balancers, and application gateways close quiet connections. Documentation may state one timeout while the effective path uses another.

Run a stepped test:

  1. establish a validated connection;
  2. leave it application-idle for 15 seconds, then send a probe;
  3. repeat with 30, 60, 120, and 300 seconds;
  4. record the first interval at which the probe or acknowledgement fails;
  5. repeat the boundary interval several times on the same exit cohort.

The safe application heartbeat interval must be shorter than the lowest repeatable idle cutoff, with margin for network jitter and event-loop delay. Do not set an aggressive heartbeat merely to keep every tunnel alive; unnecessary heartbeats multiply bandwidth and load at fleet scale.

Separate protocol ping/pong from application heartbeats

Some clients expose WebSocket ping and pong frames; browser JavaScript generally relies on application-level messages instead. Record which mechanism is being tested.

A heartbeat test should verify three outcomes:

  • the heartbeat leaves the client through the proxy;
  • the expected pong or application acknowledgement returns before the deadline;
  • a missing acknowledgement closes or quarantines the connection instead of leaving a zombie socket in the pool.

Use a monotonic timer for latency and a wall-clock timestamp only for correlation. A system clock adjustment should not create negative heartbeat latency.

Test sticky routing and reconnects separately

A connection is naturally pinned while it remains open, but a reconnect is a new routing event. If the application depends on region, account state, or an upstream affinity cookie, decide whether reconnects must use the same proxy session or a deliberately new one.

Run two cases:

  • sticky reconnect: reuse the approved session identifier and verify the same logical region and state;
  • fresh reconnect: create a new session, label it as a new sample, and verify that application state is rebuilt safely.

Do not call both cases “retry.” They answer different questions. Exponential backoff with random jitter should govern reconnect timing, and explicit denial or throttling must not trigger rapid exit rotation.

Verify close behavior

Test a normal client close, normal server close, policy rejection, application restart, network interruption, and proxy shutdown. Capture the close code and whether the peer received the close handshake.

A clean close should release the browser, worker, proxy tunnel, and application subscription. An abnormal close should enter a bounded recovery path. It must not create two live subscriptions after reconnecting.

When the approved proxy becomes unavailable, the client must fail closed. Confirm that it does not fall back to the device's direct route. Test IPv4 and IPv6 independently because one address family can remain reachable when the other proxy path fails.

Use a seven-case release matrix

CaseChange one variableRequired evidence
Baselinenormal connectionvalid upgrade and two-way messages
Idle boundaryincreasing quiet intervalrepeatable cutoff and safe heartbeat margin
Missing heartbeatsuppress acknowledgementzombie connection detected and removed
Sticky reconnectsame proxy sessionexpected region and application state preserved
Fresh reconnectnew proxy sessionnew route labeled and state rebuilt
Proxy lossgateway unavailablefail closed with no direct fallback
Dual stackIPv4 then IPv6route and DNS evidence for each family

Repeat each case enough times to distinguish a deterministic policy from a transient route failure. Report pass, fail, or inconclusive; do not turn missing evidence into a pass.

Troubleshooting guide

Upgrade succeeds, then the socket closes at a fixed interval

Measure the effective idle cutoff and compare it with heartbeat timing. Check proxy, load balancer, server, browser worker, and NAT idle policies independently.

Messages arrive only in one direction

Confirm subscription state, proxy buffering, event-loop health, and whether an intermediary is treating the connection as idle. Use controlled messages in both directions.

Reconnect reaches the wrong region

Check whether the proxy session was reused, whether DNS moved to a different resolver, and whether the new exit cohort matches the requested region. Validate response content, not only the IP label.

The socket works without the proxy but not through it

Compare the handshake request, TLS validation, proxy authentication, target port policy, and upgrade-header handling. Do not disable certificate validation as a shortcut.

Release checklist

  • The opening handshake is correlated with a proxy observation.
  • Both message directions are validated with controlled payloads.
  • The effective idle timeout is measured, not assumed.
  • Heartbeats use a safe interval and missing acknowledgements remove zombie sockets.
  • Sticky and fresh reconnects are distinct test cases.
  • Reconnects use bounded backoff with jitter.
  • Close codes and resource cleanup are recorded.
  • Proxy loss fails closed for IPv4 and IPv6.
  • Logs contain no reusable credentials or unnecessary message bodies.
  • Explicit denial and throttling signals are respected.

Compliance note

WebSocket testing does not create permission to access a service. Test only endpoints and accounts you control or are authorized to assess. Respect access controls, application terms, rate limits, data-minimization requirements, privacy obligations, and explicit denial signals. Do not use reconnects or rotating exits to evade a destination decision.

Related 98IP guides

Source note: IETF, The WebSocket Protocol, RFC 6455; MDN Web Docs, WebSocket API. External source URLs are retained only in the internal operations record.