> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Script Rule

> Advanced JavaScript-based conditional logic with access to visitor data, device info, geolocation, and more

Script Rule is a Page Events node for custom JavaScript logic. Use it when query parameter rules are not enough and you need to route visitors based on session, device, traffic, or purchase data.

## When to Use Script Rule

Script Rules are ideal when you need:

* **Complex conditional logic** - Multiple conditions combined with AND/OR operators
* **Geolocation-based routing** - Direct visitors based on country, region, ISP, or connection type
* **Behavior-based decisions** - Route based on visit frequency, time between visits, or browsing patterns
* **Customer segmentation** - Different flows for existing customers vs new visitors
* **Anti-fraud protection** - Detect suspicious patterns like rapid page visits or VPN usage
* **Device/Platform targeting** - Advanced device detection beyond simple mobile/tablet/desktop
* **Tag-based routing** - Check for multiple tags with complex logic
* **Click attribution** - Route based on traffic source, click age, or IP matching

<Note>
  Script Rules execute on the server before the page loads, making them perfect for security-sensitive decisions that shouldn't be exposed to the browser.
</Note>

## How Script Rules Work

1. **Server-Side Execution**: Script Rules run on the server before the page loads
2. **Return Boolean**: Your script must return `true` or `false`
3. **Flow Control**:
   * `true` → **Output 1**, the Yes path
   * `false` → **Output 2**, the No path
4. **Available Data**: You have access to pre-loaded visitor data (see below)

<Note>
  **The purpose-built conditions are Script Rules too.** *Is From Country*, *Is From State*, *Is From EU*, *Is From Timezone*, *Is Using VPN/Proxy*, *Is Customer*, *Has Purchased Any Upsell*, *Referred By Affiliate* and *Query Parameter Condition* all generate a script and store it on the node — the renderer treats any node carrying a script as a Script Rule. Prefer them when they fit: they are readable, validated, and use the same variables documented here. Reach for a raw Script Rule only for logic they cannot express.
</Note>

## Available Data Variables

### Core Variables

#### `is_whitelisted`

**Type:** Boolean\
**Description:** Whether the visitor is currently whitelisted

```javascript theme={null}
// Route whitelisted visitors differently
return is_whitelisted === true;
```

#### `whitelist_source`

**Type:** String | Null\
**Values:** `'same_request'`, `'same_request_blocked'`, `'cookie'`, `'cookie_blocked'`, `'expired_cookie'`, `'domain_all_whitelisted'`, `null`\
**Description:** How the whitelist status was determined. `same_request` means a **Whitelist visitor** node ran earlier in this same request, before this Script Rule.

```javascript theme={null}
// Only allow domain-level whitelist
return whitelist_source === 'domain_all_whitelisted';
```

#### `query`

**Type:** Object\
**Description:** All URL query parameters as key-value pairs

```javascript theme={null}
// Check multiple query parameters
return query.source === 'facebook' && query.campaign === 'spring2024';

// Check if parameter exists
return query.hasOwnProperty('affiliate_id');
```

#### `ip_address`

**Type:** String\
**Description:** Visitor's IPv4 address

```javascript theme={null}
// Block specific IP range
return !ip_address.startsWith('192.168.');
```

#### `ip_address6`

**Type:** String\
**Description:** Visitor's IPv6 address (if available)

```javascript theme={null}
// Allow only IPv6 traffic
return ip_address6 !== '' && ip_address6 !== null;
```

#### `referer` / `referrer`

**Type:** String\
**Description:** HTTP referrer URL (both spellings available)

```javascript theme={null}
// Check traffic source
return referer.includes('google.com') || referer.includes('facebook.com');

// Direct traffic only
return referer === '' || referer === null;
```

#### `merchant_code`

**Type:** String\
**Description:** Active payment processor code (e.g., 'buygoods', 'clickbank', 'digistore24')

```javascript theme={null}
// Route based on merchant
return merchant_code === 'buygoods';
```

***

### Device Information

