Anti-fraud and anti-bot API

KillBot offers two APIs you can use:

  • Pay-per-client API. This option is for partner providers. A partner provider gets a manager account in KillBot where they can manage their own clients (create accounts, assign subscriptions, and so on). Subscription pricing in this model is 50% of the public rates. You can integrate KillBot into your service with a button that opens each user’s personal KillBot dashboard. To get a manager account, contact support.
  • Pay-per-request API (only requests classified as human users are billed). This is a JS API for programmatically checking whether a visit belongs to a real user or a bot. You can embed it in your own anti-fraud system or any other product.

Pay-per-request API for commercial use (API plan)

If you want to integrate KillBot’s bot-detection algorithms into your own product, use the API below.

Sample API response datahttps://my.kill-bot.net/snpsht.html - a live JS demo. Open the page source and copy the code you need.

How it works

You integrate KillBot by placing JS code on your site. The code collects browser data and sends it to KillBot servers. You can get the check result in two ways:

  • Recommended: the kbDataReceived event — the result is delivered automatically after processing;
  • Alternative: a GET request to /r/get.php with the session ID.

Data collection is done by loading /js/cn.js from one of the KillBot servers. The script sends data in several requests; total payload size is about 5–15 KB.

The KillBot script does not collect personal data, form input, or request access to the microphone, geolocation, camera, or other identifying device APIs.

Important: for stable operation, the page running KillBot must be served over HTTPS.

Simplest option: load cn.js only (no waiting for the result). You can fetch the result within 5 minutes.

If you don’t need the result immediately in JS, just load cn.js. It will collect and send browser data to KillBot on its own. You can request the check result later via get.php whenever you need it.

You must request the bot-check result within 300 seconds (5 minutes) after sending the data. After that, KillBot will no longer return the result for that session.

const kbKey = 'YOUR_KEY'; /* your KillBot dashboard key */

const kbUserID = Math.floor(Math.random() * 900000000);
const kbSessionID = (Date.now() * 10000) + (Math.floor(Math.random() * (99999 - 10000)) + 10000);

const s = document.createElement('script');
s.async = true;
s.src = 'https://data.killbot.ru/js/cn.js?hash_str=' + encodeURIComponent(kbKey)
    + '&r=' + btoa(document.referrer || '')
    + '&url=' + btoa(location.href)
    + '&c=' + kbSessionID
    + '&kbUserID=' + kbUserID
    + '&v=0&rmd' + Math.random();
document.head.appendChild(s);

// Save kbSessionID and kbUserID (cookie / localStorage / server) —
// you can later fetch the result via get.php using kbSessionID

When you need the result, send a GET request (from JS or your backend):

// kbSessionID — same value you passed to cn.js as parameter c=
fetch('https://data.killbot.ru/r/get.php?waf=1&c=' + kbSessionID)
    .then(function(r) { return r.json(); })
    .then(function(data) {
        if (data.error) {
            console.log('error:', data.m);
            return;
        }
        if (data.l === false) {
            console.log('data not ready yet, retry in 1–2 sec');
            return;
        }
        console.log('bot:', data.bot, 'snsht:', data.snsht, data);
    });

If l === false or the response is empty, processing is still in progress — retry in 1–2 seconds (usually 2–5 attempts are enough).

Which option to use:

  • cn.js + get.php only — minimal code; you can fetch the result with a delay, but within 5 minutes;
  • cn.js + kbDataReceived — you need the result immediately in JS;
  • fetch + server selection + kbDataReceived — production setup with fallback when servers are blocked (see full example below).

Full example: pick the fastest available server + kbDataReceived

Recommended integration flow:

  1. Pick the fastest available server from the list (request /ping);
  2. Load cn.js via fetch and run it as an inline script (not <script src> — more reliable when external scripts are blocked);
  3. If loading fails, switch to the next server in the list;
  4. Handle the result in the kbDataReceived event listener.
const kbKey = 'YOUR_KEY'; /* KillBot dashboard key — the kbKey parameter in your KillBot JS integration code */

const kbServers = [
    'https://10052024.ru',
    'https://r1.kill-bot.ru',
    'https://data.killbot.ru',
    'https://r3.nl.kill-bot.ru',
    'https://r4.us.kill-bot.ru',
    'https://r6.sg.kill-bot.net'
];

