Stickybeak Docs Dashboard Get early access

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

  1. Set the site ID

    Set STICKYBEAK_SITE_ID in your production environment only. Copy the ID from Settings in the dashboard.

  2. 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])

    SessionMiddleware needs the itsdangerous package. Skip it, and the session parts of this page, if you only want page views.

  3. 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. SessionMiddleware also needs itsdangerous.

See Troubleshooting.