#### `is_mobile`

**Type:** Boolean\
**Description:** Whether visitor is on a mobile device

```javascript theme={null}
// Mobile-only offers
return is_mobile === true;
```

#### `is_tablet`

**Type:** Boolean\
**Description:** Whether visitor is on a tablet device

```javascript theme={null}
// Exclude tablets from mobile offers
return is_mobile === true && is_tablet === false;
```

#### `device`

**Type:** Object\
**Description:** Detailed device information

**Available Properties:**

* `device.type` - Device type (e.g., 'smartphone', 'tablet', 'desktop')
* `device.brand` - Device brand (e.g., 'Apple', 'Samsung', 'Google')
* `device.model` - Device model
* `device.os` - Operating system
* `device.os_version` - OS version
* `device.browser` - Browser name
* `device.browser_version` - Browser version

```javascript theme={null}
// Target specific platforms
return device.os === 'iOS' && device.brand === 'Apple';

// Exclude old browsers
return device.browser !== 'Internet Explorer';

// Check OS version
return device.os === 'Android' && parseInt(device.os_version) >= 10;
```

**Page templates:** The same device and request fields (`is_mobile`, `is_tablet`, `device`, `query`, `is_customer`, etc.) are available in page content. Use `@if(request.is_mobile)` or `@if(is_mobile)` and `{{ request.* }}` — see [Page Variables → Request & device context](/pages/page-variables#request--device-context).

***

### Customer Data

#### `is_customer`

**Type:** Boolean\
**Description:** Whether visitor has made a purchase

```javascript theme={null}
// Existing customers only
return is_customer === true;

// New visitors only
return is_customer === false;
```

#### `is_test_customer`

**Type:** Boolean\
**Description:** Whether customer purchase was marked as test

```javascript theme={null}
// Exclude test purchases
return is_customer === true && is_test_customer === false;
```

#### `customer`

**Type:** Object\
**Description:** Customer information from last purchase

**Available Properties:**

* `customer.name` - Customer name
* `customer.email` - Customer email
* `customer.phone` - Customer phone
* `customer.country` - Customer country
* `customer.zip` - Postal code
* `customer.city` - City
* `customer.address` - Street address
* `customer.order_id` - Last order ID
* `customer.order_item` - Last purchased product code
* `customer.order_item_name` - Last purchased product name
* `customer.order_ids` - Array of all order IDs
* `customer.is_test` - Whether it's a test order

```javascript theme={null}
// Target customers from specific country
return is_customer && customer.country === 'US';

// Check if they bought specific product
return customer.order_item === 'product-123';

// Multiple purchases
return customer.order_ids && customer.order_ids.length > 1;
```

***

### Session & Tracking

#### `session`

**Type:** Object\
**Description:** A deliberately narrow slice of the visitor's session. **Only two keys are exposed:**

* `session.aff_id` — affiliate ID
* `session.aff_source` — affiliate source

```javascript theme={null}
// Specific affiliate only
return session.aff_id === 'affiliate-001';

// Any affiliate traffic
return session.aff_id !== null && session.aff_id !== '';
```

<Note>
  There is no `request`, `cookies` or `headers` object in a Script Rule. Header-derived facts are surfaced as `is_mobile`, `is_tablet`, `device` and `referer`; cookie-derived facts as `tags`, `is_whitelisted` and `is_customer`.
</Note>

#### `time` / `utc_timestamp`

**Type:** Number (Unix timestamp in milliseconds)\
**Description:** Current server time

```javascript theme={null}
// Check time of day (convert to hours)
const hour = new Date(time).getUTCHours();
return hour >= 9 && hour <= 17; // Business hours UTC

// Time-based routing
const now = new Date(utc_timestamp);
return now.getUTCDay() === 0 || now.getUTCDay() === 6; // Weekends
```

***

### Tags

#### `tags`

**Type:** Array of Strings\
**Description:** All tags assigned to the visitor (from `tag_` cookies)

```javascript theme={null}
// Check if visitor has specific tag
return tags.includes('vip_customer');

// Check multiple tags
return tags.includes('viewed_vsl') && tags.includes('clicked_cta');

// Has any tags
return tags.length > 0;
```

***

### IP Geolocation Data (Advanced)

To use IP geolocation data, your script must reference `ip_whois` - the system automatically loads this data only when needed for performance.

#### `ip_whois`

**Type:** Object\
**Description:** IP geolocation, connection and security information.

<Warning>
  **The country code lives on `ip_whois.country_code`, not `ip_whois.country`.** `country` holds the full country **name** (e.g. `"Spain"`). Timezone, ISP and proxy data are nested objects, not flat keys. These are the paths the built-in **Is From Country / State / EU / Timezone** and **Is Using VPN/Proxy** nodes generate, so matching them keeps hand-written rules consistent with the UI ones.
</Warning>

**Location**

* `ip_whois.country_code` — ISO country code (`'US'`, `'GB'`, `'DE'`)
* `ip_whois.country` — full country name (`'Spain'`)
* `ip_whois.continent`, `ip_whois.continent_code`
* `ip_whois.region` — region/state name · `ip_whois.region_code` — region/state code
* `ip_whois.city`
* `ip_whois.postal`
* `ip_whois.latitude`, `ip_whois.longitude`
* `ip_whois.is_eu` — boolean

**Timezone** (`ip_whois.timezone` is an object)

* `ip_whois.timezone.id` — IANA ID (`'Europe/Madrid'`)
* `ip_whois.timezone.abbr`, `.is_dst`, `.offset`, `.utc`

**Connection** (`ip_whois.connection` is an object)

* `ip_whois.connection.isp` — ISP name
* `ip_whois.connection.org` — organisation
* `ip_whois.connection.asn` — AS number
* `ip_whois.connection.domain`

**Security** (`ip_whois.security` is an object)

* `ip_whois.security.proxy`, `.vpn`, `.tor`, `.anonymous`, `.hosting`

Also present: `ip_whois.ip`, `ip_whois.type` (`IPv4`/`IPv6`), `ip_whois.success`.

<Warning>
  Using `ip_whois` adds \~10-20ms to script execution time as it requires a geolocation lookup. The lookup only runs if the literal string `ip_whois` appears in your script — so remove the reference entirely when you do not need it.
</Warning>

```javascript theme={null}
// Target specific countries
return ip_whois && (ip_whois.country_code == 'US' || ip_whois.country_code == 'CA');

// Block certain regions
return ip_whois && ip_whois.country_code != 'CN' && ip_whois.country_code != 'RU';

// Block VPNs, proxies and datacentre traffic
const sec = ip_whois && ip_whois.security;
return !!sec && sec.proxy != true && sec.vpn != true && sec.hosting != true;

// EU visitors
return ip_whois && ip_whois.is_eu == true;

// Timezone-based routing
return ip_whois && ip_whois.timezone.id == 'America/New_York';

// ISP-based routing
const isp = (ip_whois && ip_whois.connection && ip_whois.connection.isp) || '';
return isp.includes('Comcast') || isp.includes('Verizon');

// Block a known network by AS number
return !(ip_whois && ip_whois.connection && ip_whois.connection.asn == 32934);
```

<Tip>
  Security flags may come back as `true`/`false` **or** `1`/`0` depending on the lookup provider. Compare with `==` rather than `===`, or coerce with `!!`.
</Tip>

***

### Click Data (Advanced)

<Note>
  Click data is available when there's a click ID present. This is commonly used on upsells but can be available on any page with click tracking.
</Note>

#### `click_data`

**Type:** Object\
**Description:** Information about the original ad click

**Available Properties:**

* `click_data.time` - Click timestamp (Unix seconds)
* `click_data.seconds_ago` - Seconds since click
* `click_data.ip_address` - Click IP address (IPv4)
* `click_data.ip_address6` - Click IP address (IPv6)
* `click_data.ip_address_matches` - Does current IP match click IP

```javascript theme={null}
// Click must be recent (within 1 hour)
return click_data.seconds_ago < 3600;

// IP must match original click
return click_data.ip_address_matches === true;

// Old clicks only
return click_data.seconds_ago > 86400; // Over 24 hours

// Combined check
return click_data.ip_address_matches && click_data.seconds_ago < 1800; // Same IP within 30min
```

***

### Visit Data (Advanced)

To use visit data, your script must reference `visit_data` - the system automatically loads visitor behavior metrics when referenced.

#### `visit_data`

**Type:** Object\
**Description:** Comprehensive visitor behavior and history

**Available Properties:**

* `visit_data.first_visit` - First visit timestamp
* `visit_data.time_since_first_visit` - Milliseconds since first visit
* `visit_data.visit_count` - Total number of visits
* `visit_data.last_visit` - Last visit timestamp
* `visit_data.time_since_last_visit` - Milliseconds since last visit
* `visit_data.ip_address` - First visit IP (IPv4)
* `visit_data.ip_address6` - First visit IP (IPv6)
* `visit_data.session_id` - First session ID
* `visit_data.has_multiple_user_agents` - Used different browsers/devices
* `visit_data.unique_user_agent_count` - Number of different user agents
* `visit_data.page_visit_count_30min` - Page visits in last 30 minutes
* `visit_data.page_visit_count_all_time` - Total page visits ever
* `visit_data.unique_pages_visited` - Number of different pages visited
* `visit_data.average_time_between_visits` - Average time between visits (ms)
* `visit_data.direct_visits_count` - Visits without referrer
* `visit_data.referrer_visits_count` - Visits with referrer
* `visit_data.rapid_visits_detected` - Suspicious rapid visiting pattern

<Warning>
  Using `visit_data` adds \~100–300ms to script execution time because it loads visit history. Only use when behavior-based logic is essential.
</Warning>

```javascript theme={null}
// First-time visitors only
return visit_data.visit_count === 1;

// Returning visitors
return visit_data.visit_count > 1;

// Visited within last hour
const oneHour = 60 * 60 * 1000;
return visit_data.time_since_last_visit < oneHour;

// Visited long ago, re-engagement
const thirtyDays = 30 * 24 * 60 * 60 * 1000;
return visit_data.time_since_first_visit > thirtyDays && visit_data.visit_count > 1;

// Block suspicious behavior (bot detection)
return visit_data.rapid_visits_detected !== true && 
       visit_data.page_visit_count_30min < 20;

// High-intent visitors
return visit_data.unique_pages_visited >= 3 && visit_data.visit_count >= 2;

// Check if user switched devices (possible sharing)
return visit_data.has_multiple_user_agents === false;
```

***

## Debugging Script Rules

### Using the Debug Window

The best way to debug Script Rules is with the **Debug Window**. It shows what happens when your script runs.

**How to Debug:**

1. **Open the Debugger** - Click the **"Debugger"** button in the Page Builder or Page Events interface
2. This will open your page with the **Debug Window** automatically activated
3. **Navigate to "Page Events" tab** in the Debug Window to see Script Rule execution details
4. **Reload the page** if needed to trigger the Script Rule

**What You'll See:**

The Debug Window shows Script Rule details:

* **Result**: `TRUE` or `FALSE` - which path was taken
* **Execution Time**: How long the script took to run (in milliseconds)
* **Next Path**: Which branch the flow followed
* **Console Messages**: All your `console.log()`, `console.warn()`, and `console.error()` output
* **Errors**: Full error messages if the script failed
* **Used IP Whois**: Whether geolocation data was loaded
* **Used Click Data**: Whether click data was accessed
* **Has Customer Data**: Whether customer information was available
* **Script Preview**: First few lines of your script code
* **Full Context**: Complete evaluation data with all variable values

<Note>
  The Debug Window is the most efficient way to debug Script Rules. It shows you everything that happened during execution, including all console output and the exact data that was available.
</Note>

### Console Logging

You can use `console.log()` to debug your Script Rules:

```javascript theme={null}
console.log('Current country:', ip_whois.country_code);
console.log('Visit count:', visit_data.visit_count);
console.log('Is customer:', is_customer);

return ip_whois.country_code == 'US';
```

Console logs appear in the **Debug Window "Page Events" tab** with real-time, expandable details.

<Tip>
  Use console logging liberally during development to understand what data is available and how your conditions evaluate. Click "Debugger" in the Page Builder to open the Debug Window and see all logs.
</Tip>

**Example Debugging Session:**

```javascript theme={null}
// Log all available data to understand what you have
console.log('Query params:', query);
console.log('Is mobile:', is_mobile);
console.log('Is customer:', is_customer);
console.log('Visit count:', visit_data?.visit_count);
console.log('Country:', ip_whois?.country_code);

// Log your condition results
const isEligible = ip_whois.country_code == 'US' && visit_data.visit_count > 1;
console.log('Is eligible:', isEligible);

return isEligible;
```

Then in the Debug Window (opened by clicking "Debugger"), you'll see all these logs with their values, making it easy to spot issues with your logic.

For more details on using the Debug Window, see the [Debug Window documentation](/debugging/debug-window).

***

## Example Use Cases

### Example 1: Geographic Targeting

```javascript theme={null}
// US and Canada only, block VPNs
return (ip_whois.country_code == 'US' || ip_whois.country_code == 'CA') &&
       ip_whois.security.proxy != true &&
       ip_whois.security.hosting != true;
```

### Example 2: Customer Segmentation

```javascript theme={null}
// Returning customers who haven't visited in 30+ days
const thirtyDays = 30 * 24 * 60 * 60 * 1000;
return is_customer === true && 
       visit_data.time_since_last_visit > thirtyDays;
```

### Example 3: Anti-Fraud Protection

```javascript theme={null}
// Block suspicious patterns when click data is available
return click_data.ip_address_matches === true &&
       click_data.seconds_ago < 3600 &&
       visit_data.rapid_visits_detected !== true &&
       ip_whois.security.tor != true &&
       ip_whois.security.proxy != true;
```

### Example 4: Device & Platform Targeting

```javascript theme={null}
// iOS users only, version 14 or higher
return device.os === 'iOS' && 
       parseInt(device.os_version) >= 14 &&
       device.brand === 'Apple';
```

### Example 5: Behavior-Based Routing

```javascript theme={null}
// High-engagement visitors: viewed 3+ pages, visited 2+ times
return visit_data.unique_pages_visited >= 3 &&
       visit_data.visit_count >= 2 &&
       tags.includes('viewed_vsl');
```

### Example 6: Multi-Condition Affiliate Routing

```javascript theme={null}
// Specific affiliate from US, mobile device, first-time visitor
return session.aff_id === 'AFF123' &&
       ip_whois.country_code == 'US' &&
       is_mobile === true &&
       visit_data.visit_count === 1;
```

### Example 7: Time-Based Offers

```javascript theme={null}
// Weekend special offer (UTC)
const now = new Date(utc_timestamp);
const dayOfWeek = now.getUTCDay(); // 0 = Sunday, 6 = Saturday
return dayOfWeek === 0 || dayOfWeek === 6;
```

### Example 8: Tag-Based Progressive Disclosure

```javascript theme={null}
// Visitor watched VSL and clicked CTA but hasn't purchased
return tags.includes('watched_vsl') &&
       tags.includes('clicked_cta') &&
       is_customer === false;
```

***

## Best Practices

### Performance Optimization

1. **Avoid Heavy Operations When Possible**
   * Only reference `ip_whois` if you need geolocation
   * Only reference `click_data` if you need click attribution (requires click ID)
   * Only reference `visit_data` if you need behavior metrics

2. **Simple Checks First**
   ```javascript theme={null}
   // Good: Check simple conditions before heavy operations
   if (!is_customer) return false; // Fast check first

   // Then check heavy data
   return ip_whois.country_code == 'US';
   ```

3. **Use Tags for Behavior Tracking**
   ```javascript theme={null}
   // Show different upsell based on whether they watched the VSL
   // Tag 'watched_vsl' is set on VSL page when video completes
   return tags.includes('watched_vsl');
   ```

### Logic Clarity

1. **Comment Your Code**
   ```javascript theme={null}
   // Route high-value traffic: US/CA, mobile, new visitors
   return (ip_whois.country_code == 'US' || ip_whois.country_code == 'CA') &&
          is_mobile === true &&
          visit_data.visit_count === 1;
   ```

2. **Break Complex Logic into Steps**
   ```javascript theme={null}
   // Check geographic eligibility
   const isEligibleCountry = ip_whois.country_code == 'US';

   // Check device requirements
   const isCorrectDevice = is_mobile && !is_tablet;

   // Check behavior requirements
   const isNewVisitor = visit_data.visit_count === 1;

   return isEligibleCountry && isCorrectDevice && isNewVisitor;
   ```

3. **Use Meaningful Variable Names**
   ```javascript theme={null}
   const isVipCustomer = is_customer && customer.order_ids.length > 3;
   const isRecentVisit = visit_data.time_since_last_visit < (7 * 24 * 60 * 60 * 1000);

   return isVipCustomer && isRecentVisit;
   ```

### Error Handling

1. **Check for Null/Undefined**
   ```javascript theme={null}
   // Good: Check if data exists before using it
   return ip_whois && ip_whois.country_code == 'US';

   // Good: Array check
   return customer.order_ids && customer.order_ids.length > 0;
   ```

2. **Provide Fallback Values**
   ```javascript theme={null}
   // Fallback to false if data unavailable
   const country = ip_whois?.country_code || 'unknown';
   return country == 'US';
   ```

### Testing

1. **Test Both Paths**
   * Verify the `true` path works as expected
   * Verify the `false` path works as expected
   * Test edge cases (missing data, null values, etc.)

2. **Use Debug Window**
   * Click "Debugger" in Page Builder or Page Events to open Debug Window
   * View console logs and script execution details in the "Page Events" tab

3. **Test with Different IPs/Devices**
   * Use VPN to test different countries
   * Use browser dev tools to simulate mobile devices
   * Test with different referrers and query parameters

***

## Troubleshooting

### Script Returns Unexpected Results

**Problem:** Script always takes same path regardless of data

**Solutions:**

1. **Use the Debug Window** - Click "Debugger" in the Page Builder or Page Events to see the actual result and all data
2. Check your return statement - must return boolean
3. Use `console.log()` to debug variable values
4. Verify data is available (not null/undefined)
5. Check for typos in property names

```javascript theme={null}
// Debug example - add these logs and check Debug Window
console.log('Country:', ip_whois?.country_code);
console.log('Visit count:', visit_data?.visit_count);
console.log('Is customer:', is_customer);

return ip_whois.country_code == 'US';
```

Then check the Debug Window → Page Events tab to see:

* The actual `Result` (TRUE or FALSE)
* All your console logs
* What data was actually available
* The exact path taken (`Next Path`)

### Script Execution Errors

**Problem:** Script fails and takes `false` path

**Solutions:**

1. **Check Debug Window** - Click "Debugger" in the Page Builder to see the exact error message
2. Check for syntax errors in your code
3. Look at the error details in Debug Window → Page Events → script\_rule event
4. Ensure you're not using unsupported JavaScript features
5. Verify all referenced variables exist

**Debugging Steps:**

1. Click **"Debugger"** in the Page Builder or Page Events interface
2. The Debug Window will open automatically
3. Go to **Page Events** tab
4. Find the `script_rule` event with red/error status
5. Look at the **Error** field for the exact error message
6. Check **Full Context** to see what data was available

**Common Errors:**

```javascript theme={null}
// Bad: Using unsupported features
const result = array.flatMap(x => x);  // flatMap not supported

// Good: Use supported methods
const result = array.map(x => x);

// Bad: Undefined variable
return customVariable === true;  // customVariable doesn't exist

// Good: Use available variables
return is_customer === true;
```

The Debug Window will show you the exact line and error type, making it much easier to fix.

### Slow Performance

**Problem:** Page loads slowly when script rule executes

**Solutions:**

1. Remove `ip_whois` reference if not needed
2. Remove `click_data` reference if not needed (requires click ID to be present)
3. Remove `visit_data` reference if not needed
4. Simplify logic to avoid heavy operations

```javascript theme={null}
// Slow: Uses all heavy operations
return ip_whois.country_code == 'US' &&
       click_data.seconds_ago < 3600 &&
       visit_data.visit_count > 1;

// Fast: Use simple checks only
return query.country === 'US' && is_customer === true;
```

### Data Not Available

**Problem:** `ip_whois`, `click_data`, or `visit_data` is empty/null

**Solutions:**

1. **ip\_whois**: Make sure you reference it in your script (triggers lookup)
2. **click\_data**: Only available when there's a click ID present
3. **visit\_data**: Data may not be available for first-time, brand-new visitors

```javascript theme={null}
// Safe check with fallback
if (!ip_whois || !ip_whois.country_code) {
    return false; // Default behavior if geolocation fails
}

return ip_whois.country_code == 'US';
```

***

## JavaScript Limitations

Script Rules run inside an isolated JavaScript sandbox — a fresh interpreter per execution, with no network, no filesystem and no access to the host process. That isolation sets the limits below.

### Sandbox limits

| Limit                       | Value                                           |
| --------------------------- | ----------------------------------------------- |
| Execution time              | 5 seconds — the script is interrupted past that |
| Memory                      | 8 MB                                            |
| Stack                       | 512 KB                                          |
| `eval()` / `new Function()` | Disabled                                        |

A script that throws is treated as **false**, so the flow takes Output 2. The error and any `console` output are captured and shown in the [Debug Window](/debugging/debug-window).

<Note>
  Your code is wrapped in a function before it runs, which is why it must **`return`** a value rather than just evaluate an expression. Write the body only — no `function` declaration of your own.
</Note>

### Supported Features

* Basic JavaScript syntax (ES5 + some ES6)
* Variables (`let`, `const`, `var`)
* Functions and arrow functions
* Arrays and objects
* Loops (`for`, `while`, `forEach`)
* Conditionals (`if`, `switch`, `ternary`)
* Comparison and logical operators
* `Math`, `Date`, `JSON` objects
* `String` and `Array` methods (most common ones)
* `console.log()` for debugging

### NOT Supported

* Async/await operations
* Promises
* Fetch API or HTTP requests
* Browser APIs (window, document, localStorage, etc.)
* ES6+ features like `flatMap`, `Object.fromEntries`
* Regular expressions with some advanced features
* Modules and imports

### Polyfills Included

The following are polyfilled automatically:

* `Array.prototype.includes()`
* `String.prototype.includes()`

<Warning>
  Always test your script rules thoroughly. If unsure about a JavaScript feature, test it with simple logic first before deploying to production.
</Warning>

***

## Related Documentation

* [Debug Window](/debugging/debug-window) - Learn how to debug Script Rules with the Debug Window
* [Page Events](/funnels/page-events) - Overview of the Page Events system
* [Page Events Node Reference](/funnels/page-events-nodes) - Every node type and its fields
* [Query Parameter Conditions](/funnels/query-parameters) - Simpler alternative for URL parameter checks
* [Content Visibility Control](/pages/visitor-based-content) - Using whitelisting with containers
* [Dynamic Content](/funnels/dynamic-content) - Personalizing content based on conditions
* [Exit Popups](/funnels/exit-popups) - Behavior-based exit intent detection

<Note>
  Start with simple Script Rule logic. Add complexity only when you can test each branch and see the expected result in the Debug Window.
</Note>
