Building Tests8 min read

Targeting

Filter who sees a test with AND/OR rules over 18 fields: location, device, traffic source, UTM tags, time, cookies, custom properties.

Targeting

Filter who sees a test with AND/OR rules over 18 fields — location, device, traffic source, UTM tags, time, cookies, and your own custom properties.

URL matching decides which pages a test runs on; targeting decides which visitors see it once they're on those pages. Leave it empty and the test runs for everyone matching the URL — the right default for most experiments. Add rules when you want to compare variants in a specific audience (mobile only, paid social only, enterprise plan customers) or when you're running a personalization test where the rules are the variants.

Targeting rules form a tree. The root is an AND or OR group; each child is either a condition (one field, one operator, one or more values) or another nested group. The SDK and the server both evaluate the tree, with the field deciding where evaluation happens — geo fields resolve from the visitor IP server-side, cookies evaluate in the browser, and most fields work on both sides.

Rule tree at a glance

AND
├── country in ["US", "CA"]
├── device_type equals "mobile"
└── OR
    ├── utm_source equals "newsletter"
    └── custom_property[plan] equals "pro"

Read top-down: a visitor matches when they're in the US or Canada, on a mobile device, and either came from the newsletter or has a Pro plan. Mix and nest groups freely.

Field reference

Eighteen built-in fields grouped by what they describe. Server-resolved fields are evaluated from the visitor's IP and mirrored to the client. Server + client fields work on both sides. Client-only fields (cookies) evaluate only in the browser because the server never sees the value.

Location

Geo-IP derived. Resolved server-side and mirrored to the SDK so the browser agrees.
  • countryCountrystringServer-resolved

    ISO-3166 country code resolved from the visitor IP. Use the country picker for a known list.

    country in ["US", "CA", "MX"]
  • regionRegion / StatestringServer-resolved

    Sub-country region resolved from the visitor IP. Granularity varies by country.

    region equals "California"

Device & browser

Inferred from user-agent. Evaluable everywhere.
  • device_typeDevice typeenumServer + client

    desktop, mobile, or tablet.

    device_type equals "mobile"
  • osOperating systemenumServer + client

    windows, macos, ios, android, linux, other.

    os in ["ios", "android"]
  • browserBrowserenumServer + client

    chrome, firefox, safari, edge, opera, other.

    browser equals "safari"
  • screen_widthScreen widthnumberServer + client

    Reported screen width in CSS pixels. Useful for layout-specific tests.

    screen_width greater_than 1280
  • languageBrowser languagestringServer + client

    BCP 47 language tag from the browser, e.g. en-US, pt-BR. Use starts_with for language families.

    language starts_with "fr"

Traffic source

Where the visitor came from. Sourced from referrer and URL parameters.
  • traffic_sourceTraffic source bucketenumServer + client

    direct, organic_search, paid_search, social, email, referral. Otter A/B picks the bucket from referrer + utm_medium.

    traffic_source in ["paid_search", "social"]
  • utm_sourceutm_sourcestringServer + client

    Raw utm_source from the URL.

    utm_source equals "newsletter"
  • utm_mediumutm_mediumstringServer + client

    Raw utm_medium from the URL.

    utm_medium contains "cpc"
  • utm_campaignutm_campaignstringServer + client

    Raw utm_campaign from the URL.

    utm_campaign starts_with "spring-"
  • referrerReferrerstringServer + client

    Document referrer (where the visitor came from). Empty for direct navigation.

    referrer contains "reddit.com"

Time

Server-side clock + visitor’s local context.
  • time_of_dayTime of daytimeServer + client

    Local visitor time. Supports between for time windows.

    time_of_day between [09:00, 17:00]
  • day_of_weekDay of weekenumServer + client

    monday through sunday.

    day_of_week in ["saturday", "sunday"]

Visitor & custom signals

Built-in audience signals plus whatever you push from your code.
  • visitor_typeVisitor typeenumServer + client

    new or returning, derived from the Otter visitor UUID cookie.

    visitor_type equals "returning"
  • url_paramURL parameterkeyedServer + client

    Test a specific query string parameter by key.

    url_param[plan] equals "pro"
  • cookieCookiekeyedClient-only

    Read any cookie on the visitor’s browser by name. Client-only because the server never sees the cookie value.

    cookie[loggedIn] equals "true"
  • custom_propertyCustom propertykeyedServer + client

    Any property you set via optimo.identify({ ... }). Use for plan, signup date, LTV, internal flags, etc.

    custom_property[plan] equals "enterprise"

Operator reference

Operators available depend on the field's data type. The wizard only offers valid combinations.

Equality

Direct comparisons. Work on string, enum, and keyed fields.

equalsnot_equalsinnot_in

Substring (string fields only)

Match against any part of the string. regex evaluates case-insensitively; you anchor it yourself.

containsnot_containsstarts_withregex

Existence

Check whether the field is set on the visitor at all.

existsnot_exists

Numeric & time

Range comparisons. Available on screen_width (numeric) and time_of_day (time).

greater_thangreater_than_or_equalless_thanless_than_or_equalbetween

Targeting tips

Start broad, narrow later. Most tests should target everyone. Add conditions only when you have a specific audience hypothesis (“this CTA works better for mobile”) or when running personalization.

Prefer signals you control over geo-IP. Cookies, UTM tags, and custom properties from optimo.identify() are deterministic. Geo-IP is mostly right but can mis-classify VPN, corporate, and mobile-carrier traffic.

Be careful with regex. Most targeting bugs come from a regex that looked right but matched the wrong audience. Test the pattern in DevTools (new RegExp(pattern, 'i').test(value)) before saving.

Finalize targeting before launch. Editing targeting mid-test doesn't reassign existing visitors, but it does change who enters going forward, which can shift the variant ratio.

Frequently asked questions

Quick answers to the questions teams ask most about this part of Otter A/B.