I am building a live streaming website where users can watch a live class and interact via WebSocket chat. I have integrated Django Channels, Redis, and HLS.js for video playback. The chat connects via a WebSocket to Django Channels. However, the issue is: The WebSocket connects successfully, but immediately closes afterward. The browser console shows multiple attempts to reconnect, but the problem persists. There is no clear error message except "WebSocket connection closed" in the JavaScript console. My Setup Django 5.1.8 channels channels-redis Redis server is running (redis-cli ping returns PONG) Development server (local machine, runserver + daphne for Channels) Code Snippets HTML/JS Side (live_stream.html) <script> // WebSocket Chat functionality const streamId = "UDOOSDIHOH49849"; // Your stream_id let chatSocket = null; let reconnectAttempts = 0; const maxReconnectAttempts = 5; // You can fetch real username from Django template if available const username = "Anonymous"; // You can dynamically change this later function connectWebSocket() { chatSocket = new WebSocket( 'ws://' + window.location.host + '/ws/chat/' + streamId + '/' ); chatSocket.onopen = function(e) { console.log('WebSocket connection established'); reconnectAttempts = 0; }; chatSocket.onmessage = function(e) { const data = JSON.parse(e.data); const chatBox = document.getElementById('chatMessages'); const newMessage = document.createElement('p'); newMessage.innerHTML = `<strong>${data.username}:</strong> ${data.message}`; chatBox.appendChild(newMessage); chatBox.scrollTop = chatBox.scrollHeight; }; chatSocket.onclose = function(e) { console.log('WebSocket connection closed'); if (reconnectAttempts < maxReconnectAttempts) { console.log('Attempting to reconnect...'); reconnectAttempts++; setTimeout(connectWebSocket, 3000); } else { console.error('Maximum reconnection attempts reached'); } }; chatSocket.onerror = function(e) { console.error('WebSocket error:', e); }; } // Initial connection connectWebSocket(); // Send button functionality document.getElementById('sendBtn').onclick = function() { const input = document.getElementById('chatInput'); const message = input.value.trim(); if (message !== '' && chatSocket && chatSocket.readyState === WebSocket.OPEN) { chatSocket.send(JSON.stringify({ 'message': message, 'username': username // Send both message and username })); input.value = ''; } }; // Enter key support document.getElementById('chatInput').addEventListener('keypress', function(e) { if (e.key === 'Enter') { document.getElementById('sendBtn').click(); } }); </script> views.py from django.contrib.auth.decorators import login_required from django.shortcuts import render @login_required def watch_stream(request, stream_id="UDOOSDIHOH49849"): return render(request, 'video/live_stream.html', { 'stream_id': stream_id, 'user': request.user, }) consumers.py # consumers.py import json from channels.generic.websocket import AsyncWebsocketConsumer from channels.db import database_sync_to_async class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): from videoconference_app.models import LiveStream # Import here to avoid app loading issues try: self.stream_id = self.scope['url_route']['kwargs']['stream_id'] self.user = self.scope['user'] self.room_group_name = f'chat_{self.stream_id}' await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() # Notify others about new user joining await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': f"{self.user.username if self.user.is_authenticated else 'Anonymous'} joined the chat!", 'username': self.user.username if self.user.is_authenticated else 'Anonymous' } ) except Exception as e: print(f"WebSocket connect error: {e}") await self.close() async def disconnect(self, close_code): try: await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) except Exception as e: print(f"WebSocket disconnect error: {e}") async def receive(self, text_data): try: text_data_json = json.loads(text_data) message = text_data_json.get('message', '') username = text_data_json.get('username', 'Anonymous') await self.channel_layer.group_send( self.room_group_name, { 'type': 'chat_message', 'message': message, 'username': username } ) except Exception as e: print(f"WebSocket receive error: {e}") async def chat_message(self, event): try: await self.send(text_data=json.dumps({ 'message': event['message'], 'username': event.get('username', 'Anonymous') })) except Exception as e: print(f"WebSocket chat_message error: {e}") @database_sync_to_async def get_stream(self): from videoconference_app.models import LiveStream try: return LiveStream.objects.get(stream_key=self.stream_id) except LiveStream.DoesNotExist: return None routing.py from django.urls import re_path from videoconference_app import consumers websocket_urlpatterns = [ re_path(r'ws/chat/(?P<stream_id>\w+)/$', consumers.ChatConsumer.as_asgi()), ] asgi.py import os from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application from channels.auth import AuthMiddlewareStack import videoconference_app.routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'course.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": AuthMiddlewareStack( URLRouter( videoconference_app.routing.websocket_urlpatterns ) ), }) settings.py (Channels + Redis) ASGI_APPLICATION = 'course.asgi.application' CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [('127.0.0.1', 6379)], }, }, } What I Have Already Tried Verified that Redis server is active (PONG confirmed). Checked that WebSocket URL is correct (ws:// since using http://localhost). Confirmed that Daphne and Django run together (daphne course.asgi:application). No visible errors in Django terminal except occasional WebSocket disconnect logs. JavaScript client correctly retries but server immediately closes the connection. Additional Information The stream page is protected via @login_required, so only authenticated users can access it. The user object is available in the Django template. Request What could be causing the WebSocket to immediately close after connection? Am I missing anything in the consumer logic, ASGI setup, or Channels configuration? Any advice or debugging tips would be appreciated! Thank you in advance. Continue reading...