--- title: Fraud Prevention — Ad Fraud --- # Ad fraud This is a **scenario guide**. The core integration is unchanged — you load the [Web SDK](../web-sdk), read a [verdict](../verdict-reference), and pull data from the [Data API](../data-api) exactly as described in those pages. This page adds the few specifics that only the ad-fraud scenario needs. Ad fraud protection filters bot and invalid traffic out of paid campaigns, so advertisers and ad platforms pay for genuine clicks and impressions — not fake volume. What makes it different from the other use cases is that **a third party delivers the visitor**, and both sides need to settle on an independent, per-click human / bot conclusion. ## Real-time blocking at the source Fraud Prevention runs inline at the entry point and returns a verdict in real time — it is not an after-the-fact report. Whoever owns the page the visitor lands on can act on that verdict immediately: - **Advertisers** run the SDK on the landing page: invalid traffic is caught — and optionally challenged — the moment it arrives, before it enters the funnel or distorts reporting. - **Traffic platforms** run the SDK on their own pre-lander or redirect page: a click is verified *before* it is forwarded, so bots are stopped at the entry and never become delivered traffic. The only requirement is a page that can run the SDK: a verdict needs browser signals, so a pure server-side 302 has nowhere to collect them — add a lightweight interstitial and the same real-time block applies. The signed click token and Data API sit on top for reconciliation across both sides; real-time inline blocking is the primary mechanism, and post-hoc API scrubbing is the fallback for traffic with no interstitial. ## The two roles - **Advertiser** — owns the landing page the visitor arrives on. Runs the Web SDK on that page to get a verdict for each arriving visit, and pulls verdicts from the Data API to reconcile what it was billed for. - **Provider** (traffic / ad source) — delivers the click. It needs to **prove the quality of what it sent**, so it issues a click token per click and later joins its delivery report against the independent verdicts. Both sides authenticate to the [Data API](../data-api) with their own application credentials and read the same per-click verdict, which is what lets them reconcile without trusting each other's raw logs. ## End-to-end flow The sequence below shows how one click travels from the provider's delivery, through the visitor and the advertiser's landing page, to a single verdict that **both accounts later read from their own side**. ```mermaid sequenceDiagram autonumber participant P as Provider (account B) participant V as Visitor participant A as Advertiser page + SDK participant F as Fraud Prevention API P->>P: Sign click_token (bot_kid + secret, carries pkid) P->>V: Deliver link with ?_ctk=click_token V->>A: Click → land on advertiser page (URL carries _ctk) A->>A: SDK reads _ctk from the URL A->>F: Encrypted POST /bot/verify
(app_key = advertiser, click_token = provider-signed) F->>F: app_key → advertiser_app_id,
verify pkid → provider_app_id, reach a verdict,
write one row carrying both app_ids F-->>A: verdict → onVerdict A->>A: Handle per verdict.action (record / block / challenge) Note over P,F: Reconciliation (cross-account) A->>F: GET /v1/bot with advertiser App-Key F-->>A: Same row (matched on advertiser_app_id) P->>F: GET /v1/bot with provider App-Key F-->>P: Same row (matched on provider_app_id) ``` The decisive property: **both app_ids live on the same row.** The advertiser reads it matched on `advertiser_app_id`, the provider reads it matched on `provider_app_id` — two different accounts, each querying with its own App-Key, each landing on the same independent verdict. Neither side has to expose or trust the other's raw logs to agree on what happened for a given click. ## Click tokens A **click token** ties a provider's delivered click to the verdict the visit ultimately receives. It is the per-click identifier that both parties settle on. The other Fraud Prevention use cases don't need click tokens — they reconcile verdicts without them. The flow: 1. **Issue** — the provider obtains a signed click token (one per click) when it routes a visitor toward the advertiser's landing page. 2. **Carry it on the destination URL** — append the issued token to the landing URL as a query parameter: ``` https://advertiser.example/lp?click_token=ct_xxxxxxxx ``` 3. **Read it on the page** — the [Web SDK](../web-sdk) reads the token from the URL automatically. If you use a different parameter name, set `tokenParam`: ```js BotSignal.init({ appKey: 'YOUR_APP_KEY', tokenParam: 'click_token' }); ``` 4. **Reconcile** — look the click up later via the Data API and join it back to the provider's delivery report. ::: info The token is already signed when it is issued to you — you only need to **carry it through to the landing URL**. There is nothing to sign or compute on your side. ::: ### `tokenParam` option The Web SDK gains one extra option in this scenario: | Option | Type | Default | Description | | --- | --- | --- | --- | | `tokenParam` | string | auto-detected | Name of the URL query parameter that carries the provider click token (e.g. `click_token`). The SDK reads it from the page URL and ties the verdict to that click. Leave unset if you don't use click tokens. | ## Reconciliation & settlement Once visits carry a click token, both sides settle on the same independent verdicts: - **Fetch a single click's verdict** — for example to dispute or confirm one click: ```bash GET /v1/bot/verdict?click_token=ct_xxx X-App-Key: YOUR_APP_KEY X-App-Secret: YOUR_APP_SECRET ``` - **Export per-click rows** — pull a time range and join each row's `click_token` back to your own click logs: ```bash GET /v1/bot/export?from=2026-06-01&to=2026-06-30&format=csv X-App-Key: YOUR_APP_KEY X-App-Secret: YOUR_APP_SECRET ``` Each row carries the visit's `click_token` (when present), timestamp, and verdict fields (`is_bot`, `score`, `level`, `action`). The advertiser excludes flagged and bot clicks from what it pays for; the provider reconciles its delivery report against the same conclusions. Because both read the **same independent verdict**, settlement does not depend on either side's raw logs. ## Next steps - [Web SDK](../web-sdk) — collect verdicts on the landing page - [Verdict Reference](../verdict-reference) — every field and how to act on it - [Data API](../data-api) — pull and reconcile verdicts server-side