How to Create Traffic Filtering Rules [WAF] Based on Visit Data

Filtering Rules: Full Control Over Traffic

Traffic filtering in KillBot is possible not only through browser snapshots, but also through flexible filtering rules that can be created manually. This gives you full control over filtering logic and allows you to configure protection according to your real needs. Rules can use browser parameters, KillBot parameters, user IP information, and other data to perform the required action (block, show captcha, create a loop, hide analytics).

Attention!
Rules are executed specifically on the verification page (KillBot Screen). This means that the user first reaches the verification page (the rotating blue circle), and only then the rule is executed (on the JavaScript level). If you need the verification page not to appear at all (for example, for payment system callbacks), use the script settings: IP whitelist, user-agent whitelist, and the list of pages where protection is completely disabled.

Where Can I Find Parameters for Creating Rules?

All important parameters can be viewed in the KillBot interface. To do this, open the "Visits" section and move the mouse over the "?" icon located in the data column:

Open visits in KillBot

The data in KillBot is presented in JSON format. The data is grouped into "blocks" with parameters and their values:

KillBot visit parameters

 

Example of Data Used for Creating a Rule:


{
    "killbot": {
        "UserID": "387619204031415763",  /*UserID - pseudo-unique user identifier. If user_pop=true, the user is not unique enough*/
        "bot": true, /*bot=true if the browser snapshot snsht is not found in system browsers (green browsers, wl=false)*/
        "capt": false, /*whether captcha was shown*/
        "solved_early": true, /*whether captcha was solved before for this UserID*/
        "metr": false, /*if false, analytics code is hidden. If true, analytics code is added to the website*/
        "deny": false, /*whether blocking is enabled in the action column on the snapshots page*/
        "man_act": true, /*means that an action is set manually for this snsht snapshot (not default action). Action can be set manually or by AI*/
        "vpn": false, /*vpn=true if Instagram website can be reached from the user's network*/
        "snsht": 2129350817, /*browser snapshot identifier*/
        "net_id": 1978768490, /*numeric identifier of user network*/
        "net_t": "home",
        "bl": true, /*browser snapshot belongs to a bot group (groups are marked red on snapshots page)*/
        "wl": false, /*browser snapshot belongs to trusted browser group (groups are marked green)*/
        "ffp": "3329686866", /*font fingerprint - how the browser renders fonts*/
        "cch": false, /*whether page content was changed on the client side*/
        "tm": "3",  /*time in seconds required to load KillBot Screen. Many visits with time above 3 seconds can indicate bots*/
        "rule_id": "30212", /*rule number that matched the visit*/
        "rule_capt": 2,  /*captcha action from rule. Rule captcha has higher priority than capt*/
        "rule_metr": false, /*whether to hide analytics according to rule. Rule value has higher priority than metr*/
        "rule_deny": false, /*blocking according to rule. Has higher priority than deny*/
        "rule_bot": true,  /*classify visit as bot or not according to rule. Has higher priority than bot*/
        "user_capt": false, /*captcha action set for UserID on visits page. Has the highest priority (overwrites rule result)*/
        "user_metr": true, /*show/hide analytics for UserID. Has the highest priority*/
        "user_deny": true, /*blocking set for UserID on visits page. Has the highest priority*/
        "user_bot": true, /*classify UserID as bot or user. Has the highest priority*/
        "user_pop": true, /*means UserID is not unique enough because many users have the same ID*/
        "new_user_website": true,  /*new user for this website*/
        "capt_force_all": true /*captcha is enabled for everyone regardless of other captcha settings*/
    },
    "user": {
        "timezone": "UTC",
        "locale": "ru"
    },
    "net": {
        "ip": "18.216.102.68",
        "host": "ec2-18-216-102-68.us-east-2.compute.amazonaws.com", /*hostname resolved from IP*/
        "asn": "25454",
        "country": "US",
         "ports": {         /*list of open ports on this IP*/
            "22": {
                "port": 22,
                "ttl": 58,
                "rtt": 48
            },
            "443": {
                "port": 443,
                "ttl": 58,
                "rtt": 56
            }
        },
        "ping": true, /*whether IP responds to ping*/
        "ttlOS": "Linux",  /*operating system detected by TTL (Linux, Windows, etc.)*/
        "ttl": "57",  /*TTL value*/
        "ttl_b": "57", /*reverse TTL value*/
        "rtt": 0 /*time until first response packet*/
    },
    "request": {
        "user-agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/150.0.0.0 Safari\/537.36",
        "referer": "",
        "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
        "url": "https:\/\/my.kill-bot.net"
    },
    "browser": {
        "name": "Chrome",
        "language": "ru-RU",
        "webdriver": true, /*webdriver=true means the browser is controlled by software*/
        "innerheight": 919,
        "innerwidth": 1920,
        "outerheight": 1040,
        "outerwidth": 1920
    },
    "device": {
        "width": 1920,
        "height": 1080,
        "os": "Windows",
        "gc": "ANGLE (NVIDIA, NVIDIA GeForce GT 710 (0x0000128B) Direct3D11 vs_5_0 ps_5_0, D3D11)", /*GPU information*/
        "fps": 61  /*browser screen rendering frequency, bots can reduce it*/
    }
}

