Skip to main content

A lightweight, real-time support chat widget for Django powered by SSE

Project description

๐Ÿ’ฌ django-supchat

A Lightweight, Real-Time Support Chat for Django

PyPI version Python Versions Django Versions License: MIT Downloads Code style: black

Zero dependencies. No WebSockets. No Redis. No React.
Just Django, vanilla JS, and Server-Sent Events.

Installation โ€ข Demo โ€ข Documentation โ€ข Examples


โœจ Overview

django-supchat is a production-ready, drop-in support chat widget for Django projects. It provides a beautiful, real-time chat experience between website visitors (guests or authenticated users) and your support team โ€” all powered by Django's ORM and Server-Sent Events (SSE).

๐ŸŽฏ Philosophy: Ship a powerful chat system without the complexity of WebSockets, Redis, or a frontend build step. Just pip install and go.


๐Ÿš€ Key Features

๐ŸŽจ Frontend

  • โœจ Modern glassmorphism UI with smooth animations
  • ๐ŸŒ“ Auto Light/Dark theme (respects OS preference)
  • ๐ŸŒ Auto bilingual (Persian/English) with RTL support
  • โŒจ๏ธ Real-time typing indicators
  • โœ… Read receipts with visual feedback
  • ๐Ÿ“ฑ Fully responsive (mobile fullscreen)
  • โ™ฟ WCAG 2.1 accessible
  • ๐ŸŽญ Customizable colors via CSS variables

โšก Backend

  • ๐Ÿ”Œ Zero external dependencies โ€” no Redis, no Channels
  • ๐Ÿ“ก Real-time via Server-Sent Events (SSE)
  • ๐Ÿ”’ Signed, HTTP-only guest cookies
  • ๐Ÿ›ก๏ธ CSRF protection on all POST endpoints
  • ๐Ÿšฆ Built-in rate limiting (pluggable)
  • ๐Ÿงน HTML sanitization & control char stripping
  • ๐Ÿ‘ฅ Multi-operator support with assignment

๐Ÿ“ฆ Quick Start

Get up and running in under 2 minutes.

1. Install

pip install django-supchat

2. Configure Django

# settings.py
INSTALLED_APPS = [
    # ...
    "supchat",
]

# Optional: Customize the widget
SUPCHAT = {
    "TITLE": "Support",
    "POSITION": "right",        # "right" or "left"
    "THEME": "auto",            # "auto", "light", or "dark"
    "ALLOW_GUEST": True,
    "MAX_MESSAGE_LENGTH": 2000,
}

3. Add URLs

# urls.py
from django.urls import include, path

urlpatterns = [
    # ...
    path("supchat/", include("supchat.urls")),
]

4. Run Migrations

python manage.py migrate

5. Render the Widget

{% raw %}
{% load supchat %}

<!DOCTYPE html>
<html lang="en">
<head>
    <title>My Site</title>
</head>
<body>
    <h1>Welcome to my site!</h1>
    
    {% supchat %}
</body>
</html>
{% endraw %}

That's it! ๐ŸŽ‰ Your chat widget is live.


๐Ÿ“š Documentation

Configuration Reference

Widget Settings

Setting Type Default Description
TITLE str "Support" Widget title displayed in header
POSITION str "right" Widget position: "right" or "left"
THEME str "auto" Theme: "auto", "light", or "dark"
ALLOW_GUEST bool True Allow anonymous visitors to chat
MAX_MESSAGE_LENGTH int 2000 Maximum characters per message

Advanced Settings

Setting Type Default Description
HEARTBEAT_INTERVAL int 25 SSE heartbeat interval (seconds)
SSE_RETRY_MS int 5000 SSE reconnection delay (ms)
GUEST_COOKIE_NAME str "supchat_guest" Name of the guest identity cookie
GUEST_COOKIE_AGE int 31536000 Cookie lifetime (1 year in seconds)
RATE_LIMIT dict {"MESSAGES": 30, "WINDOW": 60} Default rate limit config
RATE_LIMIT_CALLBACK callable None Custom rate limit function

Per-Render Overrides

You can override settings per template render:

{% raw %}
{% supchat title="Help Desk" position="left" theme="dark" %}
{% endraw %}

๐Ÿ” Security Model

django-supchat takes security seriously:

  • โœ… CSRF Protection โ€” All POST endpoints require valid CSRF tokens
  • โœ… Signed Guest Cookies โ€” Guest identity stored in signed, HTTP-only cookies
  • โœ… Conversation Access Control โ€” Every endpoint (including SSE) verifies access
  • โœ… Input Sanitization โ€” HTML stripped, control chars removed, length capped
  • โœ… XSS Prevention โ€” Frontend uses textContent, never innerHTML
  • โœ… Rate Limiting โ€” Cache-backed default + pluggable hook for custom logic

Custom Rate Limiting

# settings.py
def my_rate_limiter(request, action):
    # Return True to allow, False to deny
    if request.user.is_staff:
        return True
    return False  # Custom logic

