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

# Advanced Rules

<Info>
  **Info**

  This feature is available in selected plans. For up-to-date information on plan availability, see the [billing documentation](/waap/getting-started/billing).
</Info>

Similarly to WAAP [custom rules](/waap/waap-rules/custom-rules), you can create, edit, and manage advanced custom rules. These rules also contain "If/Then" statements, but they support more complex conditions created with the [Common Expression Language (CEL)](https://github.com/google/cel-spec) syntax.

## Create advanced rules

Due to the highly technical aspect of the advanced rules functionality, the ability to create and edit these rules is currently only available through our API.

Check out the following guides for details on how to create advanced rules and their key components:

* [API docs](https://api.gcore.com/docs/waap): Learn how to construct and manage advanced rules.
* [Advanced rule objects and attributes](/waap/waap-rules/advanced-rules/advanced-rule-objects): Get the list of all available objects you can use in rule expressions along with their respective attributes and types.
* [Source field objects](/waap/waap-rules/advanced-rules/source-field-objects): Check the available source field objects you can use in your expressions along with their respective attributes and types.

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). Set these as environment variables before running any of the examples:

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

## Advanced rule properties

The advanced rule object contains the following properties:

```json theme={null}
{
  "name": "string",
  "description": "",
  "enabled": true,
  "action": {
    "allow": {},
    "block": {
      "status_code": 403,
      "action_duration": "string"
    },
    "captcha": {},
    "handshake": {},
    "tag": {
      "tags": [
        "string"
      ]
    }
  },
  "source": "string",
  "phase": "access"
}
```

<Info>
  **Info**

  Each rule can contain only one action ΓÇö `block`, `allow`, `captcha`, `handshake`, or `tag`. If you use multiple actions in a single rule, the API will return an error.
</Info>

<Accordion title="Description of the properties">
  | Field         | Description                                     | Values                                                                                                                                                                                                                                                                      | Details                                                                                                                                                                                                                                                                                                                                                                                               |
  | ------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `name`        | Rule name                                       | Can contain only ASCII letters, numbers, spaces, periods, and colons.                                                                                                                                                                                                       | **Required.**                                                                                                                                                                                                                                                                                                                                                                                         |
  | `action`      | The action to execute when a condition is true. | <ul><li>block: WAAP blocked the request.</li><li>allow: WAAP allowed the request.</li><li>captcha: WAAP presented the user with a CAPTCHA</li><li>handshake: WAAP performed automatic browser validation.</li><li>tag: WAAP will generate a tag with no action.</li></ul>   | **Required.** On `tag` [action](/waap/waap-rules/custom-rules#actions-in-custom-rules), the tag field should be provided.<br /><br />For the `block` [action](/waap/waap-rules/custom-rules#actions-in-custom-rules), setting up the `status_code` (integer) and `action_duration` (time in seconds) is optional. By default, the status is set to `"status_code": 403`, and duration equals to `0s`. |
  | `source`      | The condition part of the rule.                 | Can reference namespace objects: request, whois, session, response, tags, user\_agent, client\_data, as well as use data and functions.<br /><br />Supported Python operand syntax: and, or, in, not, ==, !=, >, \<, etc.<br />Supported CEL operand syntax: \|\|, &&       | **Required.** Every string value should be enclosed in single quotation marks `'` and **not** in double quotation marks `"`.                                                                                                                                                                                                                                                                          |
  | `enabled`     | Whether or not the rule is enabled.             | Boolean: `true` or `false`                                                                                                                                                                                                                                                  | **Required.**                                                                                                                                                                                                                                                                                                                                                                                         |
  | `description` | A string to describe the purpose of the rule.   | Any string. The character limit for the description field is 100 characters.                                                                                                                                                                                                |                                                                                                                                                                                                                                                                                                                                                                                                       |
  | `phase`       | The request processing phase.                   | <ul><li>access: The advanced rule applies to the request phase (request headers and body available).</li><li>header\_filter: The advanced rule applies to the response headers phase.</li><li>body\_filter: The advanced rule applies to the response body phase.</li></ul> | Default value: `access`                                                                                                                                                                                                                                                                                                                                                                               |
</Accordion>

## Best practices

You can use our API documentation as a guide when constructing your own advanced rules. The following sections provide examples of advanced rules and the key CEL expressions used in each.

<Note>
  **Note**

  Examples are illustrative. Field values (paths, cookies, IPs, countries) should be adapted to the customer's environment.
</Note>

### Rate limiting

Rate-limit IPs based on the number of requests they make to your website. This can be useful for mitigating scrapers or automated clients that generate a high volume of requests over a short period of time.

The following rule limits the rate of requests an IP can send for 10 minutes when it exceeds 200 requests in 5 seconds, but excludes requests from mobile or web clients that have specific cookies.

You can find more examples in our [Rate limiting](/waap/waap-rules/advanced-rules/advanced-rate-limiting-rules) guide.

<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 = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Block Scrapers",
        description="Block IPs that hit more than 200 requests per 5 seconds for any events paths",
        enabled=False,
        phase="access",
        action={"block": {"status_code": 403, "action_duration": "10m"}},
        source=(
            "request.limit_rate(url='.*events', interval=5, requests=200, scope='ip')"
            " and not ('mb-web-ui' in request.headers['Cookie']"
            " or 'mb-mobile-ios' in request.headers['Cookie']"
            " or 'mb-mobile-android' in request.headers['Cookie']"
            " or 'session-token' in request.headers['Cookie'])"
            " and not request.headers['session']"
        ),
    )
    print(f"Created rule ID: {rule.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"
        "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)

        source := "request.limit_rate(url='.*events', interval=5, requests=200, scope='ip')" +
            " and not ('mb-web-ui' in request.headers['Cookie']" +
            " or 'mb-mobile-ios' in request.headers['Cookie']" +
            " or 'mb-mobile-android' in request.headers['Cookie']" +
            " or 'session-token' in request.headers['Cookie'])" +
            " and not request.headers['session']"

        rule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:        "Block Scrapers",
                Description: gcore.String("Block IPs that hit more than 200 requests per 5 seconds for any events paths"),
                Enabled:     false,
                Phase:       waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action: waap.DomainAdvancedRuleNewParamsAction{
                    Block: waap.DomainAdvancedRuleNewParamsActionBlock{
                        StatusCode:     403,
                        ActionDuration: gcore.String("10m"),
                    },
                },
                Source: source,
            },
        )
        fmt.Printf("Created rule ID: %d\n", rule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Block Scrapers",
        "description": "Block IPs that hit more than 200 requests per 5 seconds for any events paths",
        "enabled": false,
        "phase": "access",
        "action": {"block": {"status_code": 403, "action_duration": "10m"}},
        "source": "((request.limit_rate(url='\''.*events'\'', interval=5, requests=200, scope='\''ip'\'')) and not ('\''mb-web-ui'\'' in request.headers['\''Cookie'\''] or '\''mb-mobile-ios'\'' in request.headers['\''Cookie'\''] or '\''session-token'\'' in request.headers['\''Cookie'\'']) and not request.headers['\''session'\'']) or tags.exists('\''penalty'\'')"
      }'
    ```

    The API returns the created rule with its assigned ID:

    ```json theme={null}
    {
      "id": 269009,
      "name": "Block Scrapers",
      "description": "Block IPs that hit more than 200 requests per 5 seconds for any events paths",
      "enabled": false,
      "action": {"block": {"status_code": 403, "action_duration": "10m"}},
      "source": "...",
      "phase": "access"
    }
    ```
  </Tab>
</Tabs>

### The penalty tag

The WAAP system appends the `penalty` tag to the local (domain-related) IP record when an IP address triggers a block rule configured with an `action_duration` parameter.

To continue blocking an IP address after the original rule's conditions are no longer met, include a `penalty` tag check in the rule's source conditions (for example, using `tags.exists('penalty')`), or define a separate rule that targets requests carrying the penalty tag.

#### Block all penalty requests

The following rule blocks requests from IP addresses tagged with the `penalty` tag, allowing block actions applied by other rules to persist.

<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 = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Block Penalized Requests",
        description="Block requests from IP addresses tagged with the penalty tag",
        enabled=False,
        phase="access",
        action={"block": {}},
        source="tags.exists('penalty')",
    )
    print(f"Created rule ID: {rule.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"
        "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)

        rule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:        "Block Penalized Requests",
                Description: gcore.String("Block requests from IP addresses tagged with the penalty tag"),
                Enabled:     false,
                Phase:       waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action:      waap.DomainAdvancedRuleNewParamsAction{Block: waap.DomainAdvancedRuleNewParamsActionBlock{}},
                Source:      "tags.exists('penalty')",
            },
        )
        fmt.Printf("Created rule ID: %d\n", rule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Block Penalized Requests",
        "description": "Block requests from IP addresses tagged with the penalty tag",
        "enabled": false,
        "phase": "access",
        "action": {"block": {}},
        "source": "tags.exists('\''penalty'\'')"
      }'
    ```

    The API returns 201 with the created rule object.
  </Tab>
