Cloakup API
Guides

Campaign filters

Allowed values, query params, devices, OS, browser, ISP, IPs, and filter enums

Create/update returns 422 if a value does not match the format or is not in the API allowlist. Do not guess country names or free-form locale strings.

Allowed values

FieldTypeMax itemsFormat
filters.geolocation.countriesstring[]256ISO 3166-1 alpha-2, uppercase
filters.browser_language.languagesstring[]255IETF language tag, all lowercase (xx or xx-yy)
filters.state.statesstring[]100Place name (see below)
filters.city.citiesstring[]100Place name (see below)
pages.offers[].segmentation.countrystring[]256Same as filters.geolocation.countries
filters.device.devicesstring[]—desktop, smartphone, tablet, unknown
filters.os.osstring[]—Lowercase detector name (see OS)
filters.browser.browsersstring[]—Lowercase detector name (see Browser)
filters.isp.ispsstring[]—Substring of the GeoIP ISP name
filters.blacklist / filters.whiteliststring[]—Exact IP string

Country codes

Used in filters.geolocation.countries and pages.offers[].segmentation.country.

RuleValue
FormatExactly 2 uppercase letters (ISO 3166-1 alpha-2)
Examples"BR", "US", "PT"
Invalid"br", "Brazil", "BRA", "brasil"

Browser language codes

Used in filters.browser_language.languages.

RuleValue
FormatLowercase IETF language tag: xx or xx-yy (hyphen, not underscore)
Examples"pt-br", "en", "es"
Invalid"pt-BR", "portuguese", "pt_BR"

State and city names

Used in filters.state.states and filters.city.cities.

RuleValue
Length1–100 characters (trimmed)
Allowed charsUnicode letters, spaces, ', -, .
Must start withA letter
Examples"São Paulo", "California", "St. Louis"
Invalid"123", "", "City@Name"

Free-text GeoIP place names — not ISO codes.

URL query params (filters.query)

Cloakup matches the query string after ? in the visitor URL against filters.query.

You always send two objects with the same keys:

ObjectWhat it stores
paramsParam name → values to match (always a string[], never a plain string)
rulesParam name → how to compare (equals, contains, starts_with, ends_with)

"asiudhasudhasd": "equals" does not set the value. It only says: compare the URL param named asiudhasudhasd with exact match. The value lives in params as an array: "asiudhasudhasd": ["123u1basj"].

Visitor URL:

https://track.example.com/slug?asiudhasudhasd=123u1basj

Matching config:

"query": {
  "allow": true,
  "remove_params": false,
  "condition": "some",
  "params": {
    "asiudhasudhasd": ["123u1basj"]
  },
  "rules": {
    "asiudhasudhasd": "equals"
  }
}

Every key in params needs the same key in rules. Empty params: {} and rules: {} means no URL param filtering.

FieldTypeDescription
paramsRecord<string, string[]>Param name → list of values in the URL
rulesRecord<string, string>Per-param comparison. Not the value itself
condition"some" | "every"some = at least one param must match; every = all must match
allowbooleantrue = allow when params match; false = block when params match
remove_paramsbooleanStrip matched params from the URL before redirect

Match rules

The value in rules is the operator. The value in params is what you compare against.

RuleMeaningparams valueMatchesDoes not match
equalsExact value["google"]?utm_source=google?utm_source=Google, ?utm_source=googleads
containsSubstring anywhere["google"]?utm_source=googleads?utm_source=facebook
starts_withPrefix["Cjw"]?gclid=CjwKEAjabc?gclid=xxCjw
ends_withSuffix["-br"]?utm_campaign=promo-br?utm_campaign=br-promo

Wildcard (*)

"*" is a special value in params (not a rule, not a glob). If that key is present in the URL, the checker accepts any value and skips equals / contains / starts_with / ends_with.

URLConfigResult
?fbclid=IwAR123abc"fbclid": ["*"]Match — key exists
?fbclid="fbclid": ["*"]Match — key exists, even empty
?utm_source=google"fbclid": ["*"]No match — fbclid missing
?utm_source=googleads"utm_source": ["goo*"]No match — "goo*" is a literal string, not a pattern

You still send a rules entry for that key (use "equals"). The operator is ignored when "*" is in the values list.

"params": { "fbclid": ["*"] },
"rules": { "fbclid": "equals" }

Do not mix "*" with other values on the same key (["*", "google"]). "*" already matches any value, so the extra entries never run.

Examples

Send "utm_source": ["google"], never "utm_source": "google". A plain string returns 422.

Referer (filters.referer)

filters.referer.domains is a list of hostnames. Send the hostname only (no https://, no path). www. is stripped at match time.

* in a referer domain matches that subdomain slot. Use *.facebook.com to allow every subdomain of facebook.com.

ConfigMatchesDoes not match
"facebook.com"https://facebook.com/foo, https://www.facebook.com (www. is stripped)https://m.facebook.com
"*.facebook.com"https://m.facebook.com, https://l.facebook.comhttps://facebook.com (no subdomain)

*.facebook.com does not match the apex host facebook.com. Add both entries if you need apex + subdomains.

block_null: true blocks visitors with no referer (direct access).

"referer": {
  "allow": true,
  "block_null": true,
  "domains": ["facebook.com", "*.facebook.com", "instagram.com"]
}

Device (filters.device)

Empty devices: [] means no device filtering.

allow: true = only listed devices pass. allow: false = listed devices are blocked.

ValueWhat it matches
smartphonePhones. Phablet is treated as smartphone
tabletTablets
desktopDesktops and laptops
unknownDetector could not classify the device
"device": {
  "allow": true,
  "devices": ["smartphone", "tablet"]
}

OS (filters.os)

Empty os: [] means no OS filtering. Names are lowercase as the device detector reports them.

ValueMatches
androidAndroid
iosiOS
windowsWindows
macmacOS
gnu/linuxGeneric Linux desktop. Send this, not "linux"
ubuntuUbuntu
unknownDetector could not classify the OS
otherAny OS not in windows, mac, gnu/linux, android, ios, ubuntu
"os": {
  "allow": true,
  "os": ["android", "ios"]
}

Browser (filters.browser)

Empty browsers: [] means no browser filtering. Match is case-insensitive exact on the detector name.

Common values: chrome, chrome mobile, chrome mobile ios, chrome webview, safari, mobile safari, firefox, microsoft edge, opera, samsung browser, miui browser, android browser, internet explorer, facebook, instagram app, whatsapp, baidu spark.

"browser": {
  "allow": true,
  "browsers": ["chrome", "chrome mobile", "safari", "mobile safari"]
}

ISP (filters.isp)

Empty isps: [] means no ISP filtering. Match is a case-insensitive substring of the GeoIP ISP string — "claro" matches Claro S.A..

Use names as they appear in GeoIP (carriers, not brand slogans).

"isp": {
  "allow": true,
  "isps": ["Claro", "Vivo", "Oi", "TIM"]
}

IP lists (filters.blacklist / filters.whitelist)

Both are arrays of exact IP strings (no CIDR). Empty [] means no IP list.

FieldEffect
blacklistThat IP is blocked
whitelistThat IP always passes, including when other filters would deny. GET /v1/campaigns/:id returns is_test_mode: true if your IP is in this list
"blacklist": ["203.0.113.10", "198.51.100.22"],
"whitelist": ["192.0.2.80"]

Required filter keys

On create/update, these top-level keys under filters must be present:

geolocation, referer, query, domain, browser, browser_language, isp, os, user_agent, blacklist

Optional keys (defaults apply): ad-network flags, deny_always, bots, proxy, adspy, cloakup_ai, state, city, network_type, device, whitelist.

Full JSON Schema: Schemas → CampaignFilters.

On this page