const kbSliderTimeout = 5000;
let kbServerURL = '';
let kbRes = null;

async function kbGetFastestServer(servers) {
    return new Promise(function(resolve) {
        let resolved = false;
        const fallback = 'https://data.killbot.ru';
        let pending = servers.length;

        servers.forEach(function(url) {
            const ctrl = new AbortController();
            const t = setTimeout(function() { ctrl.abort(); }, 6000);

            fetch(url + '/ping', { cache: 'no-store', mode: 'cors', signal: ctrl.signal })
                .then(function(r) {
                    if (!resolved && r.status === 200) {
                        resolved = true;
                        resolve(url);
                    }
                })
                .catch(function() {})
                .finally(function() {
                    clearTimeout(t);
                    pending--;
                    if (!resolved && pending <= 0) resolve(fallback);
                });
        });

        setTimeout(function() {
            if (!resolved) resolve(fallback);
        }, 6050);
    });
}

function kbFireTimeout() {
    setTimeout(function() {
        if (kbRes != null) return;
        document.dispatchEvent(new CustomEvent('kbDataReceived', {
            detail: JSON.stringify({ error: true, m: 'timeout' })
        }));
    }, 2 * kbSliderTimeout + 5000);
}

document.addEventListener('kbDataReceived', function(event) {
    if (kbRes != null) return;
    try {
        if (event.detail) kbRes = JSON.parse(event.detail);
    } catch (e) {
        kbRes = null;
    }
    // Handle kbRes: bot, fraud, snsht, waf, etc.
    console.log('KillBot result:', kbRes);
});

(async function kbStart() {
    kbServerURL = await kbGetFastestServer(kbServers);

    const kbUserID = Math.floor(Math.random() * 900000000);
    const kbSessionID = (Date.now() * 10000) + (Math.floor(Math.random() * (99999 - 10000)) + 10000);

    kbFireTimeout();

    const uri = '/js/cn.js?hash_str=' + encodeURIComponent(kbKey)
        + '&p=' + btoa('')
        + '&r=' + btoa(document.referrer || '')
        + '&url=' + btoa(location.href)
        + '&c=' + kbSessionID
        + '&kbUserID=' + kbUserID
        + '&v=0&rmd' + Math.random();

    fetch(kbServerURL + uri)
        .then(function(r) { return r.text(); })
        .then(function(text) {
            const s = document.createElement('script');
            s.text = text;
            s.id = 'kb-c';
            document.head.appendChild(s);
        })
        .catch(function(e) {
            document.dispatchEvent(new CustomEvent('kbDataReceived', {
                detail: JSON.stringify({ error: true, m: e.message || 'cn.js load failed' })
            }));
        });
})();

Live demo page with the full version (server fallback, pretty-print JSON, field descriptions): https://killbot.ru/snpsht.html — open the page source and copy what you need.

 

Alternative: fetch the result via get.php

For extra safety, you can also verify the final response on your backend — in theory a bot could fake a JS response, but in practice behavioral bots rarely do this; we haven’t seen such cases in production.

You can poll the result with a GET request:
https://data.killbot.ru/r/get.php?c={{kbSessionID}}

Below is a JS example that polls for the result.

const kbTimeout = 2000;
const kbMaxRequests = 10;
let response = null;
let requestCount = 0;

function makeRequest() {
    if (requestCount >= kbMaxRequests) {
        response ? complete(response) : fail();
        return;
    }

    requestCount++;
    const xhr = new XMLHttpRequest();
    xhr.open('GET', kbServerURL + '/r/get.php?c=' + kbSessionID, true);
    xhr.timeout = 15000;

    xhr.onreadystatechange = function() {
        if (xhr.readyState !== 4) return;
        if (xhr.status === 200) {
            try {
                response = JSON.parse(xhr.responseText);
                if (!response || response.error === true || response.l === false) {
                    setTimeout(makeRequest, kbTimeout);
                } else {
                    complete(response);
                }
            } catch (e) {
                setTimeout(makeRequest, kbTimeout);
            }
        } else {
            setTimeout(makeRequest, kbTimeout);
        }
    };

    xhr.send();
}

