GAM → Kevel Zerkel Translator

Translates Google Ad Manager custom targeting into Kevel Zerkel expressions.

← Playground

Assumptions

Endpoints

GET/

Interactive playground — visual rule builder with live Zerkel output.

GET/segments

Demo segment catalog. These segments are assumed to already exist in the Kevel network.

{
  "segments": [
    { "id": 3,  "name": "People who like Mexico" },
    { "id": 7,  "name": "Frequent Travelers" },
    { "id": 12, "name": "Travel Intent — Europe" },
    ...
  ]
}

POST/translate/gam

Translate GAM custom targeting to a Kevel CustomTargeting Zerkel string.

Input A — Structured (primary, for Advendio integration)

FieldTypeDescription
groupsrequiredarrayArray of targeting groups. Multiple groups are joined by groupOperator.
groups[].criteriarequiredarrayCriteria within this group, joined by groups[].operator. Each criterion is either key/value or segment (see below).
groups[].operatoroptionalstringHow criteria inside this group are joined: AND (default) or OR.
groupOperatoroptionalstringHow groups are joined: OR (default) or AND.

Key/value criterion

FieldTypeDescription
keyrequiredstringTargeting key name. Hyphens are converted to underscores.
opoptionalstringIS (default) or IS_NOT. Also accepts operator as alias.
valuesoptionalstring[]Target values. Multiple values within a criterion are joined with OR.

Segment criterion

FieldTypeDescription
typerequiredstringMust be "segment". (Alternatively, presence of segmentIds is enough.)
opoptionalstringIS (default) or IS_NOT.
segmentIdsrequirednumber[]Kevel segment IDs, emitted as-is. Multiple IDs are joined with OR.
{
  "groups": [
    {
      "criteria": [
        { "key": "category",  "op": "IS",     "values": ["shoes", "boots"] },
        { "type": "segment",  "op": "IS",     "segmentIds": [3, 7] }
      ]
    }
  ],
  "groupOperator": "OR"
}

Input B — String (secondary, for quick testing)

FieldTypeDescription
gamTargetingrequiredstringGAM-style targeting string: key=v1,v2 AND key!=v3. The reserved key segment (also segments / $user.segments) targets segments by ID: segment=3,7.
{ "gamTargeting": "category=shoes,boots AND segment=3,7" }

Response 200

{
  "zerkel": "\"(category contains \\\"shoes\\\" or category contains \\\"boots\\\") and ($user.segments contains 3 or $user.segments contains 7)\"",
  "warnings": []
}
Note on escaping: The zerkel value is a JSON string. The actual expression saved to Kevel's CustomTargeting field includes the outer quotes with inner quotes escaped.

GET/health

Health check.

{ "ok": true }

Translation Logic

Key/value operators

GAM opValuesZerkel output
ISonekey contains "value"
ISmany(key contains "v1" or key contains "v2")
IS_NOTonenot (key contains "value")
IS_NOTmanynot (key contains "v1" or key contains "v2")

Segment operators

OpIDsZerkel output
ISone$user.segments contains 3
ISmany($user.segments contains 3 or $user.segments contains 7)
IS_NOTonenot ($user.segments contains 3)
IS_NOTmanynot ($user.segments contains 3 or $user.segments contains 7)

Grouping

Warnings

The response always includes a warnings array. Non-fatal issues (empty groups, missing keys, unknown operators, segment IDs not in the demo catalog) are reported there rather than returning a 400 — the valid criteria are still translated.

Quick-test with curl

# Structured with a segment criterion
curl -X POST https://ct.kevel.me/translate/gam \\
  -H "Content-Type: application/json" \\
  -d '{
    "groups": [{
      "criteria": [
        { "key": "category", "op": "IS", "values": ["shoes"] },
        { "type": "segment", "op": "IS", "segmentIds": [3, 7] }
      ]
    }]
  }'

# String with the reserved segment key
curl -X POST https://ct.kevel.me/translate/gam \\
  -H "Content-Type: application/json" \\
  -d '{ "gamTargeting": "category=shoes AND segment=3,7" }'