Rules

The Ad Forecaster accepts arbitrary boolean expressions as targeting and filtering rules.

Such boolean expressions can be comparisons (with the format key <operator> value), geo-targeting operations or a combination of expressions using boolean operators (AND, OR and NOT).

For example, to target Firefox users near San Francisco, one could use the following targeting rule: user-agent contains "Firefox" and userCoordinates near (37.757815, -122.5076401) by 10 km.

Supported Operators

Boolean operators

Operator Meaning Example
!, not boolean “not” !(country = "US")
|, ||, or boolean “or” country = "US" | age < 50
&, &&, and boolean “and” age > 20 & age < 50

Comparison operators

Operator Meaning Example
=, ==, is equal to country = "US"
<, lt less than age < 50
>, gt greater than age > 20
<= less than or equal age <= 50
>= greater than or equal age >= 20
in present in list of items country in ("US", "FR")
contains string contains user-agent contains "Chrome"
startsWith string starts with user-agent startsWith "Mozilla"
endsWith string ends with user-agent endsWith "43.0"
arrayContainsAny array contains any keywords arrayContainsAny ("blog", "article")
arrayContainsAll array contains all keywords arrayContainsAll ("blog", "article")

Geo targeting operators

Operator Meaning Example
near by value near coordinate userCoordinates near (41.176296, -8.596050) by 30 km

Latitude and longitude coordinates should be defined in decimal degrees. The supported units are km for kilometers and mi for miles.

Functions

Operator Meaning Example
isDefined returns true if a variable is defined isDefined(country)

Undefined Variables

Sometimes a log row can have undefined variables (e.g. some users might not have a geo location).

When an undefined variable is used on a sub-expression, that sub-expression is evaluated to false.

It is important to take this into account when negating sub-expressions. For example, if the variable age is undefined, age < 18 will evaluate to false, but !(age >= 18) will evaluate to true.

This can be addressed by using the isDefined function to check if a variable is defined (e.g. isDefined(age) && age < 18 and isDefined(age) && !(age >= 18) are the equivalent).

Accessing Indexed Variables

For keys that are described as being “indexable” (FieldDescription), usually for container types (array and map), it is possible to perform an indexing operation on the key in order to access a specific element inside the container and create a rule.

For example, assuming a field dynamicTargeting as an associative array from string to string (map String -> String), we are able to perform an indexing operation with the following syntax dynamicTargeting["gender"]. We can then create a valid rule like this: dynamicTargeting["gender"] = "male".

For array types, the index is the position of the element we’re trying to access (and the " are not mandatory). E.g. arrayField[3] > 10 or arrayField["3"] > 10.

Whenever an indexing operation fails (i.e. the specified key that’s being accessed doesn’t exist), it is treated as an undefined variable.

Additional Fields

Depending on the context, some additional fields might be available (e.g. dayOfWeek). Please refer to the API documentation to see which additional fields are available.

Useful Tips

  • Instead of using multiple equalities, use the in operation, for example:
    • gender = "m" || gender = "f"gender in ("m", "f"));
    • !(device = "phone") && !(device = "tablet")!(device in ("phone", "tablet")));
  • You can do most wildcard-style string matches by combining string operations, for example:
    • *.sapo.ptdomain endsWith ".sapo.pt"
    • www.facebook.*domain startsWith "www.facebook."
    • forecaster.*.adforecaster.comdomain startsWith "forecaster." AND domain endsWith ".adforecaster.com"
    • *.twitter.*domain contains ".twitter."
  • Use your domain knowledge to avoid tautological rules, for example:
    • dayOfWeek in (1,2,3,4,5,6,7)true
    • browser = "Edge" && operativeSystem in ("Windows", "Linux")browser = "Edge"
  • Extract common expressions so that they are evaluated only once, for example:
    • (browser = "Edge" && gender = "f") || (browser = "Firefox" && gender = "f")gender = "f" && (browser in ("Edge", "Firefox"))