function complete(response) {
    // success
}

function fail() {
    // error / timeout
}

 

Example server response

{
    "bot": false,          // check result: true = bot / suspicious visit
    "fraud": false,        // same as bot
    "l": true,             // script fully loaded and all fingerprints collected
    "bl": false,           // snapshot is in the bot blacklist
    "wl": true,            // snapshot is in the known-browser whitelist
    "d": false,            // deny: true = block access to the site
    "capt": 0,             // captcha: 0=none; 1=captcha; 2=slider; 3/31=alert; 4=hang; 6=deny
    "snsht": 2969538378,   // main browser snapshot (999999 = grouped bot)
    "net_id": 2696850341,  // network fingerprint ID
    "net_t": "home",       // network type: home, mob, corp, vpn
    "os": "Windows",       // visitor OS
    "sess": "45786830545786830",   // session ID (kbSessionID)
    "UserID": "468073784468073784", // user ID (kbUserID)
    "ip": "51.158.237.65", // visit IP
    "t": true,             // show analytics: false = do not load tracking code
    "act": "1",            // subscription is active
    "cv": "abc123...",     // checksum for server-side response verification
    "metr": "44537875",    // Yandex Metrika counter ID (if configured)
    "utm": "is_bot",       // URL parameter name for passing the check result (from settings)
    "url": "",             // redirect URL (if set by a WAF rule)
    "waf": { /* see below */ }
}

 

WAF data

Use these fields to build filtering rules:

killbot:
  UserID: 429434077125846125      // unique user ID
  UserID2: 429434077125846125     // alternate ID (cross-check)
  bot: false                       // is this visit a bot?
  capt: 0                          // captcha type for this visit (see capt above)
  metr: true                       // show analytics tracking
  deny: false                      // block access
  man_act: true                    // manual action configured for this snapshot
  solved_early: false              // previously solved captcha on this site
  solved_early_killbot: false      // previously solved captcha in KillBot network
  vpn: false                       // VPN / proxy detected
  snsht: 65519223                  // browser snapshot
  snsht_org: 695851122             // original snsht before bot grouping
  net_id: 3957945795               // network fingerprint ID
  net_t: home                      // home = residential; mob = mobile; corp = corporate
  bl: false                        // snapshot in blacklist
  wl: true                         // snapshot in whitelist
  ffp: 3329686866                  // font fingerprint
  host: data.killbot.ru            // server that processed the request
  adt: false                       // anti-detect / spoofing signals
  not_solved: false                // often sees captcha but rarely solves it
  shows_count: 8                   // how many times captcha was shown to this UserID
  solved_count: 0                  // how many times this UserID solved captcha
  new_user_killbot: true           // new UserID in KillBot
  new_user_website: true           // new UserID on this site
  tm: 0                            // processing time (sec)
user:
  timezone: Asia/Novosibirsk        // browser timezone
  locale: ru                        // browser locale
net:
  ip: 94.237.108.10                // user IP
  host: 94-237-108-10.example.host // reverse DNS
  asn: 202053                      // ASN
  country: FI                      // country by IP
  ports: []                        // open ports (WebRTC scan)
  ping: true                       // IP responds to ping
  ttlOS: Linux                     // OS guessed from TTL
  ttl: 54
  ttl_b: 52
  rtt: 93.25                       // round-trip time (ms)
request:
  user-agent: Mozilla/5.0 ...
  accept-language: ru-RU,ru;q=0.9
  url: https://example.com/page    // URL where KillBot was called
  referer:                         // referer
browser:
  name: Chrome
  language: ru-RU
  webdriver: false                  // true = automation (bot)
  innerheight: 919
  innerwidth: 1920
  outerheight: 1040
  outerwidth: 1920
device:
  width: 1920
  height: 1080
  os: Windows
  gc: ANGLE (NVIDIA, ...)           // GPU / WebGL renderer
  fps: 63                          // FPS (requestAnimationFrame)

 

Error response

{
    "error": true,
    "error_code": 100,   // 100 = session not found; 200 = other error
    "m": "KillBot session does not exist kbSessionID=255483105"
}