Filtering

Complete guide to Hood Web SDK filtering system: operators, macros, lookup tables, and advanced targeting.
developer

What are Filters?

Filters are the decision-making engine of the Hood Web SDK. They determine whether an action (modal, push notification, tag execution) should run after a trigger fires. Think of filters as conditional logic that evaluates user data, browser information, and custom variables to make intelligent targeting decisions.

Filtering Pipeline

Event Occurs → Trigger Fires → Filters Evaluate → Action Executes (if filters pass)

Example: A user scrolls 50% down the page (trigger), the system checks if they’re from Germany OR using mobile (filters), and if any condition is true, shows a promotional modal (action).

Info

Important Client-Side Limitation

Filters are executed exclusively client-side and are limited to data available to the SDK. This means:

  • No server-side data: Filters cannot access server-side user profiles, purchase history, or other backend data
  • Limited data scope: Only data explicitly set via setuserproperties, identify, setVar, or available in browser context
  • Real-time only: Filters work with data available at the moment of evaluation, not historical data
  • Privacy constraints: Cannot access sensitive server-side information for privacy and security reasons

Available data sources:

  • User properties set via SDK methods (data.*)
  • Browser information (window.BW_INFO.*)
  • URL parameters (url.*)
  • Cookies (cookie.*)
  • Custom variables (var.*)
  • Window/document properties (window.*, document.*)

Not available:

  • Server-side user profiles
  • Complete purchase history
  • Backend analytics data
  • Historical user behavior
  • Server-side personalization data

Filter Object Structure

Every filter is a JSON object with specific fields that define what to check, how to check it, and what value to compare against.

Filter Object Fields

  • c (string, required): Check expression - Variable to evaluate. If contains macros like {{data.country}}, they are resolved to their actual values before evaluation
  • o (string, required): Operator - Comparison method (eq, gt, contains, etc.)
  • m (string, required): Match value - Value to compare against
  • d (string, optional): Default - Value to use when check expression returns empty string or null. Prevents filter failures due to missing data
  • cu (string, optional): Custom undefined - Value to use when check expression returns undefined. Handles cases where variable doesn’t exist
  • cn (string, optional): Custom null - Value to use when check expression returns null. Provides fallback for null values
  • ct (string, optional): Custom true - Value to use when check expression returns boolean true. Converts boolean to string for comparison
  • cf (string, optional): Custom false - Value to use when check expression returns boolean false. Converts boolean to string for comparison
  • f (string, optional): String formatting - Transforms the final value to lowercase (lc), uppercase (uc), or snake_case (sc) before any further processing. Does not affect the matching logic itself

Basic Example:

{
  "c": "{{data.country}}",
  "o": "eq", 
  "m": "DE"
}

Advanced Example:

{
  "c": "{{data.user_segment}}",
  "o": "eq",
  "m": "premium",
  "d": "free",
  "cu": "unknown",
  "f": "lc"
}

String Formatting Example:

// Without formatting - might fail due to case differences
{ "c": "{{data.user_type}}", "o": "eq", "m": "Premium" }

// With formatting - ensures consistent comparison
{ "c": "{{data.user_type}}", "o": "eq", "m": "premium", "f": "lc" }
// If data.user_type = "PREMIUM", it becomes "premium" before comparison

Field Definitions

Check Expression

Defines the variable or expression to evaluate. This is the “left side” of the comparison.

Usage:

{ "c": "{{data.country}}" }
{ "c": "{{window.BW_INFO.t}}" }
{ "c": "{{call.getCartTotal()}}" }

Macro Resolution: If the value contains macros like {{data.country}}, they are resolved to their actual values before evaluation. For example, {{data.country}} becomes "DE" if the user is from Germany.

Examples:

  • Static value: "premium"
  • User data: "{{data.user_segment}}"
  • Browser info: "{{window.BW_INFO.t}}"
  • Custom function: "{{call.getCartTotal()}}"

Operator

Defines how the check value (c) is compared against the match value (m).