SUPCHAT = {
    "RATE_LIMIT_CALLBACK": my_rate_limiter,
}

๐Ÿ‘ฅ Operator Management

Creating Operators

Create Operator records in Django admin for your support staff:

from django.contrib.auth import get_user_model
from supchat.models import Operator

User = get_user_model()
user = User.objects.get(username="support_agent")
Operator.objects.create(user=user, is_online=True)

Assigning Operators Programmatically

from supchat.services import assign_operator

# Auto-assign to current user (if they're an operator)
assign_operator(request, conversation)

# Assign to a specific operator
assign_operator(request, conversation, operator=some_operator)

Operator Dashboard

Access the operator panel at /supchat/operator/ (requires staff permissions).

Features:

  • ๐Ÿ’ฌ Real-time conversation list with unread badges
  • ๐Ÿ“Š Analytics dashboard with 7-day & 30-day charts
  • ๐ŸŽฏ Conversation assignment & status management
  • ๐ŸŒ“ Dark/Light theme toggle
  • ๐ŸŒ Bilingual interface (EN/FA)

๐Ÿ› ๏ธ Public API

The service layer is the stable integration point. Use these functions in your views, signals, or management commands:

from supchat.services import (
    get_or_create_conversation,
    send_message,
    close_conversation,
    assign_operator,
    mark_messages_read,
)

get_or_create_conversation(request) โ†’ (Conversation, guest_id | None)

Returns an open conversation for the user/guest. Creates one if none exists.

conversation, guest_id = get_or_create_conversation(request)

send_message(request, conversation, text) โ†’ Message

Sends a message and broadcasts it via SSE.

message = send_message(request, conversation, "Hello!")

close_conversation(request, conversation) โ†’ Conversation

Closes a conversation (operators only).

close_conversation(request, conversation)

assign_operator(request, conversation, operator=None) โ†’ Conversation

Assigns an operator to a conversation.

assign_operator(request, conversation, operator=my_operator)

mark_messages_read(request, conversation, message_ids=None) โ†’ int

Marks messages as read. Returns count of updated messages.

count = mark_messages_read(request, conversation)

๐ŸŽจ Customization

Override any of these in your project:

your_project/
โ”œโ”€โ”€ templates/
โ”‚   โ””โ”€โ”€ supchat/
โ”‚       โ””โ”€โ”€ widget.html          # Override the widget template
โ””โ”€โ”€ static/
    โ””โ”€โ”€ supchat/
        โ”œโ”€โ”€ supchat.css          # Override styles
        โ””โ”€โ”€ supchat.js           # Override behavior

CSS Variables

Customize colors by overriding CSS variables:

.supchat-widget {
    --sc-primary: #6366f1;
    --sc-primary-hover: #4f46e5;
    --sc-bubble-user: linear-gradient(135deg, #6366f1, #8b5cf6);
    --sc-bubble-agent: #ffffff;
    --sc-bg: rgba(255, 255, 255, 0.95);
    --sc-fg: #0f172a;
    --sc-border: rgba(226, 232, 240, 0.8);
}

JavaScript Events

Listen to chat events:

document.addEventListener('supchat:open', () => {
    console.log('Chat opened');
});

document.addEventListener('supchat:close', () => {
    console.log('Chat closed');
});

document.addEventListener('supchat:message', (e) => {
    console.log('New message:', e.detail);
});

๐Ÿšข Deployment

SSE Requirements

The built-in SSE manager is process-local and works great for:

  • Development
  • Single-process deployments
  • Small to medium traffic

For multi-worker deployments (Gunicorn, uWSGI with multiple workers), clients connected to different workers won't receive broadcasts. Solutions:

Option 1: Single Worker

gunicorn myproject.wsgi:application --workers 1 --threads 8

Option 2: Cross-Worker Fanout

Implement your own broadcast mechanism using Redis Pub/Sub, a message queue, or your cache backend:

# myproject/sse_bridge.py
from django.core.cache import cache
from supchat.sse import sse_manager

def broadcast_to_all_workers(conversation_id, event, data):
    # Publish to Redis/cache
    cache.set(f"supchat:broadcast:{conversation_id}", {
        "event": event,
        "data": data,
    }, timeout=5)
    
    # Each worker subscribes and calls:
    # sse_manager.broadcast(conversation_id, event, data)

Proxy Configuration

Nginx:

location /supchat/ {
    proxy_pass http://localhost:8000;
    proxy_buffering off;              # Critical for SSE
    proxy_cache off;
    proxy_read_timeout 86400s;        # Long timeout for SSE
    proxy_send_timeout 86400s;
}

Apache:

<Location /supchat/>
    ProxyPass http://localhost:8000/supchat/
    ProxyPassReverse http://localhost:8000/supchat/
    SetEnv proxy-nokeepalive 1
    SetEnv proxy-sendchunked 1
</Location>

๐ŸŒ Browser Support

Browser Version
Chrome 90+
Firefox 88+
Safari 14+
Edge 90+
iOS Safari 14+
Android Chrome 90+

๐Ÿ—บ๏ธ Roadmap

  • File/image attachments
  • Message reactions & emoji
  • Conversation tags & categories
  • Canned responses / quick replies
  • Chat transcripts via email
  • Webhook integrations (Slack, Discord)
  • Bot/AI auto-responses
  • Multi-language support (beyond EN/FA)
  • Mobile SDK (iOS/Android)
  • WebSocket adapter (optional)

๐Ÿค Contributing

Contributions are welcome! Here's how:

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Development Setup

git clone https://github.com/xo-aria/django-supchat.git
cd django-supchat
pip install -e '.[test]'
pytest

๐Ÿ“„ License & Trademark

Code License

django-supchat is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

This means:

  • โœ… You can use, modify, and distribute this software
  • โœ… You can use it commercially
  • โš ๏ธ You must disclose source code (even for SaaS/network services)
  • โš ๏ธ You must include the same license in distributions
  • โš ๏ธ You must state changes you made

๐Ÿ“– Read the full AGPL-3.0 license

Trademark Policy

The name "SupChat" is a trademark of xo-aria. See the Trademark Policy for details on:

  • โœ… How to use the SupChat name
  • โœ… Attribution requirements
  • โŒ What you cannot do
  • ๐ŸŽจ Logo usage guidelines

Quick Summary:

  • You must keep "SupChat" in the name when distributing
  • You must include attribution: Based on SupChat by xo-aria - https://github.com/xo-aria/django-supchat
  • You cannot rebrand without mentioning SupChat
  • You cannot use SupChat logos without permission

Why AGPL-3.0?

We chose AGPL-3.0 to:

  1. Protect user freedom - Ensure the software stays free
  2. Close the SaaS loophole - Even network services must share source code
  3. Encourage contributions - Improvements benefit everyone
  4. Maintain quality - Prevent closed-source forks from fragmenting the project

Commercial Use

Yes, you can use SupChat commercially! Just:

  • โœ… Comply with AGPL-3.0 (disclose source code)
  • โœ… Follow the trademark policy (attribution)
  • โœ… Document your changes

Need a commercial license without AGPL restrictions? Contact us.


๐Ÿ™ Attribution

If you use SupChat in your project, we'd appreciate:

Required (by license):

Based on SupChat by xo-aria
https://github.com/xo-aria/django-supchat
Licensed under AGPL-3.0

Appreciated (but optional):

  • โญ Star the repository on GitHub
  • ๐Ÿ“ Mention "Powered by SupChat" in your docs/about page
  • ๐Ÿ”— Link back to https://github.com/xo-aria/django-supchat
  • ๐Ÿฆ Tweet about it (we'd love to see your projects!)

๐Ÿ“ž Support & Contact

Bug Reports & Feature Requests:

Questions & Discussions:

Commercial Licensing:

  • ๐Ÿ“ง Email: [your-email@example.com]
  • ๐Ÿ’ผ Custom licensing available for closed-source projects

Security Issues:

  • ๐Ÿ”’ Please email security issues directly to [your-email@example.com]
  • โš ๏ธ Do not open public issues for security vulnerabilities

If django-supchat helps your project, please consider:

โญ Starring on GitHub โ€ข ๐Ÿด Forking โ€ข ๐Ÿ’ฌ Joining Discussions

Made with โค๏ธ by xo-aria


๐Ÿ™ Acknowledgments


๐Ÿ“ž Support


If django-supchat helps your project, consider giving it a โญ on GitHub!

โญ Star on GitHub โ€ข ๐Ÿ’ฌ Join Discussions

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_supchat-1.8.0.tar.gz (56.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_supchat-1.8.0-py3-none-any.whl (59.0 kB view details)

Uploaded Python 3

File details

Details for the file django_supchat-1.8.0.tar.gz.

File metadata

  • Download URL: django_supchat-1.8.0.tar.gz
  • Upload date:
  • Size: 56.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for django_supchat-1.8.0.tar.gz
Algorithm Hash digest
SHA256 b4aaae22179e801bcd94982f323ac7792b8273a1acbab11138b0cecd5b54c186
MD5 879c416987dd902391e3f7a2a2f666f3
BLAKE2b-256 55b325c57c0492e105e4d81a8ec09adeebb96c5c119654b1a01448d39558363b

See more details on using hashes here.

File details

Details for the file django_supchat-1.8.0-py3-none-any.whl.

File metadata

  • Download URL: django_supchat-1.8.0-py3-none-any.whl
  • Upload date:
  • Size: 59.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for django_supchat-1.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 25ac299e1d7f3df3887fafd9e74fac4c2bda26ce54835324139183fbc25b7b9e
MD5 974feddae61123cf5c47f495c7b9b61e
BLAKE2b-256 d0f0ebeedef14dd7fb0740e3452a32b4060eb2f8f218a5cc7b0d5e6e5d817567

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page