## Overview

By default, every Ad Decision Request evaluates all targeting rules configured on Flights — keyword targeting, geo-targeting, segment targeting, and more. If an Ad's Flight has keyword targeting configured but the request doesn't include matching keywords, the Ad won't be returned.

**`skipFilters`** is a placement-level option in the Decision API that lets you selectively bypass one or more of these targeting rules at request time. This gives you flexibility to reuse the same Flights and Ads across different contexts without duplicating Campaign configuration.

For example, a Flight might target the keyword "electronics" for search result pages. But when the same Ad should also be eligible on a homepage or category page where no keywords are present, you can include `skipFilters` to bypass keyword targeting for that specific request — without changing the Flight's configuration.

## When to Use skipFilters

Common scenarios include:

- **Mixed-context Ads.** A Flight targets keywords for search pages, but the same Ads should also serve on non-search pages (e.g., homepage, category page, product detail page) where those keywords aren't relevant.
- **Simplified Campaign setup.** Instead of creating separate Flights for each context, configure targeting on one Flight and use `skipFilters` on requests where that targeting shouldn't apply.
- **Search term targeting opt-out.** A Flight uses [search term targeting](https://dev.kevel.com/docs/search-term-targeting), but some placements (like a "trending" section) should show those Ads without requiring a matching search term.
- **Geo-override.** A Flight has location targeting, but you want a specific API integration to return Ads regardless of the user's detected location.
- **Auction-as-a-Service.** When using [AdQuery to pass candidate product lists](https://dev.kevel.com/docs/auction-as-a-service), you may want to bypass keyword or location targeting because your own system has already determined relevance.

## Basic Usage: Bypassing a Filter

Add `skipFilters` to a placement and set each filter you want to bypass to `true`:

### JSON

```json
{
  "placements": [
    {
      "divName": "div0",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [5],
      "skipFilters": {
        "keyword": true
      }
    }
  ]
}
```

This tells Kevel: "For this placement, don't disqualify Ads based on keyword targeting rules. Evaluate everything else normally."

You can skip multiple filters at once:

### JSON

```json
{
  "placements": [
    {
      "divName": "div0",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [5],
      "skipFilters": {
        "keyword": true,
        "geolocation": true,
        "geodistance": true
      }
    }
  ]
}
```

## Supported Filters

The following filters can be bypassed with `skipFilters`:

| Filter key      | What it skips                                                                                         |
|------------------|------------------------------------------------------------------------------------------------------|
| `keyword`        | [Keyword targeting](https://dev.kevel.com/docs/keyword-targeting) on both Flights and Ads             |
| `siteZone`      | [Site and zone targeting](https://dev.kevel.com/docs/site-zone-targeting) rules                       |
| `geolocation`   | [Location targeting](https://dev.kevel.com/docs/geo-targeting) (country, region, metro)              |
| `geodistance`   | [Distance targeting](https://dev.kevel.com/docs/geo-targeting) (radius-based proximity)              |
| `segment`       | [Segment targeting](https://dev.kevel.com/docs/segment-targeting) (user segment membership)           |
| `searchTerm`    | [Search term targeting](https://dev.kevel.com/docs/search-term-targeting) (broad and strict match)   |
| `facet`         | Facet targeting                                                                                      |
| `placementLimit`| Advertiser placement limits (maximum Ads per Advertiser per placement)                               |

> **Note:** `geolocation` and `geodistance` can also be referenced as `location` and `distance` respectively. Both forms are accepted.

## Advanced: Replacing a Filter with an AdQuery Predicate

In addition to fully bypassing a filter, you can **replace** it with an [AdQuery](https://dev.kevel.com/docs/adquery) predicate. Instead of setting a filter to `true`, provide an AdQuery object. This creates an **OR condition**: an Ad is eligible if it matches the AdQuery predicate **or** the original targeting rule.

This is useful when you want to expand the pool of eligible Ads beyond what the Flight's targeting would normally allow, without removing that targeting entirely.

### Example: keyword OR AdQuery

A Flight targets the keyword "bargain". You want to also include Ads that match a price range, even if they don't have the keyword:

### JSON

```json
{
  "placements": [
    {
      "divName": "div0",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [5],
      "keywords": ["bargain"],
      "skipFilters": {
        "keyword": {
          "ctPrice": {
            "min": 50,
            "max": 250,
            "nullValuesMatch": false
          }
        }
      }
    }
  ]
}
```

With this request, an Ad is eligible if:

- Its `ctPrice` value is between 50 and 250 (the AdQuery matches), **OR**
- It matches the keyword "bargain" (the original keyword targeting matches)

An Ad that matches **neither** is excluded.

### Example: distance OR AdQuery

A Flight has geodistance targeting. You want to also include Ads matching a specific product attribute, regardless of proximity:

### JSON

```json
{
  "placements": [
    {
      "divName": "div0",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [5],
      "skipFilters": {
        "geodistance": {
          "ctCategory": {
            "eq": "electronics",
            "nullValuesMatch": false
          }
        }
      }
    }
  ]
}
```

An Ad is eligible if it's in the "electronics" category **or** within the Flight's configured distance radius.

### Which filters support the AdQuery replacement mode?

The AdQuery replacement (OR) mode is supported for: `keyword`, `siteZone`, `geodistance`, `geolocation`, and `segment`.

Other filters (`searchTerm`, `facet`, `placementLimit`) only support the boolean `true` bypass.

## Combining with AdQuery

`skipFilters` and top-level `adQuery` are independent and composable. You can use both on the same placement:

### JSON

```json
{
  "placements": [
    {
      "divName": "div0",
      "networkId": 12345,
      "siteId": 67890,
      "adTypes": [5],
      "adQuery": {
        "ctSku": {
          "in": ["sku-001", "sku-002", "sku-003"]
        }
      },
      "skipFilters": {
        "keyword": true,
        "geolocation": true
      }
    }
  ]
}
```

In this example:

- `adQuery` filters Ads to only those matching the given SKUs.
- `skipFilters` ensures keyword and geolocation targeting don't further narrow the candidate set.

This combination is common in [Auction-as-a-Service](https://dev.kevel.com/docs/auction-as-a-service) setups, where your system determines relevance and you want Kevel to focus on auction mechanics rather than replicating your targeting logic.

## Scope and Behavior

- **Placement-scoped.** `skipFilters` applies only to the placement it's defined on. In a multi-placement request, each placement can have its own `skipFilters` configuration.
- **Other rules still apply.** Skipping a filter does not bypass pacing, budgeting, frequency capping, or priority evaluation. Those always apply.
- **Only affects the specified filters.** Any filter not listed in `skipFilters` continues to be evaluated normally.
