> For an index of all Botscent documentation, see https://botscent.nibnalin.me/llms.txt.

# FastAPI and Starlette

Add the server half of Botscent to a FastAPI or Starlette app and check the install.

Add the server half of Botscent to a FastAPI or Starlette app. The server half runs as ASGI middleware from `botscent.asgi` and puts the request's own verdict on `request.state.botscent`. For the page half, see [A script tag](/docs/script-tag), [React](/docs/react), [Vue](/docs/vue) or the page for the framework your site uses.

## Before you start

You need:

* A FastAPI or Starlette app
* Python 3.11 or later

## 1. Install the package

Install `botscent` from PyPI.

```sh title="Terminal"
pip install botscent
```

With uv or poetry, use `uv add botscent` or `poetry add botscent`.

## 2. Add the server half

In `app.py`, add `BotscentMiddleware` to the app.

```python title="app.py"
from fastapi import FastAPI

from botscent.asgi import BotscentMiddleware

app = FastAPI()
app.add_middleware(BotscentMiddleware)
```

Every request now carries its own verdict on `request.state.botscent`.

In Starlette, use the same `add_middleware` call. In another ASGI framework, read the verdict from `scope["state"]["botscent"]`.

By default, the middleware does not send the verdict to the page. The app runs at the origin, and an origin cannot see whether a CDN in front of it stores HTML. The `transport=True` argument turns the sending on: `app.add_middleware(BotscentMiddleware, transport=True)`. For the details, see [From the server to the page](/docs/server-to-page).

> **Warning:** Do not set `transport=True` unless no shared cache stores your HTML. If a cache stores an agent's page and ignores `Cache-Control: no-store`, a person can get the agent's `Server-Timing` entry. If you are not sure, keep the default.

## 3. Add the page half

The server half reads only what each request declares. The page half finds agents that operate a browser, from inside the page. The page half comes from the npm package `botscent`.

If FastAPI sends your HTML, add `<script defer src="/botscent.js"></script>` to each page. Serve `node_modules/botscent/dist/botscent.js` at `/botscent.js` from your own origin. If a frontend framework renders your pages, add the page half there instead. The [Quickstart](/docs/quickstart) lists every framework.

## 4. Read the verdict

In a route, read `request.state.botscent`.

```python title="app.py"
from fastapi import FastAPI, Request

from botscent.asgi import BotscentMiddleware

app = FastAPI()
app.add_middleware(BotscentMiddleware)


@app.get("/verdict")
async def verdict(request: Request):
    return request.state.botscent
```

A request from `curl` to `/verdict` gets `{"type":"agent","agent_name":"curl","reasons":["ua.declared-agent-token"]}`.

To give an agent access, use `botscent.is_verified(request.state.botscent)`. Use no other field for access. See [The trust model](/docs/trust-model).

## 5. Check the install

Start the app. Then run the check against one of its pages.

```sh title="Terminal"
npx botscent check http://localhost:8000/
```

The `page-script` check prints `pass`, and the check exits with code 0. The `server-half` check prints `unknown`, because the transport is off at an origin. If a check fails, see [Verify your install](/docs/verify).

## Next steps

* [The verdict](/docs/verdict): what `type`, `agent_name` and `reasons` mean.
* [From the page to the server](/docs/page-to-server): read a page report with `botscent.read_report`.
* [Server API (Python)](/docs/python-api): every function of the Python package.
* [FastAPI example](https://github.com/nalinbhardwaj/botscent/tree/main/examples/fastapi): the tested FastAPI app.