Available Operators:

  • Equality: eq, neq
  • Numeric: gt, gte, lt, lte, between
  • String: contains, startswith, endswith
  • Boolean/Existence: isset, isempty, istrue, isfalse
  • Negated: not.contains, isnset, isnempty, etc.
  • Advanced: matchregex, matchcss

Usage:

{ "o": "eq" }      // Equals
{ "o": "gt" }      // Greater than
{ "o": "contains" } // Contains substring

Match Value

Defines the value to compare against the check expression result. This is the “right side” of the comparison.

Usage:

{ "m": "DE" }           // String value
{ "m": "100" }          // Numeric value
{ "m": "[50, 200]" }    // Array for 'between' operator

Data Types: Can be string, number, boolean, or array depending on the operator used.

Important: Match values are static - they cannot contain macros like {{data.country}}. Only the check expression (c) supports macro resolution.

Default

Provides a fallback value when the check expression returns empty string or null.

When to use: Prevents filter failures due to missing or empty data.

Usage:

{
  "c": "{{data.user_segment}}",
  "o": "eq",
  "m": "premium",
  "d": "free"  // Use "free" if user_segment is empty/null
}

Example: If {{data.user_segment}} returns "" or null, the filter will use "free" instead.

Custom Undefined

Provides a value when the check expression returns undefined.

When to use: Handles cases where the variable doesn’t exist or hasn’t been set.

Usage:

{
  "c": "{{data.last_purchase}}",
  "o": "isset",
  "cu": "never"  // Use "never" if last_purchase is undefined
}

Example: If {{data.last_purchase}} is undefined, the filter will use "never".

Custom Null

Provides a value when the check expression returns null.

When to use: Handles cases where the variable exists but has a null value.

Usage:

{
  "c": "{{data.subscription}}",
  "o": "eq",
  "m": "active",
  "cn": "inactive"  // Use "inactive" if subscription is null
}

Example: If {{data.subscription}} is null, the filter will use "inactive".

Custom True

Provides a value when the check expression returns boolean true.

When to use: Converts boolean values to strings for comparison.

Usage:

{
  "c": "{{data.newsletter_subscribed}}",
  "o": "eq",
  "m": "yes",
  "ct": "yes"  // Use "yes" if newsletter_subscribed is true
}

Example: If {{data.newsletter_subscribed}} is true, the filter will use "yes".

Custom False

Provides a value when the check expression returns boolean false.

When to use: Converts boolean values to strings for comparison.

Usage:

{
  "c": "{{data.newsletter_subscribed}}",
  "o": "eq",
  "m": "no",
  "cf": "no"  // Use "no" if newsletter_subscribed is false
}

Example: If {{data.newsletter_subscribed}} is false, the filter will use "no".

String Formatting

Transforms the final value before any further processing.

Available Formats:

  • lc: Convert to lowercase
  • uc: Convert to uppercase
  • sc: Convert to snake_case

Usage:

{
  "c": "{{data.user_type}}",
  "o": "eq",
  "m": "premium",
  "f": "lc"  // Transform to lowercase
}

Example: If {{data.user_type}} returns "PREMIUM", it gets transformed to "premium" before comparison.

Note: This only transforms the value - it doesn’t affect the matching logic itself.

Operators Reference

Operators define how the check value (c) is compared against the match value (m). The SDK supports multiple categories of operators for different data types and comparison needs.

Equality Operators

eq - Equals (exact match)

  • Description: Exact match using loose equality
  • Example: "DE" eq "DE" → ✅ True
  • Usage: { "c": "{{data.country}}", "o": "eq", "m": "DE" }

neq - Not equals

  • Description: Values are not equal
  • Example: "US" neq "DE" → ✅ True
  • Usage: { "c": "{{data.plan}}", "o": "neq", "m": "free" }

Numeric Operators

gt - Greater than

  • Description: Value is greater than match value
  • Example: 100 gt 50 → ✅ True
  • Usage: { "c": "{{data.age}}", "o": "gt", "m": "18" }

gte - Greater than or equal

  • Description: Value is greater than or equal to match value
  • Example: 50 gte 50 → ✅ True
  • Usage: { "c": "{{data.age}}", "o": "gte", "m": "18" }

