## Overview

Zerkel is a querying language used by Kevel to set the custom targeting of a flight, channel or creative.

Zerkel is very flexible and contains operators for:

- [String Values](https://dev.kevel.co/docs/zerkel-queries#section-operators-for-string-values) - exact match, wildcards, etc
- [Numerical Values](https://dev.kevel.co/docs/zerkel-queries#section-operators-for-numeric-values) - exact number match, less than, greater than, etc
- [Array Values](https://dev.kevel.co/docs/zerkel-queries#section-operators-for-array-values) - targets if element is included in array
- [Logic Operators](https://dev.kevel.co/docs/zerkel-queries#section-logic-operators) - and, or, not
- [True or False](https://dev.kevel.co/docs/zerkel-queries#section-true-or-false)
- [Regular Expressions](https://dev.kevel.co/docs/zerkel-queries#section-operators-for-regular-expressions) - matches, does not match

> 📘
>
> The keys and string values in a Zerkel query are case-sensitive. Whitespace around the Zerkel operators is optional.

> 🚧
>
> The maximum character length for Zerkel queries is 1000 characters.

> 🚧
>
> When passing queries via `CustomTargeting` field in API, make sure quotation marks are escaped so they don't break JSON. For example:
>
> `name = "Kevel"` would become `name = \\"Kevel\\"`

## Operators for String Values

| String Operators | Description |
| --- | --- |
| `=` | exact string match |
| `<>` | strings do not match exactly |
| `contains` | substring match |
| `like` | wildcard match allows `*` character to match any preceding or trailing characters |

**String Examples**

- `$url contains "kevel"` - Targets URLs such as " [www.kevel.co](/content/site-root.html)" , "kevel.net" , etc.
- `$url like "www.kevel.com*"` - Targets any URL that begins with " [www.kevel.com](https://www.kevel.com/)" , such as " [www.kevel.com/about](https://www.kevel.com/about)" , " [www.kevel.com/solutions/](https://www.kevel.com/solutions/)" , etc.

## Operators for Numeric Values

| Numeric Operators | Description |
| --- | --- |
| `=` | exact number match |
| `<>` | numbers do not match exactly |
| `<` | less than |
| `<=` | less than or equal to |
| `>` | greater than |
| `>=` | greater than or equal to |

## Operators for Array Values

**contains**

The `contains` operator targets a placement based on whether an element is present in the array. For example, given numbers `= [1,2,3,4]` in a placement:

- `numbers contains 1` would be true, and the placement will be targeted.
- `numbers contains "potato"` would be false, and the placement will not be targeted.

> 📘
>
> Unlike strings, the contains operator for arrays is an exact match for an element. For example:
>
> - `numbers contains 23` would be true if 23 is an element in the array.
> - `numbers contains 23` would not be true if 1234 is an element in the array.

## Logic Operators

You can create complex queries by using these Boolean operators:

- `and`
- `or`
- `not`

In addition, you can use parentheses to group logical statements together.

> ❗️
>
> If you use the `not` operator, you must use parentheses to enclose what you're querying against. For example:
> `weather contains "sunny" and not (season = "winter")`
> If you do not include the parentheses, the Zerkel query will be incorrectly parsed!

## True or False

To determine whether a key exists in a request (`true`) or doesn't exist (`false`), use the key by itself as your query:

- `foo` - matches if the `foo` key is present in the request
- `not foo` - matches if the `foo` key is not present in the request

> 🚧
>
> If the value of a key is `0`, `""`, or `null`, Zerkel will parse the key as nonexistent.
> For instance, given `"foo":0` in the request, `foo` will return false (i.e. not match) and `not foo` will return true.
> To work around this, you can pass an arbitrary value or `[]` instead of `0`, `""` or `null` in your requests.

## Operators for Regular Expressions

Zerkel supports two operators for querying against regular expressions:

- ` =~` (matches)
- `!~` (does not match)

For example:

Zerkel

```javascript
$url =~ "^https?:\/\/([^/:]\.)*foo\.bar\.com([:/].*)?$"
```

Will target any URL that contains foo.bar.com in the domain, including secure sites and subdomains.

Before using these operators, you should be familiar with how to use regular expressions.

## Comments

You can include comments in your queries. Zerkel supports both single-line and multi-line comments. Any text that is commented will be ignored by custom targeting.

A single-line comment starts with `//` and extends to the end of the line:

Zerkel Single-line Comment

```javascript
weather contains "sunny" // this targets sunny weather
```

A multi-line comment starts with / _and ends with_/ . All content within the operators will be ignored:

Zerkel Multi-line Comment

```javascript
/* The following query
   will target
   sunny weather */
weather contains "sunny"
```

## Example Queries

Simple value comparison:

Zerkel

```javascript
age > 25
```

Multiple comparisons. Make sure to use parentheses.

Zerkel

```javascript
(age > 25 and gender = "male")
```

Even more complexity:

Zerkel

```javascript
(age > 25 and gender = "male") or
   (age > 50 and gender = "female")
```

With [Reserved Keys](https://dev.kevel.co/v1.0/docs/reserved-keys):

JavaScript

```javascript
$device.brandName like "*Samsung*"
```

To target arrays, place BEFORE the key you are comparing:

Zerkel

```javascript
["27511", "27519", "27701", "27707"] contains $location.postalCode
```

The Zerkel interpreter in the UI automatically validates queries before you save the flight. If a query is invalid, an alert will appear:

The full [Zerkel parser](https://github.com/adzerk/zerkel) is hosted on Github.
