
Language 🇺🇸 English (US)
Documentation
Getting Started
Usage
API Reference
Add Comments to Your Django App
This is the official Django Package for FastComments.
Live commenting and chat components with Secure SSO via template tags.
Repository
Requirements 
- Python 3.10+
- Django 4.2, 5.0, 5.1, or 5.2
- A FastComments tenant ID (use
demoto try it without an account) - An API secret is required only for Secure SSO
Installation 
Install from a release tag (this project is distributed via git tags, not PyPI):
pip install "git+https://github.com/fastcomments/fastcomments-django.git@v0.1.0"
For server-side REST access (the admin() / public_api() helpers), add the
api extra, which pulls in the SDK's generated client:
pip install "fastcomments-django[api] @ git+https://github.com/fastcomments/fastcomments-django.git@v0.1.0"
Add the app to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"fastcomments_django",
]
Quickstart 
Configure your tenant in settings.py:
import os
FASTCOMMENTS = {
"TENANT_ID": os.environ.get("FASTCOMMENTS_TENANT_ID", "demo"),
}
Drop the widget into any template:
{% load fastcomments %}
{% fastcomments url_id="my-page" %}
Prerequisites for automatic SSO 
To pass the logged-in user to the widget automatically, the tags read the current user from the request. Make sure your project has both of these (they are on by default in a standard Django project):
django.template.context_processors.requestinTEMPLATES["OPTIONS"]["context_processors"]django.contrib.auth.middleware.AuthenticationMiddlewareinMIDDLEWARE
Without a request in the template context, widgets render for an anonymous
visitor. You can always pass a user explicitly: {% fastcomments user=some_user %}.
Widget tags 
Every widget has its own tag. All of them accept **extra keyword arguments,
which are merged into the widget config as-is (use camelCase keys) for anything
not covered by the named arguments below.
| Tag | Widget |
|---|---|
{% fastcomments %} | Comments |
{% fastcomments_live_chat %} | Live chat |
{% fastcomments_comment_count %} | Comment count badge |
{% fastcomments_comment_count_bulk %} + {% fastcomments_count_marker %} | Bulk comment counts |
{% fastcomments_collab_chat target="#el" %} | Collaborative (inline) chat |
{% fastcomments_image_chat target="#el" %} | Image annotation chat |
{% fastcomments_recent_comments %} | Recent comments |
{% fastcomments_recent_discussions %} | Recent discussions |
{% fastcomments_reviews_summary %} | Reviews summary |
{% fastcomments_top_pages %} | Most-discussed pages |
{% fastcomments_user_activity user_id="..." %} | A user's activity feed |
Named arguments map to the widget's camelCase config keys:
| Argument | Config key | Tags |
|---|---|---|
url_id | urlId | comments, live chat, comment count, collab/image chat, recent comments, reviews summary |
url | url | comments, live chat, collab/image chat |
readonly | readonly | comments, live chat, collab/image chat |
locale | locale | comments, live chat, collab/image chat, user activity |
has_dark_background | hasDarkBackground | all |
default_sort_direction | defaultSortDirection | comments, live chat, collab/image chat |
number_only | numberOnly | comment count |
is_live | isLive | comment count |
count | count | recent comments, recent discussions |
target | (querySelector, not sent) | collab chat, image chat |
chat_square_percentage | chatSquarePercentage | image chat |
user_id | userId | user activity |
Examples:
{% load fastcomments %}
{% fastcomments url_id="my-page" locale="en_us" default_sort_direction="MR" %}
{% fastcomments_live_chat url_id="room-1" %}
Comments: {% fastcomments_comment_count url_id="my-page" number_only=True %}
{# Collab chat attaches to an existing element on the page #}
<article id="post-body">...</article>
{% fastcomments_collab_chat target="#post-body" %}
{# Bulk counts: place markers, then one bulk loader fills them all in #}
{% for post in posts %}
<a href="\{{ post.url }}">\{{ post.title }}</a>
{% fastcomments_count_marker url_id=post.url_id %}
{% endfor %}
{% fastcomments_comment_count_bulk %}
SSO (Single Sign-On) 
Enable SSO and choose a mode in settings.py. Secure SSO signs the user
server-side with HMAC-SHA256 using your API secret and is recommended.
FASTCOMMENTS = {
"TENANT_ID": os.environ["FASTCOMMENTS_TENANT_ID"],
"API_KEY": os.environ["FASTCOMMENTS_API_KEY"], # your API secret; signs Secure SSO
"SSO": {
"ENABLED": True,
"MODE": "secure", # "secure" | "simple"
# Map FastComments fields to your user model. Values may be an attribute
# name, a dotted path ("profile.avatar_url"), a callable(user), or None.
"USER_MAP": {
"id": "id",
"email": "email",
"username": "username",
"avatar": None,
"display_name": None,
"website_url": None,
},
"IS_ADMIN": lambda user: user.is_staff, # callable(user) -> bool, or dotted path
"IS_MODERATOR": None,
"GROUP_IDS": None, # callable(user) -> list, or dotted path
},
}
Choose the SSO
iddeliberately. The FastCommentsidis the permanent handle for a user's comment history. The defaultUSER_MAPmaps it to your Django primary key for zero-config convenience, but sequential integer PKs are enumerable and hard to change later (changing a user'sidsplits their history into a new account). For anything beyond a demo, mapidto a stable, opaque value chosen up front (a UUID or a dedicated public id), and never put private data in it. The example app uses a username-based id for this reason.
SSO is injected automatically into {% fastcomments %}, {% fastcomments_live_chat %},
{% fastcomments_collab_chat %}, {% fastcomments_image_chat %}, and
{% fastcomments_user_activity %} for the current user.
Login/logout URLs shown to signed-out visitors default to reverse("login") /
reverse("logout"); override them with SSO["LOGIN_URL"] / SSO["LOGOUT_URL"].
Custom mapping
Two higher-precedence options beat USER_MAP:
-
A method on your user model (the Pythonic analog of an interface):
class User(AbstractUser): def to_fastcomments_user_data(self): return {"id": self.pk, "email": self.email, "username": self.get_username()} -
A global mapper, a dotted path to
callable(user) -> dict:FASTCOMMENTS = {"SSO": {"USER_MAPPER": "myapp.sso.map_user"}}
Precedence is USER_MAPPER > to_fastcomments_user_data() > USER_MAP.
Server-side API access 
With the [api] extra installed, call the FastComments REST API through the SDK,
pre-configured with your API key and region:
from fastcomments_django import admin, public_api, get_manager
admin().get_comments("YOUR_TENANT_ID", ...) # authenticated (DefaultApi)
public_api().get_comments_public(...) # public (PublicApi)
# Generate an SSO token for API calls or client hand-off:
token = get_manager().sso().token_for(request.user)
EU region 
Set REGION to route the widgets and API to the EU:
FASTCOMMENTS = {"TENANT_ID": "...", "REGION": "eu"}
Customizing the embed markup 
Override fastcomments/widget.html by placing your own copy earlier on the
template search path (a project templates/fastcomments/widget.html). This is
the Django analog of Laravel's vendor:publish --tag=fastcomments-views.
Settings reference 
| Key | Default | Description |
|---|---|---|
TENANT_ID | "" | Your FastComments tenant ID (demo for testing). |
API_KEY | "" | Your API secret. Signs Secure SSO and authenticates admin(). |
REGION | None | None for US, "eu" for the EU region. |
SSO.ENABLED | False | Turn SSO on. |
SSO.MODE | "secure" | "secure" (HMAC) or "simple" (unsigned). |
SSO.LOGIN_URL / SSO.LOGOUT_URL | None | Shown to signed-out visitors; default to reverse("login"/"logout"). |
SSO.USER_MAP | id/email/username | FastComments field to user attribute/path/callable. |
SSO.IS_ADMIN / IS_MODERATOR / GROUP_IDS | None | callable(user) or dotted path. |
SSO.USER_MAPPER | None | Dotted path to callable(user) -> dict; highest precedence. |
WIDGET_DEFAULTS | {} | Config merged into every widget (camelCase keys). |
Example project 
A runnable showcase lives in example/: a left-rail + main-stage
app with a page per widget and a sign-in page listing pre-seeded demo users.
Sign in as any of them and the comment and live-chat widgets authenticate that
identity via Secure SSO. From that directory:
python manage.py migrate
# Use your own tenant to see Secure SSO in action (an API secret enables it):
FASTCOMMENTS_TENANT_ID=... FASTCOMMENTS_API_KEY=... python manage.py runserver
Without an API secret it falls back to the public demo tenant (anonymous).
example/browser_smoke.py is a Playwright e2e
that loads the page in a real browser and posts a comment as the Secure-SSO
user.
Need Help?
If you encounter any issues or have questions about the Django Package, please:
Contributing
Contributions are welcome! Please visit the GitHub repository for contribution guidelines.