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

# Verify your install

Run the Botscent check against your site, read each line, and fix what fails.

`npx botscent check` tests a Botscent install from outside. It requests your page, opens the page in a local Chrome, and reads your project. Run it at the end of every install, and again after each fix.

## 1. Start the site

Start the site that you installed Botscent in. A local server and a deployed site both work.

## 2. Run the check

From the project's directory, run the check against the URL of one page:

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

The check prints one line for each check, then a summary line.

## 3. Read the output

This output comes from a run against the Botscent site, which runs Next.js on Vercel:

```text title="Terminal"
botscent check 0.0.0: https://botscent.nibnalin.me/
PASS     reachable     200, text/html; charset=utf-8
PASS     server-half   entry 1;botscent-check;1790995621428;ua.declared-agent-token on check's own request
PASS     entry         fresh (+0.9 s) and single
PASS     no-store      Cache-Control: no-store
PASS     person        no entry on a request without agent evidence
PASS     cache         cached HTML (Age: 1335), decorated after the cache lookup
PASS     page-script   botscent 0.0.0 started 852 ms after navigation
PASS     page-verdict  agent [browser.webdriver-flag, ua.headless-chrome] under automation, as expected
PASS     transport     the page received 1;;1790995622694;ua.headless-chrome
PASS     probes        10 ok
PASS     csp           no policy
SKIPPED  script        no botscent.js tag; the page half is bundled, or absent
PASS     stack         Next.js; on Vercel
SKIPPED  adapters      not run inside a project (pass --project <dir>)
Installed.
```

Each line gives the outcome, the check id and what the check observed. A line that is not a pass also gives the likely cause and the fix.

The last line is `Installed.`, `Unverified: neither half could be confirmed.` or a `Broken:` line with the number of failed checks.

## 4. Fix each failure

