Install StageWhisper in Flask
Install StageWhisper in Flask by adding one async script tag to your Jinja2 base template — every template that extends it inherits the widget, so one edit covers your whole app. No extension, no blueprint, no config key.
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
flask runlocally.
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-route 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 flask-talisman
Serving a strict Content Security Policy with
flask-talisman? Pass your policy to Talisman and
list the directives that should carry a per-request nonce in
content_security_policy_nonce_in:
# app.py
from flask import Flask
from flask_talisman import Talisman
app = Flask(__name__)
csp = {
"default-src": "'self'",
"script-src": ["'self'", "https://cdn.stagewhisper.co"],
"style-src": "'self'",
"connect-src": ["'self'", "https://api-staging.stagewhisper.co"],
}
Talisman(
app,
content_security_policy=csp,
content_security_policy_nonce_in=["script-src", "style-src"],
)
Then carry the nonce on the loader tag itself with
nonce="{{ csp_nonce() }}" — flask-talisman registers
csp_nonce() as a Jinja2 global automatically, so it works in
any template with nothing extra to import:
<script async src="https://cdn.stagewhisper.co/loader.js" data-sw-key="pub_your_site_key" nonce="{{ 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.