</Tabs>

## Other examples

### Validate a set of countries

Applies browser validation (JavaScript-based challenge) using the `handshake` action to requests originating from specific countries, based on the `whois.country` field, while excluding requests that contain certain cookies.

<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 = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Validate set of countries",
        description="Validate with JavaScript challenge IPs coming from specific countries",
        enabled=False,
        phase="access",
        action={"handshake": {}},
        source=(
            "whois.country in ['BR', 'VN', 'ID', 'TH', 'ME', 'XK', 'LK']"
            " and not ('mb-web-ui' in request.headers['Cookie']"
            " or 'mb-mobile-ios' in request.headers['Cookie']"
            " or 'mobile-android' in request.headers['Cookie']"
            " or 'mb-mobile-android' in request.headers['Cookie'])"
        ),
    )
    print(f"Created rule ID: {rule.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"
        "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)

        source := "whois.country in ['BR', 'VN', 'ID', 'TH', 'ME', 'XK', 'LK']" +
            " and not ('mb-web-ui' in request.headers['Cookie']" +
            " or 'mb-mobile-ios' in request.headers['Cookie']" +
            " or 'mobile-android' in request.headers['Cookie']" +
            " or 'mb-mobile-android' in request.headers['Cookie'])"

        rule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:        "Validate set of countries",
                Description: gcore.String("Validate with JavaScript challenge IPs coming from specific countries"),
                Enabled:     false,
                Phase:       waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action:      waap.DomainAdvancedRuleNewParamsAction{Handshake: map[string]any{}},
                Source:      source,
            },
        )
        fmt.Printf("Created rule ID: %d\n", rule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "action": {"handshake": {}},
        "phase": "access",
        "name": "Validate set of countries",
        "description": "Validate with JavaScript challenge IPs coming from specific countries",
        "enabled": false,
        "source": "whois.country in ['\''BR'\'', '\''VN'\'', '\''ID'\'', '\''TH'\'', '\''ME'\'', '\''XK'\'', '\''LK'\''] and not ('\''mb-web-ui'\'' in request.headers['\''Cookie'\''] or '\''mb-mobile-ios'\'' in request.headers['\''Cookie'\''] or '\''mobile-android'\'' in request.headers['\''Cookie'\''] or '\''mb-mobile-android'\'' in request.headers['\''Cookie'\''])"
      }'
    ```

    The API returns 201 with the created rule object.
  </Tab>
</Tabs>

### Add clients to allow list

Allow requests from specific IP addresses or IP ranges by matching IP values in the rule condition.

<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 = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Allowlist known IPs",
        enabled=False,
        action={"allow": {}},
        source="request.ip == '117.20.32.5' or request.ip == '117.20.32.4' or request.ip_in_range('72.21.217.0', '72.21.217.255')",
    )
    print(f"Created rule ID: {rule.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"
        "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)

        rule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:    "Allowlist known IPs",
                Enabled: false,
                Action:  waap.DomainAdvancedRuleNewParamsAction{Allow: map[string]any{}},
                Source:  "request.ip == '117.20.32.5' or request.ip == '117.20.32.4' or request.ip_in_range('72.21.217.0', '72.21.217.255')",
            },
        )
        fmt.Printf("Created rule ID: %d\n", rule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Allowlist known IPs",
        "enabled": false,
        "action": {"allow": {}},
        "source": "request.ip == '\''117.20.32.5'\'' or request.ip == '\''117.20.32.4'\'' or request.ip_in_range('\''72.21.217.0'\'', '\''72.21.217.255'\'')"
      }'
    ```

    The API returns 201 with the created rule object.
  </Tab>
</Tabs>

### Tag and allow registered clients

Tag requests based on the presence of a specific cookie and allow requests associated with the assigned tag. When defining tag values in JSON, double quotation marks must be used, while string values inside rule expressions must be enclosed in single quotation marks.

<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"])

    # Step 1: tag registered clients by cookie
    tag_rule = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Tag registered clients",
        description="Detect and tag registered clients by cookie",
        enabled=False,
        phase="access",
        action={"tag": {"tags": ["registered"]}},
        source="'mb-mobile-android' in request.headers['Cookie']",
    )
    print(f"Tag rule ID: {tag_rule.id}")

    # Step 2: allow requests carrying the tag
    allow_rule = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Allow registered clients",
        description="Allow registered clients",
        enabled=False,
        phase="access",
        action={"allow": {}},
        source="tags.exists('registered')",
    )
    print(f"Allow rule ID: {allow_rule.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"
        "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)

        // Step 1: tag registered clients by cookie
        tagRule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:        "Tag registered clients",
                Description: gcore.String("Detect and tag registered clients by cookie"),
                Enabled:     false,
                Phase:       waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action:      waap.DomainAdvancedRuleNewParamsAction{Tag: waap.DomainAdvancedRuleNewParamsActionTag{Tags: []string{"registered"}}},
                Source:      "'mb-mobile-android' in request.headers['Cookie']",
            },
        )
        fmt.Printf("Tag rule ID: %d\n", tagRule.ID)

        // Step 2: allow requests carrying the tag
        allowRule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:        "Allow registered clients",
                Description: gcore.String("Allow registered clients"),
                Enabled:     false,
                Phase:       waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action:      waap.DomainAdvancedRuleNewParamsAction{Allow: map[string]any{}},
                Source:      "tags.exists('registered')",
            },
        )
        fmt.Printf("Allow rule ID: %d\n", allowRule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    # Step 1: tag registered clients by cookie
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Tag registered clients",
        "description": "Detect and tag registered clients by cookie",
        "enabled": false,
        "phase": "access",
        "source": "'\''mb-mobile-android'\'' in request.headers['\''Cookie'\'']",
        "action": {"tag": {"tags": ["registered"]}}
      }'

    # Step 2: allow requests carrying the tag
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Allow registered clients",
        "description": "Allow registered clients",
        "enabled": false,
        "phase": "access",
        "source": "tags.exists('\''registered'\'')",
        "action": {"allow": {}}
      }'
    ```

    Both calls return 201 with the created rule object.
  </Tab>
</Tabs>

### Define login pages

Tag requests that match specific URL patterns using string matching on the request URI.

<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 = client.waap.domains.advanced_rules.create(
        domain_id,
        name="Detect and Tag Login Pages",
        enabled=False,
        phase="access",
        action={"tag": {"tags": ["login page"]}},
        source="['url1/login','url2/signup'] in request.uri",
    )
    print(f"Created rule ID: {rule.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"
        "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)

        rule, _ := client.Waap.Domains.AdvancedRules.New(
            context.Background(),
            domainID,
            waap.DomainAdvancedRuleNewParams{
                Name:    "Detect and Tag Login Pages",
                Enabled: false,
                Phase:   waap.DomainAdvancedRuleNewParamsPhaseAccess,
                Action:  waap.DomainAdvancedRuleNewParamsAction{Tag: waap.DomainAdvancedRuleNewParamsActionTag{Tags: []string{"login page"}}},
                Source:  "['url1/login','url2/signup'] in request.uri",
            },
        )
        fmt.Printf("Created rule ID: %d\n", rule.ID)
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X POST "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Detect and Tag Login Pages",
        "enabled": false,
        "phase": "access",
        "source": "['\''url1/login'\'','\''url2/signup'\''] in request.uri",
        "action": {"tag": {"tags": ["login page"]}}
      }'
    ```

    The API returns 201 with the created rule object.
  </Tab>
</Tabs>

## List rules

Retrieve all advanced rules configured for a domain, including their current enabled state, actions, and CEL source expressions.

<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"])

    rules = client.waap.domains.advanced_rules.list(domain_id)
    for rule in rules:
        status = "enabled" if rule.enabled else "disabled"
        print(f"{rule.id}: {rule.name} [{status}] ΓÇö {rule.source[:60]}")
    ```
  </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)

        rules, _ := client.Waap.Domains.AdvancedRules.List(context.Background(), domainID, waap.DomainAdvancedRuleListParams{})
        for _, rule := range rules.Results {
            status := "disabled"
            if rule.Enabled {
                status = "enabled"
            }
            fmt.Printf("%d: %s [%s]\n", rule.ID, rule.Name, status)
        }
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    curl -X GET "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"
    ```

    The API returns a paginated list of rules:

    ```json theme={null}
    {
      "limit": 100,
      "offset": 0,
      "count": 1,
      "results": [
        {
          "id": 269009,
          "name": "Block Scrapers",
          "description": "Block IPs that hit more than 200 requests per 5 seconds",
          "enabled": false,
          "action": {"block": {"status_code": 403, "action_duration": "10m"}},
          "source": "request.limit_rate(url='.*events', interval=5, requests=200, scope='ip') ...",
          "phase": "access"
        }
      ]
    }
    ```
  </Tab>