If a line says `FAIL`, apply the fix that the line gives. Then run the check again. For the common failures, see [Common fixes](#common-fixes).

If a line says `UNKNOWN`, read its likely cause. At an origin server with the transport off, an `UNKNOWN` line for `server-half` is expected.

## What the check does

The check does 3 things, in this order:

1. It requests the page as a navigation, with the user agent `botscent-check/<version>`. Then it requests the page again at once, with an empty user agent. If a cache stored the first response, the cache serves the stored copy to the second request.
2. It opens the page in a local Chrome or Chromium over the DevTools protocol. It reads the page verdict, the page half's diagnostics, the `Server-Timing` entries, console errors and Content Security Policy violations.
3. It reads the project in the current directory, or in the directory that `--project` gives. It finds the frameworks and every `botscent` import. It compares a Next.js proxy or a Vercel middleware file with its version at git `HEAD`.

Chrome under the DevTools protocol sets the webdriver flag, as any automation does. So the page half reports an agent in the check's browser, with the reason `browser.webdriver-flag`. The `page-verdict` check expects this.

## Options

| Option            | What it does                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| `--origin <url>`  | Also requests the origin directly, to find a hop that removes `Server-Timing`.                   |
| `--project <dir>` | Reads this project. The default is the current directory, if it has a `package.json`.            |
| `--chrome <path>` | Drives this Chrome or Chromium. The default is a browser that the check finds, or `CHROME_PATH`. |
| `--no-browser`    | Skips the checks that need a browser.                                                            |
| `--json`          | Prints the checks as JSON.                                                                       |
| `--report`        | Adds a block to paste into an issue.                                                             |

## Outcomes

| Outcome   | Meaning                                                                                             |
| --------- | --------------------------------------------------------------------------------------------------- |
| `pass`    | The check observed what a working install gives.                                                    |
| `fail`    | The check observed a broken install. The line gives the likely cause and the fix.                   |
| `unknown` | The check cannot tell from outside whether the install is correct. The line gives the likely cause. |
| `skipped` | The check had nothing to test, for example because no browser was found.                            |

## The checks

The checks run and print in this order:

| Check          | What it tests                                                                                               |
| -------------- | ----------------------------------------------------------------------------------------------------------- |
| `reachable`    | The page answers with a status below 400. A challenge page from the site's own protection gives `unknown`.  |
| `server-half`  | The check's own request gets a `botscent` entry in `Server-Timing`, and the entry names `botscent-check`.   |
| `entry`        | There is one entry, and it was written between 10 s before and 120 s after the check's request.             |
| `no-store`     | The response that carries the entry also has `Cache-Control: no-store`.                                     |
| `person`       | The request with an empty user agent gets no entry.                                                         |
| `cache`        | If people get cached HTML, the cached HTML carries no `botscent` entry.                                     |
| `page-script`  | The page half is on the page and has started.                                                               |
| `page-verdict` | Under automation, the page verdict is `agent` with the reason `browser.webdriver-flag`.                     |
| `transport`    | The page received the entry from the server half.                                                           |
| `probes`       | No probe of the page half failed. A probe that the browser does not support is a pass.                      |
| `csp`          | The Content Security Policy blocked no Botscent script. It reports other blocked resources as context only. |
| `script`       | A `botscent.js` script tag loads from the site's own origin. It is `skipped` when the page half is bundled. |
| `stack`        | The framework and the platform that the check recognises.                                                   |
| `adapters`     | The project imports `botscent`, and an existing proxy was wrapped, not replaced.                            |

## Exit codes

| Code | Meaning                                                                          |
| ---- | -------------------------------------------------------------------------------- |
| `0`  | Installed. No check failed, and `server-half` or `page-script` passed.           |
| `1`  | Broken. At least one check failed.                                               |
| `2`  | Unverified. No check failed, and neither `server-half` nor `page-script` passed. |
| `64` | A usage error, such as a missing URL or an unknown option.                       |

## Output for scripts and agents

With `--json`, the check prints one JSON object. This sample shows only the first of the 14 checks:

```json title="Terminal"
{
  "check": "0.0.0",
  "url": "https://botscent.nibnalin.me/",
  "checks": [
    {
      "id": "reachable",
      "outcome": "pass",
      "observed": "200, text/html; charset=utf-8"
    }
  ],
  "exit": 0
}
```

Each check has `id`, `outcome` and `observed`, and can have `detail`, `cause` and `fix`. The `detail` field holds the page's own text, such as its error messages.

With `--report`, the check adds a block to paste into an issue. The block has the versions, the stack, the adapters, the Botscent entries and the diagnostics. It has no query string, cookie, address or `detail` text.

The option names, the JSON field names, the check ids, the outcomes and the exit codes stay the same across minor versions. The text of each line can change in any release.

## Common fixes

| Line                                        | Likely cause                                                                                                                   | Fix                                                                                                                                                         |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `UNKNOWN server-half` at an origin          | The transport is off. This is the default for Express, Astro, Hono on Node.js, Django, FastAPI, Flask and self-hosted Next.js. | If the server half is installed, no fix is needed. Your code still gets the request's own verdict. See [From the server to the page](/docs/server-to-page). |
| `FAIL page-script`: no botscent on the page | The page half is not loaded, or a script error stopped it.                                                                     | Import `botscent/auto` in the client entry, add `<Botscent />`, or add the script tag.                                                                      |
| `FAIL page-script`: never started           | Code imported the `botscent` entry and did not call `start`.                                                                   | Call `start` once in the browser, or import `botscent/auto`.                                                                                                |
| `SKIPPED page-script`                       | The check found no Chrome or Chromium.                                                                                         | Install Chrome, or pass `--chrome <path>`.                                                                                                                  |
| `FAIL entry`: 2 entries                     | Two adapters each add an entry, or a cache adds a stored one.                                                                  | Keep one server adapter on the path.                                                                                                                        |
| `FAIL no-store`                             | A later layer replaced the `no-store` that the adapter set.                                                                    | Keep `Cache-Control: no-store` on responses that carry a `botscent` entry.                                                                                  |
| `FAIL person`                               | A shared cache replays an agent's response, so people get an agent's entry.                                                    | Turn the transport off. Then run the adapter in front of the cache.                                                                                         |
| `UNKNOWN transport`                         | The page is on `http` and not on `localhost`, so the browser hides `Server-Timing`.                                            | Run the check against the `https` deployment.                                                                                                               |
| `FAIL csp`                                  | The Content Security Policy does not allow `botscent.js`.                                                                      | Allow the script's origin in `script-src`, or serve `botscent.js` from your own origin.                                                                     |
| `FAIL adapters`: replaced                   | An existing proxy or middleware was replaced, not wrapped.                                                                     | Restore the old file, and wrap its function with `withBotscent`.                                                                                            |
| `FAIL probes`                               | A script on the page broke a browser API that a probe reads.                                                                   | Run the check with `--report`, and open an issue with the report.                                                                                           |
| `FAIL page-verdict`                         | The webdriver probe did not find the flag.                                                                                     | Run the check with `--report`, and open an issue with the report.                                                                                           |

> **Warning:** If `person` fails, turn the transport off now. A cache serves an agent's entry to people, and their pages then report an agent.

## Related

* [`npx botscent check`](/docs/check): the full reference for the command.
* [From the server to the page](/docs/server-to-page): what the `Server-Timing` entry is, and when an adapter writes it.
* [Quickstart](/docs/quickstart): install Botscent with one prompt, or pick your framework.
* [Log verdicts for a week](/docs/log-verdicts): the first step once the check passes.
