Skip to content

WebSocket connections get stuck in CONNECTING on iOS Safari (ESP32-S3 + ESPAsyncWebServer) #339

@jerre321

Description

@jerre321

Summary

On iOS Safari, rapidly switching between pages that use WebSockets can leave connections half-open.
With ESPAsyncWebServer this may cause new WebSocket connections to stay stuck in CONNECTING, while desktop browsers work fine.

Root cause

AsyncWebSocket does not automatically clean up stale/half-open clients.
On iOS Safari, disconnect events are often delayed or missing during quick navigation, so stale clients accumulate unless cleanupClients() is called manually.

Fix

  1. Expose cleanup in WebSocketTxRx.h
    Add a public loop() method to periodically clean up clients:
// WebSocketTxRx.h
public:
  void loop() {
    _webSocket.cleanupClients();
  }
  1. Call cleanup from the owning service
    Example using LightStateService:
// LightStateService.h
public:
  void loop();
// LightStateService.cpp
void LightStateService::loop() {
  _webSocket.loop();
}
  1. Then call this once per main loop:
// main.cpp
void loop() {
  lightStateService.loop();
}

Conclusion

I’m not entirely sure this is the best or intended way to handle WebSocket lifecycle management in ESPAsyncWebServer.
However, in practice this change consistently resolves the issue on iOS Safari and prevents connections from getting stuck in CONNECTING during rapid navigation.

If there is a more idiomatic or built-in approach to handle stale WebSocket clients—especially for mobile browsers—I’d be very interested to learn about it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions