> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Anti-automation and bot protection

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>WAAP uses [behavioral WAF](/waap/waap-policies/behavioral-waf) to block non-human traffic from accessing your application, including scanners, bots, and other automated tools. </p>

    <p>To protect your site from malicious attacks, we use [JavaScript injection](/waap/frequently-asked-questions/javascript-injection). This method ensures that we get all necessary information to block automated traffic from reaching your origin server. Meanwhile, all known bots, such as search engines, can still access your app. </p>

    <Info>
      **Info**

      This policy group is available in the Pro and Enterprise plans. More details on the [Security pricing page](https://gcore.com/pricing/security#waap).
    </Info>

    ## Configure Bot Attacks rules

    <p>Our WAAP includes pre-defined bot protection rules to protect your site from automated traffic. You can review and configure them in the [Gcore Customer Portal](https://portal.gcore.com/accounts/reports/dashboard): </p>

    <p>1. Navigate to **WAAP** > **Bot Management**. </p>

    <p>2. In the domain dropdown at the top right of the page, select the needed domain.</p>

    <p>3. The **Bot Attacks** tab displays all available bot protection rules.</p>

    <Info>
      **Info**

      The **Invalid user agent** and **Unknown user agent** policies are set to **Protection** mode by default. Other policies are set to **Disabled**. To change a policy mode, click the dropdown near that policy.
    </Info>

    ### Anti-spam

    <p>Challenge-identified submission spammers using CAPTCHA and JavaScript validation.</p>

    ### Traffic anomaly

    <p>Challenge or block requests when the user or device doesn't maintain cookies or execute JavaScript correctly. If this happens, users are presented with either CAPTCHA or JavaScript validation screen. </p>

    ### Automated clients

    <p>Challenge or block requests from automated sessions. Automated clients are usually bots looking to hack, spam, spy, or generally compromise your website. Activating this policy will detect these requests and force human interaction. </p>

    <p>You can review a list of known bots and configure their mode within the [Known Bots](/waap/waap-policies/known-bots) section. Learn more about enabling and troubleshooting bot protection in [our dedicated guide](/waap/troubleshooting/enable-troubleshoot-bot-protection). </p>

    ### Headless browsers

    <p>Challenge or block requests from users or devices that use automation tools to launch browsers. Headless browsers are sometimes used to perform DDoS attacks on websites, increase advertisement impressions, or automate websites in unintended ways. Activate this policy to protect your site from these attacks. </p>

    ### Anti-scraping

    <p>Challenge or block requests when a user or device uses an automation tool with rapid and aggressive scraping practices. </p>

    <p>In certain cases, you may want to disable this policy. For example, if you have a travel website with aggregated data and want to allow partners to extract and display information on their own sites.</p>

    ### Vulnerability Scanner

    <p>Challenge or block requests from automated vulnerability scanners. Vulnerability scanners are security tools that systematically probe websites and applications to identify known weaknesses using techniques like port scanning, service enumeration, and vulnerability signature matching.</p>

    <p>These tools are commonly used for legitimate security testing, but attackers may also use them to discover exploitable flaws.</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Anti-automation and Bot Protection policies defend against non-human traffic by detecting and challenging or blocking requests from bots, scrapers, headless browsers, and vulnerability scanners. Two policies — Invalid user agent and Unknown user agent — are enabled by default; all others are disabled and can be enabled as needed.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with the ID of a [WAAP-protected domain](/waap/getting-started/configure-waap-for-a-domain) and the [Python](/developer-tools/sdks/python) or [Go](/developer-tools/sdks/go) SDK installed for SDK examples. This policy group is available on the Pro and Enterprise WAAP plans.
    </Info>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export WAAP_DOMAIN_ID="{YOUR_DOMAIN_ID}"
    ```

    ## View policy states

    <p>Retrieve the current mode of all Anti-automation and Bot Protection policies for a domain.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import gcore
        import os

        client = gcore.Gcore(api_key=os.environ["GCORE_API_KEY"])
        domain_id = int(os.environ["WAAP_DOMAIN_ID"])

        rule_sets = client.waap.domains.list_rule_sets(domain_id)
        aa_set = next(
            rs for rs in rule_sets if rs.resource_slug == "anti-automation-bot-protection"
        )

        for policy in aa_set.rules:
            status = "enabled" if policy.mode else "disabled"
            print(f"{policy.name}: {status} ({policy.id})")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "os"
            "strconv"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/option"
        )

        func main() {
            client := gcore.NewClient(option.WithAPIKey(os.Getenv("GCORE_API_KEY")))
            domainID, _ := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)

            ruleSets, _ := client.Waap.Domains.ListRuleSets(context.Background(), domainID)
            for _, rs := range *ruleSets {
                if rs.ResourceSlug == "anti-automation-bot-protection" {
                    for _, policy := range rs.Rules {
                        status := "disabled"
                        if policy.Mode {
                            status = "enabled"
                        }
                        fmt.Printf("%s: %s (%s)\n", policy.Name, status, policy.ID)
                    }
                }
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X GET "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/rule-sets" \
          -H "Authorization: APIKey ${GCORE_API_KEY}" \
          | jq '.[] | select(.resource_slug == "anti-automation-bot-protection") | .rules[] | {name, id, mode}'
        ```
      </Tab>
    </Tabs>

    <p>The response includes each policy in the group with its ID and current state. `mode: true` means enabled; `mode: false` means disabled.</p>

    ## Toggle a policy

    <p>Switch a policy between enabled and disabled. Each call flips the current mode. Use the policy ID returned by the [View policy states](#view-policy-states) request.</p>

    <Warning>
      This endpoint toggles the current state rather than setting a specific value. If the target state is unknown, check the current policy state first using the View policy states request.
    </Warning>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import gcore
        import os

        client = gcore.Gcore(api_key=os.environ["GCORE_API_KEY"])
        domain_id = int(os.environ["WAAP_DOMAIN_ID"])

        # Find the policy ID by name
        rule_sets = client.waap.domains.list_rule_sets(domain_id)
        aa_set = next(
            rs for rs in rule_sets if rs.resource_slug == "anti-automation-bot-protection"
        )
        policy = next(r for r in aa_set.rules if r.name == "Anti-spam")

        result = client.waap.domains.policies.toggle(policy.id, domain_id=domain_id)
        status = "enabled" if result.mode else "disabled"
        print(f"Anti-spam is now {status}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "os"
            "strconv"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/option"
            "github.com/G-Core/gcore-go/waap"
        )

        func main() {
            client := gcore.NewClient(option.WithAPIKey(os.Getenv("GCORE_API_KEY")))
            domainID, _ := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)

            // Find the policy ID by name
            ruleSets, _ := client.Waap.Domains.ListRuleSets(context.Background(), domainID)
            var policyID string
            for _, rs := range *ruleSets {
                if rs.ResourceSlug == "anti-automation-bot-protection" {
                    for _, p := range rs.Rules {
                        if p.Name == "Anti-spam" {
                            policyID = p.ID
                        }
                    }
                }
            }

            result, _ := client.Waap.Domains.Policies.Toggle(context.Background(), policyID, waap.DomainPolicyToggleParams{DomainID: domainID})
            status := "disabled"
            if result.Mode {
                status = "enabled"
            }
            fmt.Printf("Anti-spam is now %s\n", status)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        # Set POLICY_ID to the policy ID from the Policy reference or View policy states response
        export POLICY_ID="{POLICY_ID}"

        curl -X PATCH "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/policies/${POLICY_ID}/toggle" \
          -H "Authorization: APIKey ${GCORE_API_KEY}"
        ```

        Response:

        ```json theme={null}
        {"mode": true}
        ```
      </Tab>
    </Tabs>

    <p>The API returns the updated policy object. `mode: true` confirms the policy is now enabled; `mode: false` confirms disabled.</p>

    ## Policy reference

    <Accordion title="All Anti-automation and Bot Protection policies">
      **Action** indicates how the policy responds when triggered: **Block** rejects the request outright; **Captcha** presents a CAPTCHA challenge; **Handshake** applies a transparent JavaScript-based browser check without user interaction.

      | Policy                | Purpose                                                                                         | Action    | Default  |
      | --------------------- | ----------------------------------------------------------------------------------------------- | --------- | -------- |
      | Invalid user agent    | Blocks requests from user agents known to be associated with malicious activity.                | Block     | Enabled  |
      | Unknown user agent    | Applies a transparent JavaScript-based browser check to requests from unrecognized user agents. | Handshake | Enabled  |
      | Anti-spam             | Challenges identified submission spammers with CAPTCHA.                                         | Captcha   | Disabled |
      | Traffic anomaly       | Challenges requests from clients that do not maintain cookies or execute JavaScript correctly.  | Captcha   | Disabled |
      | Automated clients     | Challenges or blocks requests from automated sessions such as bots and scrapers.                | Block     | Disabled |
      | Headless browsers     | Challenges or blocks requests from browser-based automation tools.                              | Captcha   | Disabled |
      | Anti-scraping         | Challenges or blocks requests from tools performing rapid and aggressive data extraction.       | Captcha   | Disabled |
      | Vulnerability scanner | Blocks requests from automated security scanning tools.                                         | Block     | Disabled |
    </Accordion>
  </MethodSection>
</MethodSwitch>
