Skip to main content

💬 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

Metadata

Release files for django-supchat 1.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-supchat 1.8.0
File Size Uploaded
django_supchat-1.8.0.tar.gz 56.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-supchat 1.8.0
File Interpreter ABI Platform
django_supchat-1.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 115.2 kB

Release files / django_supchat-1.8.0.tar.gz

Download URL django_supchat-1.8.0.tar.gz
Size 56.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b4aaae22179e801bcd94982f323ac7792b8273a1acbab11138b0cecd5b54c186
BLAKE2b-256 checksum
How to use checksums
55b325c57c0492e105e4d81a8ec09adeebb96c5c119654b1a01448d39558363b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / django_supchat-1.8.0-py3-none-any.whl

Download URL django_supchat-1.8.0-py3-none-any.whl
Size 59.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
25ac299e1d7f3df3887fafd9e74fac4c2bda26ce54835324139183fbc25b7b9e
BLAKE2b-256 checksum
How to use checksums
d0f0ebeedef14dd7fb0740e3452a32b4060eb2f8f218a5cc7b0d5e6e5d817567
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.8.0 This release

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.3.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page