Example: Why the Parameters Above Belong to a Bot

  1. The parameter "webdriver": true means that the browser is controlled by software.
  2. The timezone is "timezone": "UTC", but the user IP location is the USA ("country": "US").
  3. The visitor IP address "ip": "18.216.102.68" resolves to an Amazon server: "host": "ec2-18-216-102-68.us-east-2.compute.amazonaws.com".
  4. An anti-detect browser technology is used: "adt": true.
  5. KillBot script was not fully loaded: l.false — this behavior is typical for bots.
  6. The website browser snapshot is not in the list of known browsers: wl.false.

Priority Order!

The default classification of visits as users or bots has the lowest priority. By default, a visit is classified as a bot if its browser snapshot is not found in system browsers. If an action is set in the snapshot action column (the action can be assigned manually or by AI), this action overrides the default behavior. If a rule exists and the visit matches this rule, the rule overrides the action configured for the browser snapshot on the snapshots page. If an individual action is set for the UserID on the visits page, this user-specific action overrides all previous actions.

Attention!
Creating rules requires programming knowledge. If you need help creating a rule, contact us in Telegram: https://t.me/grigoriy_melnikov We can create a rule specifically for your case. A simple visual rule builder will be added later, where anyone will be able to create rules by clicking buttons without programming.

 

Instruction: How to Write PHP Traffic Filtering Rules in KillBot

You can create traffic filtering rules on this page: https://my.kill-bot.net/waf/create (left menu → create rule)

There are two main fields:

  1. PHP rule code — write your filtering logic using PHP.

  2. Visit JSON parameters — test data used to check your rule. You can simply copy and paste visit data here to test your rule.

Available PHP Language Elements

Available Variable

  • $data — contains the JSON structure of the visit (for example, $data['user']['locale']). Use only $data. All other variables are forbidden.

Allowed Functions

strpos, stripos, strstr, stristr, str_contains, substr, preg_match, in_array, isset, empty, count, strlen, array_key_exists

Allowed Operators

&&, ||, !, ==, ===, !=, !==, <, >, <=, >=

Allowed Language Constructs


if, else, elseif, return, true, false, null

Forbidden

  • Dangerous functions: eval, exec, system, shell_exec, fopen, file_get_contents, include, require, etc.

  • Creating classes/functions: You cannot use function, class, namespace, new.

  • Global variables: $_GET, $_POST, $_SERVER and others.

  • Output: echo, print, die, exit are forbidden.


Example: How to Access Parameters

What you need How to write
Timezone $data['user']['timezone']
User language $data['user']['locale']
User-Agent $data['request']['user-agent']
WebDriver (bot indicator) $data['browser']['webdriver']
IP hostname $data['net']['host']
TTL OS $data['net']['ttlOS']
Operating system $data['device']['os']

What Should the PHP Rule Return?

The PHP code must return true or false. TRUE means that the rule condition is matched and the rule is triggered.

Attention!
You can create many filtering rules in KillBot. Rules are checked in order. The first rule that returns TRUE is applied, and all following rules are ignored. If no rule matches, the visit is classified as a bot or a user according to the default KillBot script settings.

Rule Creation Example

Below is a rule that marks all visits as bots if the user-agent contains the word Bot:


if (stripos($data['request']['user-agent'], 'bot') !== false) {
  return true;
}
return false;

Explanation:

  • $data['request']['user-agent'] — User-Agent string of the visitor.
  • stripos — function that searches for the substring "Bot". Because it uses "i" (case-insensitive), "bot" and "Bot" are treated the same.
  • stripos($data['request']['user-agent'], 'bot') — searches for the first occurrence of "bot" and returns FALSE if this text is not found.
  • if (stripos($data['request']['user-agent'], 'bot') !== false) — means the condition is TRUE if the User-Agent contains the word "bot".


This is how the rule looks in the KillBot interface:

Example filtering rule in KillBot


Click the "Save rule" button. At this moment KillBot checks the rule syntax and shows the result of applying the rule to the test data:

KillBot rule executed


KillBot shows the message: "Rule execution result: FALSE - rule was not triggered, test data does not match the rule conditions" This means that the User-Agent shown in the screenshot does not contain the word Bot.

Now change the test User-Agent to the Google bot User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +https://www.google.com/bot.html) Then click "Save rule" again and check the result.

Changed User-Agent to Google bot


Our rule returned TRUE because the User-Agent contains the substring "Bot".

Improve the Rule: Allow Real Search Engine Bots and Block Fake Ones

This rule improvement is only an example. In KillBot DNS integration, this logic is already built in and works automatically. You do not need to create this rule separately.

One of the main ways to verify whether a visit really belongs to Googlebot is to check which hostname the visitor IP address resolves to. KillBot automatically detects the hostname associated with the visitor IP address. This value is stored in: $data["net"]["host"].

If the visit comes from a real GoogleBot, the IP address should resolve to a domain in the google.com zone, for example:

crawl-66-249-66-1.googlebot.com

If:

  • the hostname cannot be resolved;
  • the hostname points to third-party infrastructure (for example, ec2-3-145-12-52.us-west-2.compute.amazonaws.com);
  • the hostname belongs to another zone (amazonaws.com, contabo.net, etc.);

this is a sign of a fake search bot pretending to be Google.


After adding this verification, our rule will look like this:



if (substr($data['net']['host'], -strlen(".google.com")) === ".google.com") {
// if the hostname ends with ".google.com", it is a real Google service bot
// allow this visit
  return false;
}

if (strpos($data['request']['user-agent'], 'bot') !== false) {
// if User-Agent contains "bot", classify the visit as a bot
  return true;
}

// if none of the conditions above are matched, classify the visit as a normal user
return false;


What Should Happen When a Rule Matches?

This is configured in the rule settings:

If rule matches classify visit as user

For our rule, if the rule returns TRUE, we classify this visit as a bot. The reason: if User-Agent contains "Bot" and the IP address does not resolve to Google's servers, this is most likely a fake bot.

Now choose the action for visits matched by this rule. In our example, we select: "Block".

Block fake bots

 

After select websites to apply this rule:

Select filtering rule


Done. After this, all visits processed by this KillBot script will be checked by this rule. If the rule matches (returns TRUE), the visitor parameters in analytics will contain the rule parameter with the rule number. The same rule number will also be displayed in the KillBot visit list.

 

Examples of How Bots Can Be Detected

Below are the main parameters that can help distinguish bots from real users. You can create universal rules and apply them to all websites in your KillBot account.

1. Host (IP Address Reverse DNS)

One of the strongest indicators is the host name where the visitor IP address resolves.

  • If an IP resolves to domains like: *.amazonaws.com, digitalocean.com or other cloud platforms, it is usually a server, not a real home user.

  • Such hosts are often used for bot operations or as VPN exit nodes.

  • If many visits come from the same range, it is almost certainly a bot network. A single visit may also be a VPN user.



if (strpos($data['net']['host'], 'amazon') !== false) {
// hostname contains the word 'amazon'
  return true; // IP belongs to Amazon infrastructure
}

return false; // allow other visitors


2. Timezone vs Geographic Location

Another useful check is the match between the user's timezone and the IP location.

  • For example, a user from Russia with timezone UTC+0 looks suspicious.

  • This may indicate a server environment, default system settings, or a bot that does not correctly emulate user settings.



