From the page to the server
How your code sends the page verdict to your server, and how the server keeps it apart.
A page report is the page verdict, sent by your code to your own server. The page half sends nothing on its own. Your code chooses a carrier, and the server reads the report with readReport.
import { reportHeaders } from 'botscent'
export async function checkout() {
return fetch('/api/checkout', { method: 'POST', headers: { ...reportHeaders('/api/checkout') }, body: 'cart=1' })
}The carriers
Botscent has 3 carriers. Each carrier reads the page verdict at the moment your code sends it.
| Carrier | Use it for | What the server gets |
|---|---|---|
reportHeaders(url) | A fetch that your code sends | A Botscent-Report header |
data-botscent-field | A POST form that the browser submits | A botscent form field |
| An argument | A server function that your code calls | The verdict object |
A header for fetch
reportHeaders returns { 'Botscent-Report': <entry> } when two things are true. The page verdict is an agent, and url is on the page's own origin. In every other case, it returns {}. So a person's requests do not change, and no report goes to another origin.
Spread the headers into the request, as in the example above. With the script tag, use window.botscent.reportHeaders.
A field for forms
Add data-botscent-field to a form, or to an element inside the form:
<form method="post" action="/checkout" data-botscent-field>
<input name="cart" value="1" />
<button>Check out</button>
</form>The form gets a botscent field only on its own submission: a click, Enter, or requestSubmit. All of these must also be true:
- No listener canceled the
submitevent. - The page verdict is an agent.
- The method is
POST. A submit button'sformmethodcounts. - The action is on the same origin. A submit button's
formactioncounts.
A call to form.submit and a new FormData(form) never get the field, because their data can go anywhere. A form that a submit listener reads while the event is still in progress does not get the field either. If your code sends a form's data with fetch, use reportHeaders(url). Botscent writes nothing to the DOM.
An argument
Pass the object that verdict returns to a server function that your code calls. On the server, pass the object to readReport. readReport checks the object against the same format as the header.
On the server
Read the report, and keep it apart from the request's own verdict:
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'))
return Response.json({ request: own, report, combined: combine(own, report) })
}The response holds 3 verdicts: what the request declared, what the page reported, and the two joined.
readReport returns null for a value that is malformed, longer than 256 bytes, or of an unknown major version. Each reason of a parsed report gets the page. prefix, for example page.claude.marker.active. So a report never passes isVerified.
For a form, your code parses the body and passes the botscent field to readReport. Botscent never reads a request body. In Python, use botscent.read_report and botscent.combine.
How combine joins the two
combine(own, report) adds the report's evidence to the request's own verdict:
- The joined verdict is an agent when either verdict is an agent.
- Its reasons are the request's reasons, then the report's reasons.
- Its name is the request's name. If the request has no name, it is the report's name.
- A missing or empty report returns the request's own verdict unchanged.
Use the joined verdict to measure agent traffic and to adapt what you show.
Warning: Do not use a page report or a joined verdict to allow access. Scripts on the page can forge a report. Use
isVerifiedon the request's own verdict.
What a report does not carry
- It carries no observed value. It holds only the format version, the agent name and the reason ids.
- It is not sent for a person.
reportHeadersreturns{}, and the form gets no field. - It does not go to another origin.
- It does not say who performed the action that sent it.
When a report leaves the device, your site collects it. See Privacy.
Related
- The trust model: why a page report is not fit to decide access.
- Page API: the signature of
reportHeadersand the other page functions. - Server API (TypeScript):
readReport,combineandisVerified.