</Tabs>

The rules are also visible in the Gcore Customer Portal, where they can be enabled, disabled, or deleted:

<Frame>
  <img src="https://mintcdn.com/gcore/f2sQyewrEkNYNknM/images/docs/waap/waap-rules/advanced-rules/advanced-rules-sample.png?fit=max&auto=format&n=f2sQyewrEkNYNknM&q=85&s=6ce0d7e977c4df8549cfb6c2dee00545" alt="Advanced rules section in WAAP Customer Portal" width="1400" height="900" data-path="images/docs/waap/waap-rules/advanced-rules/advanced-rules-sample.png" />
</Frame>

## Update a rule

Update any combination of a rule's name, description, enabled state, action, phase, or source expression. Only fields included in the request body are changed. The API returns 204 with no body on success.

<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_id = 269009

    client.waap.domains.advanced_rules.update(
        rule_id,
        domain_id=domain_id,
        description="Updated: block IPs exceeding 100 req/5s on all paths",
        source="request.limit_rate(url='.*', interval=5, requests=100, scope='ip')",
    )
    print("Rule updated")
    ```
  </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)
        ruleID := int64(269009)

        client.Waap.Domains.AdvancedRules.Update(
            context.Background(),
            ruleID,
            waap.DomainAdvancedRuleUpdateParams{
                DomainID:    domainID,
                Description: gcore.String("Updated: block IPs exceeding 100 req/5s on all paths"),
                Source:      gcore.String("request.limit_rate(url='.*', interval=5, requests=100, scope='ip')"),
            },
        )
        fmt.Println("Rule updated")
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    export RULE_ID=269009

    curl -X PATCH "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules/${RULE_ID}" \
      -H "Authorization: APIKey ${GCORE_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "description": "Updated: block IPs exceeding 100 req/5s on all paths",
        "source": "request.limit_rate(url='\''.*'\'', interval=5, requests=100, scope='\''ip'\'')"
      }'
    ```

    The API returns 204 with no body on success.
  </Tab>
</Tabs>

## Enable and disable a rule

Switch a rule between active and inactive without deleting it. Disabling a rule stops it from matching requests while preserving its configuration. The API returns 204 with no body for both operations.

<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_id = 269009

    client.waap.domains.advanced_rules.toggle("disable", domain_id=domain_id, rule_id=rule_id)
    print("Rule disabled")

    client.waap.domains.advanced_rules.toggle("enable", domain_id=domain_id, rule_id=rule_id)
    print("Rule enabled")
    ```
  </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)
        ruleID := int64(269009)

        client.Waap.Domains.AdvancedRules.Toggle(
            context.Background(),
            waap.DomainAdvancedRuleToggleParamsActionDisable,
            waap.DomainAdvancedRuleToggleParams{DomainID: domainID, RuleID: ruleID},
        )
        fmt.Println("Rule disabled")

        client.Waap.Domains.AdvancedRules.Toggle(
            context.Background(),
            waap.DomainAdvancedRuleToggleParamsActionEnable,
            waap.DomainAdvancedRuleToggleParams{DomainID: domainID, RuleID: ruleID},
        )
        fmt.Println("Rule enabled")
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    export RULE_ID=269009

    # Disable
    curl -X PATCH "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules/${RULE_ID}/disable" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"

    # Enable
    curl -X PATCH "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules/${RULE_ID}/enable" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"
    ```

    Both calls return 204 with no body on success.
  </Tab>
</Tabs>

## Delete a rule

Delete a rule by ID. The operation is irreversible and returns 204 with no body on success.

<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_id = 269009

    client.waap.domains.advanced_rules.delete(rule_id, domain_id=domain_id)
    print("Rule deleted")
    ```
  </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)
        ruleID := int64(269009)

        client.Waap.Domains.AdvancedRules.Delete(
            context.Background(),
            ruleID,
            waap.DomainAdvancedRuleDeleteParams{DomainID: domainID},
        )
        fmt.Println("Rule deleted")
    }
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={null}
    export RULE_ID=269009

    curl -X DELETE "https://api.gcore.com/waap/v1/domains/${WAAP_DOMAIN_ID}/advanced-rules/${RULE_ID}" \
      -H "Authorization: APIKey ${GCORE_API_KEY}"
    ```

    The API returns 204 with no body on success.
  </Tab>
</Tabs>