if ($data['user']['timezone'] == 'UTC' && $data['net']['country'] === 'RU')
{
     return true; // timezone does not match Russia
}

return false;


3. Browser Language and Locale

Another useful indicator is the browser language (navigator.language) and locale settings.

  • For example, if timezone is Russian, browser language is Russian (ru-RU), but locale is English, this is not a 100% bot indicator. However, if many visitors have the same pattern, it can indicate automated traffic.

  • Combined with other signals, this increases confidence that the traffic is not from real users.



if (
$data['user']['timezone'] === 'Europe/Moscow'
&&
$data['browser']['language'] === 'ru-RU'
&&
$data['user']['locale'] === 'en-US'
)
{
      return true; // suspicious language and locale mismatch
}

return false;


4. Open Ports on the IP Address

A normal user — whether using mobile internet or home Wi-Fi — usually does not have open ports on their public IP address. This means that external services cannot connect directly to the user's computer, and no public web service is running on this IP.

If the IP address has open:

  • 80 or 443 ports — there is a high probability that a web server is running on this IP.

  • 22 (SSH) or 3389 (RDP) ports — these are remote administration services, commonly used on servers.

Such an IP address may belong to a VPN, proxy server, or a server used by bots.



if (isset($data['net']['ports'][443])) { 

// if port 443 exists in the $data['net']['ports'] array

     return true; // suspicious port detected - possible server or VPN

}

return false;


5. TTL (Time To Live) Analysis

TTL (Time To Live) is a value stored in every network packet. It defines the maximum number of network hops (routers, servers, or other network devices) that the packet can pass through.

Each operating system uses its own default TTL value when sending packets.

Operating System TTL
Windows 128
Linux / Android / macOS 64
Unix BSD 255

When a packet passes through a router, TTL decreases by 1. Therefore, based on the received TTL value, it is possible to approximately determine the original operating system.

For example, if the request headers say that the user is on Windows, but the TTL value is around 64 (typical for Linux), this is suspicious. Such a mismatch between User-Agent and TTL may indicate:

  • use of a proxy server that changes network characteristics;

  • a container or cloud server environment with another operating system;

  • fake User-Agent where a bot pretends to be another operating system.

TTL is not an absolute indicator. It can change because of network routing, VPN usage, and other conditions. However, together with other signals (WebDriver, host, locale, WebRTC, etc.), TTL becomes a powerful indicator of suspicious traffic and bot networks.



if ($data['device']['os'] === 'Windows' && $data['net']['ttl'] < 100) {

// OS=Windows but TTL is lower than expected for Windows

// suspicious mismatch

  return true;

}

return false;


7. 100% Bot Indicator: WebDriver = true

WebDriver is a browser automation interface that allows external software to control a browser and simulate user actions: clicks, typing, navigation, and other actions.

It is used by automation tools such as:

  • Selenium

  • Puppeteer

  • Headless Chrome / Firefox

If KillBot detects this parameter, it means:

  • the browser is controlled by software;

  • the browser contains: navigator.webdriver = true;

  • this is direct evidence that a bot script or automation platform controls the browser.

If webdriver=true, the visit is considered a bot. A real user can only have this value if someone is intentionally testing browser automation software.



if ($data['browser']['webdriver'] == true ) {

// definitely a bot

  return true;

}

return false;


8. WebRTC and Real IP Address Leak

Even if a bot correctly hides its IP address using a proxy, browser technologies can reveal the real IP address. One of the most important examples is WebRTC (Web Real-Time Communication).

  • WebRTC is a built-in browser technology for real-time audio, video, and data communication.

  • It can work outside the normal proxy path and may reveal the real device IP address even when traffic goes through VPN or proxy.

  • If the browser IP (proxy IP) is different from the WebRTC IP, the user is using a proxy. This alone is not bad, but it requires attention. If many visitors have this mismatch and the WebRTC IP remains the same while browser IPs constantly change, this is a typical pattern of a bot system working from one server through multiple proxies.



if ($data['net']['ip'] != $data['net']['webrtc_ip']) {

// WebRTC IP is different from visitor IP

          return true;

}

