Backends
FastAPI
FastAPI analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue.
Add the script
Set the site ID
Set
STICKYBEAK_SITE_IDin your production environment only. Copy the ID from Settings in the dashboard.Add a context processor
Context processors are plain (not
async) functions that take the request and return a dict.import os from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates from starlette.middleware.sessions import SessionMiddleware STICKYBEAK_SITE_ID = os.environ.get("STICKYBEAK_SITE_ID") # unset outside production def stickybeak(request: Request) -> dict: session = request.scope.get("session") return { "stickybeak_site": STICKYBEAK_SITE_ID, "stickybeak_goal": session.pop("stickybeak_goal", None) if session is not None else None, } app = FastAPI() app.add_middleware(SessionMiddleware, secret_key=os.environ["SESSION_SECRET"], https_only=True) templates = Jinja2Templates(directory="templates", context_processors=[stickybeak])SessionMiddlewareneeds theitsdangerouspackage. Skip it, and the session parts of this page, if you only want page views.Add it to your base template
Put this before
</head>:<script>window.stickybeak = window.stickybeak || function () { (window.stickybeak.q = window.stickybeak.q || []).push(arguments); };</script> {% if stickybeak_site %} <script defer data-site="{{ stickybeak_site }}" data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js" ></script> {% endif %} {% if stickybeak_goal %} <script>window.stickybeak({{ stickybeak_goal.name|tojson }}, {{ (stickybeak_goal.props or {})|tojson }});</script> {% endif %}
Render pages with the request first, as current Starlette expects: templates.TemplateResponse(request, "home.html", {...}).
Check it's working
Publish first, then follow Verify your install.
Track goals
Give any button or link a data-goal attribute. See Custom goals.
<button type="submit" data-goal="start_trial">Start trial</button>
Fire a goal after a redirect
When a form post succeeds, put the goal in the session and redirect. The context processor pops it on the next page.
from fastapi import Form
from fastapi.responses import RedirectResponse
@app.post("/signup")
async def signup(request: Request, email: str = Form(...), plan: str = Form("free")):
await create_user(email, plan)
request.session["stickybeak_goal"] = {"name": "signup", "props": {"plan": plan}}
return RedirectResponse("/welcome", status_code=303)
Track purchases
request.session["stickybeak_goal"] = {
"name": "purchase",
"props": {"revenue": str(order.total), "currency": "USD", "order_id": str(order.id)},
}
See Revenue.
If it isn't working
- Confirm the environment variable reaches Uvicorn or Gunicorn.
SessionMiddlewarealso needsitsdangerous.
See Troubleshooting.