# Flask and FastAPI

Add ProductLense to a Flask or FastAPI site in the Jinja2 base template, then identify the signed-in user with the tojson filter.

Flask and FastAPI both render HTML with Jinja2 templates. Put the script in the base template that other pages extend, and every page carries it. If your FastAPI app only serves an API to a separate frontend, follow the guide for that frontend instead, such as [React (Vite)](/docs/install/react).

## Add the script

Replace `SITE_ID` with the id from Settings → Sites in the ProductLense dashboard.

```html title="templates/base.html" {5-6}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script>window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
    <script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
    <title>{% block title %}{% endblock %}</title>
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>
```

In FastAPI, render pages with `Jinja2Templates(directory="templates")` and `templates.TemplateResponse(request, "page.html", context)` so they extend the same base.

## Identify users

Jinja2's `tojson` filter escapes the value for use inside a script block:

```html title="templates/base.html" {3}
{% if user_id %}
  <script>
    window.productlense('identify', String({{ user_id|tojson }}));
  </script>
{% endif %}
```

Pass `user_id` from the view: in Flask with Flask-Login, `current_user.get_id()` when `current_user.is_authenticated`; in FastAPI, from whatever dependency resolves the signed-in user. Place the block after the queue stub. Use the same id you store on the customer in your billing provider; see [how payments are attributed](/docs/revenue/attribution).

## Events from your server

Actions that happen only on the server, such as a background task that converts a trial, can be sent to the Events API with an API key. API keys are on the Scale plan; see [server-side events](/docs/install/server-side-events).

## Verify your installation

1. Deploy, then open your site in a normal browser window.
2. Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds.
3. In the browser's developer tools, the Network tab shows a `POST` to `https://api.productlense.app/api/e` with status `204`.

During development, open `flask run` or `uvicorn` at `localhost`, where nothing is sent unless you add `data-dev="true"` to the tag. The script skips only the hostname `localhost`; events from `127.0.0.1` are sent and then rejected, because that host is not on the site's list. Ad blockers in your own browser may block the request. If the visit does not appear, follow [Verify your installation](/docs/install/verify).