return false;


9. Bot Indicator: wl=false (Browser Snapshot Not Found)

wl is a KillBot parameter. It can have two values:

  • true — the browser snapshot of this visit exists in the system browser list (trusted browsers);

  • false — the browser snapshot was not found among known trusted browsers.

If wl=false, KillBot classifies such visits as bots by default. If many visits have this parameter, they are almost certainly bots. If less than 5% of real traffic has this parameter, some of these visits may still belong to real users.



if ($data['killbot']['wl'] = true) {

// browser snapshot is not in the system browser list

          return true;

}

return false;


 

10. Block Specific ASNs

Some internet providers are mainly used for bot traffic. For example, Biterika and similar networks. It can be useful to block such ASN numbers immediately.



if (in_array($data['net']['asn'],array("35048","35049","54048") ) ){

// if ASN matches one of the listed values, classify as BOT

          return true;

}

return false;


11. Block Direct Traffic from a Specific Browser Snapshot

Sometimes you do not need to block all traffic from a browser snapshot. You may only want to restrict direct visits.



if ($data['killbot']['snsht'] == 3933974590 && $data['request']['referer'] == "") { 

// if browser snapshot equals 3933974590
// and the visit has no referrer (direct traffic)

          return true;

}

return false;


12. Allow Traffic with a Specific URL Parameter

Sometimes you need to allow visitors with specific URL parameters or marketing tags.



if (stripos($data['request']['url'], 'from=seo') !==false ){ 

// if URL contains 'from=seo', apply the rule action

          return true;

}

return false;


 

13. Block Access from a Specific IP Address



if (in_array($data['net']['ip'],array("46.159.126.145") ) ){

// if IP matches the specified value, classify as BOT

          return true;

}

return false;


 

14. Allow Requests from a Specific Referer (Example: yandex.ru)



return isset($data['request']['referer']) 
&& stripos($data['request']['referer'], 'yandex.ru') !== false;

// if referer contains yandex.ru,
// the configured rule action will be applied
// (for example, do not show captcha)


 

15. Show Captcha for Direct Visits Without Referer



if ($data['request']['referer'] == "") { 

// if there is no referer, the rule is triggered
// for example, show captcha for such visitors

          return true;

}

return false;


 

16. Show Captcha for Visitors Outside CIS Countries



if (!in_array($data['net']['country'], ['RU', 'KZ', 'BY', 'AM', 'AZ', 'KG', 'MD', 'TJ', 'UZ', 'TM', 'GE']))
  { 

      return true; // captcha for visitors outside this country list

  } 

  return false;


 

17. Show Captcha for Visitors from China (CN)



if ($data['net']['country'] == 'CN')
  { 

      return true; // visitors from China get captcha

  } 

  return false;


 

18. Visitor from .google.com



if (strpos($data['net']['host'], '.google.com') !== false) 
{

   return true; // visitor belongs to google.com
                // apply selected action, for example: no captcha

}

return false;


 

19. Visitor from .googlebot.com



if (strpos($data['net']['host'], '.googlebot.com') !== false) 
{

   return true; // visitor belongs to googlebot.com
                // apply selected action, for example: no captcha

}

return false;


 

20. Visitor from .yandex.com



if (strpos($data['net']['host'], '.yandex.com') !== false) 
{

   return true; // visitor belongs to yandex.com
                // apply selected action, for example: no captcha

}

return false;


 

21. Visitor from .yandex.ru



if (strpos($data['net']['host'], '.yandex.ru') !== false) 
{

   return true; // visitor belongs to yandex.ru
                // apply selected action, for example: no captcha

}

return false;


 

22. Visitor with yandexwebcache.net Referer



return isset($data['request']['referer']) 
&& stripos($data['request']['referer'], 'yandexwebcache.net') !== false;


 

23. Visitor from Google ASN 15169



if (in_array($data['net']['asn'],array("15169") ) ){

// ASN 15169 belongs to Google

// apply selected action, for example: no captcha

          return true;

}

return false;


 

24. Visitor from .gstatic.com



if (strpos($data['net']['host'], '.gstatic.com') !== false) 
{

   return true; // visitor belongs to gstatic.com
                // apply selected action

}

return false;