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

# Log verdicts for a week

Log the verdict of each page load on your server for a week, and change nothing for visitors.

Log the verdict of each page load for a week before you act on it. After the week, you know which agents visit, how often, and which pages they read.

Visitors see no change. The log uses both halves, because each half sees different agents. The server half sees agents that sign or declare their requests, such as ChatGPT and Devin. The page half sees agents that operate a person's own browser, such as Claude for Chrome.

## Before you start

* Install both halves of Botscent. See [Next.js](/docs/nextjs), or pick your framework in the [Quickstart](/docs/quickstart).
* Find where your server's logs go. Each line that this guide adds is one JSON object, written with `console.log`.

## 1. Log the request's own verdict

In `proxy.ts`, wrap a logging function with `withBotscent`. The function logs one line for each GET request that asks for HTML, that is for each page load.

```ts title="proxy.ts"
import { NextResponse, type NextRequest } from 'next/server'
import { withBotscent } from 'botscent/next'
import { inspect } from 'botscent/server'

async function logPageLoad(request: NextRequest) {
  const accept = request.headers.get('accept') ?? ''
  if (request.method === 'GET' && accept.includes('text/html')) {
    const verdict = await inspect(request)
    console.log(JSON.stringify({ time: new Date().toISOString(), kind: 'request', path: request.nextUrl.pathname, ...verdict }))
  }
  return NextResponse.next()
}

export const proxy = withBotscent(logPageLoad)
```

Every page load now writes the request's own verdict to your server's log.

If `proxy.ts` already wraps a function, add the logging lines to that function. Scripts, images and API calls do not ask for HTML, so they write no line. A click on a Next.js `Link` loads no new document, so it writes no line either.

## 2. Send the page verdict to your server

In a client component, send one request to your server when the page verdict first becomes `agent`. [`reportHeaders`](/docs/page-api#reportheaders) adds the page report to the request.

```tsx title="app/visit-log.tsx"
'use client'
import { diagnostics, reportHeaders, subscribe, verdict, type Verdict } from 'botscent'
import { useEffect } from 'react'

export function VisitLog() {
  useEffect(() => {
    let sent = false
    const send = (current: Verdict) => {
      if (current.type !== 'agent' || sent) return
      sent = true
      void fetch('/api/visit', {
        method: 'POST',
        headers: { 'content-type': 'application/json', ...reportHeaders('/api/visit') },
        body: JSON.stringify({ path: location.pathname, transport: diagnostics().transport }),
      })
    }
    send(verdict())
    return subscribe(send)
  }, [])
  return null
}
```

Render `<VisitLog />` once in `app/layout.tsx`. A person's page sends no request, because its page verdict stays `human`.

The page verdict can become `agent` minutes after load. An extension agent, such as Claude for Chrome, shows its evidence only when it acts. [`subscribe`](/docs/page-api#subscribe) calls `send` at that moment.

## 3. Log the page report

In a route handler, read the page report with [`readReport`](/docs/server-api#readreport). Join the report to the request's own verdict with [`combine`](/docs/server-api#combine).

```ts title="app/api/visit/route.ts"
import { combine, inspect, readReport } from 'botscent/server'

export async function POST(request: Request) {
  const own = await inspect(request)
  const report = readReport(request.headers.get('botscent-report'))
  const { path, transport } = await request.json()
  console.log(JSON.stringify({ time: new Date().toISOString(), kind: 'page', path, ...combine(own, report), request: own.type, transport }))
  return new Response(null, { status: 204 })
}
```

Each page where the page half sees an agent now writes a `page` line.

The `request` field holds the type of the request's own verdict. The `transport` field says whether the page got the server's verdict in a `Server-Timing` entry. See [From the server to the page](/docs/server-to-page). [Measure agent traffic](/docs/measure) uses both fields to count each visit once.

## 4. Read the log after a week

After a week, read the log for 3 things:

* Which agents visit: each `agent_name`, and the agent lines that have no name.
* How many page loads come from agents, as a share of all page loads.
* Which pages each agent reads.

Each count of agents is a floor, not an exact count. `human` means that Botscent saw no agent evidence. So an agent that shows no evidence counts as a person.

Keep the `reasons` of each line. They show which evidence found each agent.

## Result

Your server's log now has one `request` line for each page load. It also has one `page` line for each page where the page half saw an agent:

```text title="Server log"
{"time":"2026-10-03T09:12:44.120Z","kind":"request","path":"/pricing","type":"agent","agent_name":"chatgpt","reasons":["signer.web-bot-auth.verified"]}
{"time":"2026-10-03T09:13:02.871Z","kind":"request","path":"/docs","type":"human","reasons":[]}
{"time":"2026-10-03T09:13:31.406Z","kind":"page","path":"/docs","type":"agent","agent_name":"claude-chrome","reasons":["page.claude.marker.active"],"request":"human","transport":"absent"}
```

## Next steps

* [Measure agent traffic](/docs/measure): turn the log into counts per agent and per page.
* [Adapt the page for agents](/docs/adapt): change what agents see, after you know who they are.
* [The verdict](/docs/verdict): what `type`, `agent_name` and `reasons` mean.
* [Privacy](/docs/privacy): what your site collects when a page report leaves the page.
