Install StageWhisper in Django
Install StageWhisper in Django by adding one async script tag to your base template — every template that extends it inherits the widget, so one edit covers your whole app. No package, no app to register, no migration.
Prerequisites
- A StageWhisper site created in the dashboard.
-
Your app’s origin on the site’s origin allowlist — enable
the localhost toggle while you test with
runserverlocally.
Add the loader to your base template
-
Open
templates/base.html— the template every page{% extends %}— so the widget rides along on every page without per-view wiring. -
Paste the loader tag inside the
<head>, and swappub_your_site_keyfor the public site key shown on your site’s install page in the dashboard:templates/base.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>{% block title %}My app{% endblock %}</title> <script async src="https://cdn.stagewhisper.co/loader.js" data-sw-key="pub_your_site_key"></script> {% block extra_head %}{% endblock %} </head> <body> {% block content %}{% endblock %} </body> </html>
The tag is async, so it never blocks your page render —
the widget mounts quietly once the page is up.
Strict CSP with django-csp
Serving a strict Content Security Policy with
django-csp? Install its middleware and enable per-request
nonces by including the NONCE constant
(csp.constants.NONCE) in your script-src
directive config:
# settings.py
from csp.constants import NONCE, SELF
MIDDLEWARE = [
# ...
"csp.middleware.CSPMiddleware",
]
CONTENT_SECURITY_POLICY = {
"DIRECTIVES": {
"script-src": [SELF, NONCE, "https://cdn.stagewhisper.co"],
"style-src": [SELF, NONCE],
"connect-src": [SELF, "https://api-staging.stagewhisper.co"],
},
}
Then carry the nonce on the loader tag itself with
nonce="{{ request.csp_nonce }}":
<script async src="https://cdn.stagewhisper.co/loader.js" data-sw-key="pub_your_site_key" nonce="{{ request.csp_nonce }}"></script>
The Content Security Policy guide has the full directive list, including the Turnstile origins to allow if you enable it.
Verify
Refresh your app, then watch the site’s install status in the dashboard — it flips the moment the first ping arrives.
Widget not showing up? Head to Troubleshooting for the usual suspects — blocked origins, CSP, localhost, and stale config.