Collector API
The collector exports four functions. With npm, import them from @octetproof/collector. With the script tag, they are properties of the global octet.
import { start, ready, settled, verify } from '@octetproof/collector';
start(config)
start(config: CollectorConfig): void
Begins a collection in the background and returns at once. Call it at page load. Calling start() again replaces the configuration, discards any stored result, and begins a new collection.
Throws at once if config.challenge is missing, if config.apiUrl is not a valid https:// URL, or if config.mode is not 'full', 'lite' or 'passive'. See CollectorConfig.
ready()
ready(): Promise<ReadyResult>
Resolves once your edge has passed the latest collection to Octet, which means your backend can fetch the verdict. Call it at the moment of action.
- If the collection that
start()began is still running,ready()waits for it. - If that collection finished less than 90 seconds ago,
ready()resolves at once with its result. - Otherwise,
ready()needs a new collection. The challenge fromstart()has already been sent, soready()rejects withoctet: this challenge was already used. Get a new challenge from your backend and callstart()with it.
With the early verdict, ready() resolves once the first of the collection's two reports is in, and your backend can fetch the provisional verdict. Call settled() before the page navigates away.
Rejects if start() was never called, if the POST to your edge fails, or if the collection was aborted. A failed collection is not stored. If the collection finished, its challenge counts as used, even if the POST never started, so call start() with a new challenge before the next ready().
settled()
settled(): Promise<void>
Resolves once the collector has finished sending the latest collection, whether it succeeded or failed, or at once if it already finished. It carries no result and starts nothing. Using it is optional. If your page navigates away soon after a collection, for example when the login form submits, await settled() first so the browser doesn't cancel a report still on its way. It matters most for a license with the early verdict, where the second report is sent after ready() resolves. Since v1.9.1.
Rejects with octet: call start() before settled() if start() was never called. verify() resolves after everything is sent, so it doesn't need settled().
verify(config)
verify(config: CollectorConfig): Promise<EdgeReply>
Runs one collection and resolves with your edge's reply. With the early verdict, it resolves after both reports. It stores nothing, so each call collects again and needs a new challenge. Use it where there is no separate moment of action. It rejects at once for a missing challenge or an invalid apiUrl or mode, and later if the challenge was already used, if the POST to your edge fails, or if the collection is aborted.
CollectorConfig
| Field | Type | Required | Description |
|---|---|---|---|
apiUrl |
string |
Yes | Your edge's origin, for example https://octet.example.com. Must be https://. http:// is accepted only for localhost, 127.0.0.1 and [::1]. |
sessionRef |
string |
Yes | The unguessable reference your backend created for this page view. Your backend fetches the verdict with it. |
challenge |
string |
Yes | The one-time challenge your backend got from Octet for this sessionRef with POST /v1/challenge. Each challenge works for one collection, within 10 minutes. See Get a challenge. |
mode |
'full' \| 'lite' \| 'passive' |
No | How much network measurement to do. The default is 'full'. See Modes. |
wsUrl |
string |
No | The WebSocket URL for your edge. The default is apiUrl with https replaced by wss, plus /v1/ws. Set it only if your edge's WebSocket has a different address. |
signal |
AbortSignal |
No | Cancels the collection. See Cancelling. |
cspNonce |
string |
No | Your page's CSP nonce, if your script-src uses one. Base64 or base64url characters, at most 256. Without it, or if the value isn't valid, the collector uses the nonce of a script already on the page. Since v1.8.0. See Network and CSP. |
Modes
| Mode | What it does | Network requests beyond your edge |
|---|---|---|
full |
Everything, for the strongest results | HTTPS and UDP 3478 to three Octet network hosts |
lite |
Skips the HTTPS requests to the Octet network hosts | UDP 3478 to three Octet network hosts |
passive |
No network measurement and no WebRTC | None |
No mode shows a permission prompt. The hosts are listed in Network and CSP.
ReadyResult
| Field | Type | Description |
|---|---|---|
response |
EdgeReply |
Your edge's reply to the POST. |
issuedAtMs |
number |
When the edge replied, in milliseconds since the Unix epoch. |
expiresAtMs |
number |
When ready() stops reusing this result, in milliseconds since the Unix epoch. issuedAtMs plus 90 seconds. |
elapsedMs |
number |
Milliseconds from the start of collection to the edge's reply. |
EdgeReply
In production your edge always replies with:
{ "ok": true }
The reply never contains the verdict. Your backend fetches it. See Fetch the Verdict. Only the testing setting EDGE_EXPOSE_VERDICT changes this reply. See Edge Configuration.
Cancelling
Pass an AbortSignal in the configuration. Aborting stops the collection and cancels the POST to your edge if it has started. ready() or verify() then rejects with the signal's abort reason, which is a DOMException named AbortError unless you pass your own reason to abort(). If the abort comes before the POST reaches your edge, no verdict is produced for that collection.
const controller = new AbortController();
octet.start({ apiUrl: 'https://octet.example.com', sessionRef, challenge, signal: controller.signal });
window.addEventListener('pagehide', () => controller.abort());
Errors
| Thrown or rejected with | When |
|---|---|
Error: octet: `challenge` is required. … |
challenge is missing or empty. Thrown by start(), rejected by verify(). |
Error: octet: this challenge was already used. … |
The collector already sent this challenge. Rejected by ready() or verify(). Get a new challenge and call start() or verify() with it. |
Error: octet: invalid apiUrl "…" |
apiUrl is not a URL. Thrown by start(), rejected by verify(). |
Error: octet: apiUrl must be https://… |
apiUrl uses another scheme. Thrown by start(), rejected by verify(). |
Error: octet: unknown mode "…" |
mode is not 'full', 'lite' or 'passive'. Thrown by start(), rejected by verify(). |
Error: octet: the collector needs a secure context (https) for crypto.subtle |
The page isn't served over HTTPS or from localhost, 127.0.0.1 or [::1]. |
Error: octet: call start() before ready() |
ready() was called before start(). |
Error: octet: call start() before settled() |
settled() was called before start(). |
Error: signal report failed: <status> |
Your edge answered the POST with an error status. See Errors. |
TypeError from fetch |
The POST to your edge failed at the network level, for example because of CORS or DNS. |
DOMException named AbortError, or your own abort reason |
The collection was aborted. |
A measurement that fails or is blocked never causes an error. The collector leaves it out and sends the rest.