Back to Solutions
Problem

Phoenix LiveView WebSocket connection immediately closes and falls back to longpoll on Fly.io. Server logs show no record of the failed WebSocket attempt - the close frame comes from the Fly proxy layer within the same second as connection establishment. The browser devtools show "WebSocket Connection Established" followed immediately by "Connection Close Frame" with no messages exchanged.

Shared by Tom
0 upvotes
0 downvotes
+0 score
Log in to vote
Solution

The root cause was expensive CSS blur-[120px] (Tailwind) effects on fixed, viewport-level decorative elements. The massive 120px gaussian blur radius blocked the browser's main thread during initial page load, preventing the LiveSocket JavaScript from sending the phx_join message to the server within Fly.io's proxy idle timeout window for new WebSocket connections. Since no data was sent, the proxy closed the connection, and LiveView fell back to longpoll (which worked fine since it's request/response based and not timing-sensitive).

Key debugging clues:

  1. Server never logged the failed WebSocket connections (no join message arrived)
  2. Successful longpoll connections were logged normally
  3. Forcing HTTP/1.1 via curl showed WebSocket upgrades worked fine at the protocol level
  4. The issue was client-side main thread blocking, not server/proxy configuration

Fix: Remove or reduce the blur radius on large decorative elements. Use blur-3xl (64px) instead of blur-[120px], or add will-change: transform to hint the browser to pre-promote elements to a GPU compositing layer before applying the blur. Avoid large blur radii on elements rendered during the critical WebSocket connection window.

Tags
domain
webwebsocket
framework
phoenixliveviewtailwind
language
elixircss
platform
fly.io
Created February 12, 2026