lt - Less than

  • Description: Value is less than match value
  • Example: 25 lt 50 → ✅ True
  • Usage: { "c": "{{data.score}}", "o": "lt", "m": "100" }

lte - Less than or equal

  • Description: Value is less than or equal to match value
  • Example: 50 lte 50 → ✅ True
  • Usage: { "c": "{{data.score}}", "o": "lte", "m": "100" }

between - Between range

  • Description: Value is between min and max (expects array [min, max])
  • Example: 75 between [50, 100] → ✅ True
  • Usage: { "c": "{{data.age}}", "o": "between", "m": "[25, 65]" }

Common usage:

{ "c": "{{data.age}}", "o": "gte", "m": "18" }
{ "c": "{{call.getCartTotal()}}", "o": "between", "m": "[50, 200]" }

Note: Numeric operators automatically convert values to numbers. Non-numeric values return false.

String Operators

contains - Contains substring

  • Description: Checks if string contains substring (case-insensitive)
  • Example: "Hello World" contains "world" → ✅ True
  • Usage: { "c": "{{data.email}}", "o": "contains", "m": "@gmail.com" }
  • Array Support: Also works with arrays - checks if array includes the match value

startswith - Starts with

  • Description: Checks if string starts with prefix (case-insensitive)
  • Example: "JavaScript" startswith "java" → ✅ True
  • Usage: { "c": "{{url.path}}", "o": "startswith", "m": "/checkout" }

endswith - Ends with

  • Description: Checks if string ends with suffix (case-insensitive)
  • Example: "document.pdf" endswith ".pdf" → ✅ True
  • Usage: { "c": "{{data.filename}}", "o": "endswith", "m": ".pdf" }

Boolean & Existence Operators

isset - Is defined

  • Description: Checks if value is not undefined or null
  • Example: "value" isset → ✅ True
  • Usage: { "c": "{{data.email}}", "o": "isset", "m": "" }

isempty - Is empty

  • Description: Checks if value is empty string, array, or object
  • Example: "" isempty → ✅ True
  • Usage: { "c": "{{data.cart}}", "o": "isempty", "m": "" }

istrue - Is true

  • Description: Checks if value is boolean true or string "true"
  • Example: true istrue → ✅ True
  • Usage: { "c": "{{data.premium}}", "o": "istrue", "m": "" }

isfalse - Is false

  • Description: Checks if value is boolean false or string "false"
  • Example: false isfalse → ✅ True
  • Usage: { "c": "{{data.subscribed}}", "o": "isfalse", "m": "" }

Usage:

{ "c": "{{data.user_id}}", "o": "isset" }
{ "c": "{{data.newsletter}}", "o": "istrue" }
{ "c": "{{data.cart_items}}", "o": "isempty" }

Empty Check Details:

  • Strings: trim() === ""
  • Arrays: length === 0
  • Objects: Object.keys().length === 0
  • null: considered empty
  • undefined: not considered empty

Negated Operators

All string and boolean operators have negated versions:

not.contains - Does not contain

  • Description: Checks if string does NOT contain substring
  • Example: "Hello" not.contains "World" → ✅ True
  • Usage: { "c": "{{data.email}}", "o": "not.contains", "m": "@competitor.com" }

not.startswith - Does not start with

  • Description: Checks if string does NOT start with prefix
  • Example: "file.txt" not.startswith "doc" → ✅ True
  • Usage: { "c": "{{url.path}}", "o": "not.startswith", "m": "/admin" }

not.endswith - Does not end with

  • Description: Checks if string does NOT end with suffix
  • Example: "image.jpg" not.endswith ".png" → ✅ True
  • Usage: { "c": "{{data.filename}}", "o": "not.endswith", "m": ".tmp" }

isnset - Is not set

  • Description: Checks if value is undefined or null
  • Example: undefined isnset → ✅ True
  • Usage: { "c": "{{data.optional}}", "o": "isnset", "m": "" }

isnempty - Is not empty

  • Description: Checks if value is NOT empty
  • Example: "Hello" isnempty → ✅ True
  • Usage: { "c": "{{data.cart}}", "o": "isnempty", "m": "" }

isntrue - Is not true

  • Description: Checks if value is NOT boolean true
  • Example: false isntrue → ✅ True
  • Usage: { "c": "{{data.verified}}", "o": "isntrue", "m": "" }

isnfalse - Is not false

  • Description: Checks if value is NOT boolean false
  • Example: true isnfalse → ✅ True
  • Usage: { "c": "{{data.active}}", "o": "isnfalse", "m": "" }

### Advanced Operators

**`matchregex` - Regex match (case-sensitive)**
- Description: Tests value against regular expression pattern
- Example: `"[email protected]" matchregex "^[^@]+@[^@]+\\.[^@]+$"` → ✅ True
- Usage: `{ "c": "{{data.email}}", "o": "matchregex", "m": "^[^@]+@[^@]+\\.[^@]+$" }`

**`matchregexi` - Regex match (case-insensitive)**
- Description: Tests value against regular expression pattern (case-insensitive)
- Example: `"[email protected]" matchregexi "^[^@]+@[^@]+\\.[^@]+$"` → ✅ True
- Usage: `{ "c": "{{data.email}}", "o": "matchregexi", "m": "^[^@]+@[^@]+\\.[^@]+$" }`

**`notmatchregex` - Regex no match (case-sensitive)**
- Description: Tests that value does NOT match regex pattern
- Example: `"invalid" notmatchregex "^[^@]+@[^@]+\\.[^@]+$"` → ✅ True
- Usage: `{ "c": "{{data.input}}", "o": "notmatchregex", "m": "^[0-9]+$" }`

**`notmatchregexi` - Regex no match (case-insensitive)**
- Description: Tests that value does NOT match regex pattern (case-insensitive)
- Example: `"invalid" notmatchregexi "^[^@]+@[^@]+\\.[^@]+$"` → ✅ True
- Usage: `{ "c": "{{data.input}}", "o": "notmatchregexi", "m": "^[0-9]+$" }`

**`matchcss` - CSS selector match**
- Description: Tests if value matches CSS selector pattern
- Example: `"btn-primary" matchcss ".btn-primary"` → ✅ True
- Usage: `{ "c": "{{data.user_class}}", "o": "matchcss", "m": ".premium-user" }`

**`not.matchcss` - CSS selector no match**
- Description: Tests if value does NOT match CSS selector pattern
- Example: `"btn-secondary" not.matchcss ".btn-primary"` → ✅ True
- Usage: `{ "c": "{{data.element_class}}", "o": "not.matchcss", "m": ".disabled" }`

**Safety**: Regex patterns are validated to prevent catastrophic backtracking attacks.

## Macros and Data Sources

Macros allow you to access dynamic data from various sources using the `{{namespace.property}}` syntax. They're **resolved at runtime** - when a filter evaluates, macros like `{{data.country}}` are replaced with their actual values (e.g., `"DE"`) before the comparison happens. This enables dynamic filtering based on real-time data.




Info

Client-Side Data Only

Remember: All macro data sources are client-side only. The SDK can only access data that has been explicitly made available in the browser context through SDK methods or browser APIs. Server-side data, complete user profiles, or backend analytics are not accessible to filters.

### Data Namespaces **Available Data Sources** | Namespace | Description | Example | Use Case | |-----------|-------------|---------|----------| | `data.*` | **User properties** set via `setuserproperties` or `identify` | `{{data.country}}` | User segmentation | | `var.*` | **Transient variables** set via `setVar` | `{{var.cart_total}}` | Session data | | `cookie.*` | **Browser cookies** | `{{cookie.session_id}}` | Session tracking | | `window.*` | **Window object properties** | `{{window.BW_INFO.t}}` | Browser detection | | `document.*` | **Document properties** | `{{document.title}}` | Page context | | `url.*` | **Current URL parts** | `{{url.host}}` | Page targeting | | `referrer.*` | **Referrer URL parts** | `{{referrer.host}}` | Traffic source | | `session.*` | **Session data** | `{{session.vt}}` | Visit tracking | | `utm.*` | **UTM parameters** | `{{utm.campaign}}` | Campaign tracking | | `partner.*` | **Partner/ad platform data** | `{{partner.fbclid}}` | Retargeting | **Examples**: ```json { "c": "{{data.user_segment}}", "o": "eq", "m": "premium" } { "c": "{{window.BW_INFO.t}}", "o": "eq", "m": "mobile" } { "c": "{{url.path}}", "o": "contains", "m": "/checkout" }

Macro Resolution Example:

// Filter definition
{ "c": "{{data.country}}", "o": "eq", "m": "DE" }

// At runtime, if data.country = "DE", the filter becomes:
{ "c": "DE", "o": "eq", "m": "DE" }
// Result: ✅ True

Browser Information (BW_INFO)

Browser Detection Data

The SDK automatically collects browser information in window.BW_INFO:

PropertyDescriptionExample Values
nBrowser name"chrome", "firefox", "safari"
vBrowser version"120", "119"
tDevice type"mobile", "desktop"
httpsHTTPS support1 (yes), 0 (no)
zTimezone offset"-300" (EST), "0" (UTC)
lsLocalStorage available1 (yes), 0 (no)
wvWebView detection1 (yes), 0 (no)
ulUser language"en", "de", "fr"
pePush notifications enabled1 (yes), 0 (no)

Usage:

{ "c": "{{window.BW_INFO.t}}", "o": "eq", "m": "mobile" }
{ "c": "{{window.BW_INFO.ul}}", "o": "eq", "m": "en" }
{ "c": "{{window.BW_INFO.pe}}", "o": "eq", "m": "1" }

Custom Functions

Function Calls

You can call any JavaScript function that exists in the window object using the call.* namespace:

Syntax: {{call.functionName(arg1, arg2)}}

How it works: The SDK looks for functions in two places:

  1. Registered functions in md.fn[functionName] (if you’ve registered custom functions)
  2. Window functions in window[functionName] (any global function)

Example:

{ "c": "{{call.getCartTotal()}}", "o": "gte", "m": "100" }
{ "c": "{{call.getUserTier()}}", "o": "eq", "m": "premium" }

Function Requirements:

  • Function must exist in window object or be registered
  • Function must return a primitive type (string, number, boolean)
  • Function is executed safely within the SDK context

Example Functions:

// Global functions (automatically available)
window.getCartTotal = function() {
  return window.cart ? window.cart.total : 0;
};

window.getUserTier = function() {
  return window.user ? window.user.tier : 'free';
};

Function Safety: Functions are validated and executed safely within the SDK context.

Lookup Tables

Lookup tables provide static and dynamic data mapping capabilities for complex filtering scenarios.

Static Tables (ts)

Static Key-Value Tables

Static tables provide direct key-value lookups for consistent data mapping.

Syntax: {{lookup.TABLE_NAME.KEY}}

{
  "ts": {
    "currencies": {
      "DE": "EUR",
      "US": "USD", 
      "GB": "GBP",
      "FR": "EUR"
    },
    "regions": {
      "DE": "Europe",
      "US": "North America",
      "GB": "Europe"
    }
  }
}

Usage in Filters:

{ "c": "{{lookup.currencies.{{data.country}}}}", "o": "eq", "m": "EUR" }
{ "c": "{{lookup.regions.{{data.country}}}}", "o": "eq", "m": "Europe" }

Nested Macros: Keys can contain macros that are resolved before lookup.

Regex Tables (tr)

Pattern-Based Tables

Regex tables use pattern matching to find the first matching key and return its value.

Syntax: {{lookupr.TABLE_NAME.KEY}}

{
  "tr": {
    "user_agents": {
      ".*Chrome.*": "chrome",
      ".*Firefox.*": "firefox", 
      ".*Safari.*": "safari",
      ".*Mobile.*": "mobile"
    },
    "email_domains": {
      ".*@gmail\\.com$": "google",
      ".*@outlook\\.com$": "microsoft",
      ".*@yahoo\\.com$": "yahoo"
    }
  }
}

Usage in Filters:

{ "c": "{{lookupr.user_agents.{{window.BW_INFO.ua}}}}", "o": "eq", "m": "chrome" }
{ "c": "{{lookupr.email_domains.{{data.email}}}}", "o": "eq", "m": "google" }

Pattern Matching: First matching pattern wins, order matters.

Advanced Filter Features

Value Transformations

Custom Value Handling

Filters support multiple transformation options for handling different value states:

  • d: Default - Used when check result is empty/null. Example: "d": "free"
  • cu: Custom undefined - Used when result is undefined. Example: "cu": "unknown"
  • cn: Custom null - Used when result is null. Example: "cn": "empty"
  • ct: Custom true - Used when result is boolean true. Example: "ct": "yes"
  • cf: Custom false - Used when result is boolean false. Example: "cf": "no"

Example:

{
  "c": "{{data.subscription}}",
  "o": "eq",
  "m": "active",
  "d": "inactive",
  "cu": "unknown",
  "cn": "null"
}

String Formatting (f field):

FormatDescriptionPurposeExample
lcLowercaseTransforms value to lowercase"Hello""hello"
ucUppercaseTransforms value to uppercase"hello""HELLO"
scSnake caseConverts spaces to underscores"Hello World""hello_world"

Practical Example:

{
  "c": "{{data.user_type}}",
  "o": "eq", 
  "m": "premium",
  "f": "lc"
}
// If data.user_type = "PREMIUM", it gets transformed to "premium" before comparison
// The matching logic still compares "premium" == "premium"

Multiple Filters

Filter Arrays

Multiple filters can be combined using arrays. By default, ANY filter must pass for the action to execute (OR logic).

Example:

{
  "filters": [
    { "c": "{{data.country}}", "o": "eq", "m": "DE" },
    { "c": "{{window.BW_INFO.t}}", "o": "eq", "m": "mobile" },
    { "c": "{{data.age}}", "o": "gte", "m": "18" }
  ]
}

How it works: The system uses .some() logic - if ANY filter in the array returns true, the action executes.

Practical Example:

{
  "filters": [
    { "c": "{{data.country}}", "o": "eq", "m": "DE" },      // User from Germany
    { "c": "{{data.country}}", "o": "eq", "m": "FR" },      // OR User from France  
    { "c": "{{data.country}}", "o": "eq", "m": "IT" }       // OR User from Italy
  ]
}
// Action executes if user is from ANY of these countries

Note: There is no require_all_triggers option. The filtering system always uses OR logic for multiple filters.

Practical Examples

Understanding Data Limitations

What You CAN Filter On

// ✅ Available - Data set via SDK
{ "c": "{{data.user_segment}}", "o": "eq", "m": "premium" }

// ✅ Available - Browser information
{ "c": "{{window.BW_INFO.t}}", "o": "eq", "m": "mobile" }

// ✅ Available - URL parameters
{ "c": "{{url.searchParams.utm_source}}", "o": "eq", "m": "google" }

// ✅ Available - Custom variables
{ "c": "{{var.cart_total}}", "o": "gt", "m": "100" }

What You CANNOT Filter On

// ❌ Not available - Server-side data
{ "c": "{{server.user_purchase_history}}", "o": "gt", "m": "5" }

// ❌ Not available - Backend analytics
{ "c": "{{analytics.lifetime_value}}", "o": "gt", "m": "1000" }

// ❌ Not available - Complete user profile
{ "c": "{{profile.subscription_tier}}", "o": "eq", "m": "enterprise" }

// ❌ Not available - Historical data
{ "c": "{{history.last_login_days}}", "o": "lt", "m": "7" }

Workaround: Set relevant data via SDK methods before filtering:

// Set data that filters can access
Hood('setuserproperties', {
  user_segment: 'premium',
  subscription_tier: 'enterprise',
  cart_total: window.cart?.total || 0
});

E-commerce Targeting

Cart Abandonment Recovery

Show a discount modal to users who added items to cart but haven’t completed checkout:

{
  "triggers": [
    { "type": "beforeunload" }
  ],
  "filters": [
    { "c": "{{call.getCartTotal()}}", "o": "gt", "m": "0" },
    { "c": "{{data.has_completed_checkout}}", "o": "isfalse" },
    { "c": "{{data.country}}", "o": "eq", "m": "DE" }
  ]
}

User Segmentation

Target premium users with exclusive offers:

{
  "triggers": [
    { "type": "scroll", "config": { "vertical": 75 } }
  ],
  "filters": [
    { "c": "{{data.user_tier}}", "o": "eq", "m": "premium" },
    { "c": "{{data.last_purchase}}", "o": "isset" },
    { "c": "{{lookup.regions.{{data.country}}}}", "o": "eq", "m": "Europe" }
  ]
}

Geographic Targeting

Location-Based Campaigns

Show region-specific content based on user location:

{
  "triggers": [
    { "type": "load" }
  ],
  "filters": [
    { "c": "{{lookup.currencies.{{data.country}}}}", "o": "eq", "m": "EUR" },
    { "c": "{{lookup.regions.{{data.country}}}}", "o": "eq", "m": "Europe" },
    { "c": "{{window.BW_INFO.ul}}", "o": "eq", "m": "en" }
  ]
}

Mobile-Specific Offers

Target mobile users with app download prompts:

{
  "triggers": [
    { "type": "timer", "config": { "time": 10000 } }
  ],
  "filters": [
    { "c": "{{window.BW_INFO.t}}", "o": "eq", "m": "mobile" },
    { "c": "{{data.has_app}}", "o": "isfalse" },
    { "c": "{{data.app_store_visits}}", "o": "lt", "m": "3" }
  ]
}

Behavioral Targeting

Engagement-Based Targeting

Show content based on user behavior patterns:

{
  "triggers": [
    { "type": "scroll", "config": { "vertical": 90 } }
  ],
  "filters": [
    { "c": "{{data.page_views}}", "o": "gte", "m": "5" },
    { "c": "{{data.time_on_site}}", "o": "gte", "m": "300" },
    { "c": "{{data.bounce_rate}}", "o": "lt", "m": "0.3" }
  ]
}

Return Visitor Targeting

Target returning users with personalized content:

{
  "triggers": [
    { "type": "pageView" }
  ],
  "filters": [
    { "c": "{{session.vt}}", "o": "isset" },
    { "c": "{{data.last_visit}}", "o": "gte", "m": "7" },
    { "c": "{{data.newsletter_subscribed}}", "o": "isfalse" }
  ]
}

Best Practices

Performance Optimization

Efficient Filtering

  1. Order filters by selectivity - Put most restrictive filters first
  2. Use appropriate operators - isset is faster than eq for existence checks
  3. Cache expensive operations - Use var.* for computed values
  4. Limit regex complexity - Keep regex patterns simple and safe

Example:

{
  "filters": [
    { "c": "{{data.user_id}}", "o": "isset" },           // Fast existence check
    { "c": "{{data.country}}", "o": "eq", "m": "DE" },   // Simple equality
    { "c": "{{data.email}}", "o": "matchregex", "m": "^[^@]+@[^@]+\\.[^@]+$" } // Complex check last
  ]
}

Error Handling

Robust Filter Design

  1. Provide defaults - Use d, cu, cn fields for missing data
  2. Validate inputs - Test filters with various data states
  3. Handle edge cases - Consider null, undefined, and empty values
  4. Monitor performance - Watch for slow regex or complex lookups

Example:

{
  "c": "{{data.user_segment}}",
  "o": "eq",
  "m": "premium",
  "d": "free",        // Default for empty values
  "cu": "unknown",    // Handle undefined
  "cn": "null"        // Handle null
}

Troubleshooting

Common Issues

Debugging Filters

Filter not matching:

  • Check macro syntax: {{data.property}} not {data.property}
  • Verify data exists: Use isset operator first
  • Test with simple values: Start with eq operator

Performance issues:

  • Avoid complex regex patterns
  • Limit nested macro calls
  • Use var.* for expensive computations

Data not available:

  • Ensure data is set before filter evaluation
  • Use setuserproperties for user data
  • Check browser compatibility for window.* properties

Example Debug Filter:

{
  "c": "{{data.debug_info}}",
  "o": "eq",
  "m": "{{data.user_id}}",
  "d": "no_user_id",
  "cu": "no_data",
  "cn": "null_data"
}