FunnelFlux Pro API DocumentsFunnelFlux Pro API Documents
  • Changelog
  • Status
  • Dashboard
  • Documentation
  • Authentication
  • Domains
  • Assets
  • Reporting
Getting Started
    General InformationAuthenticationGenerating Asset IDsAPI Best PracticesCreating FunnelsLogic ScriptsWebhook PayloadsChangelog
Getting Started

Logic Scripts

Logic Scripts are reusable routing scripts for funnel logic nodes. A script reads visitor, request, tracking-field, visitor-tag, or submitted-form context and returns a route key. Funnel connections from a logic node then match that key through connectionLogicParams.onRouteKeys[].

Logic Scripts are global assets. Create and manage them through the Assets API, then reference the Logic Script asset from a funnel logic node.

Runtime model

A Logic Script is a Go-statement snippet, not a full Go file. Do not include package, import, or a function wrapper. Every path must return a string route key.

Code
if country == "US" { return "us" } if oneOf(country, "CA", "AU", "NZ") { return "tier_one" } return "default"

Route keys must match ^[a-z0-9_]{1,64}$. The reserved fallback key is default.

Always connect a default route from each funnel logic node. Runtime uses that connection when the script cannot safely choose one of your other connected routes. This covers invalid code, execution errors, missing data, or code that returns a route key you did not connect.

Keep route keys explicit where possible. For example, return "us" is easy for the API to validate and easy for a funnel connection to match. Returning a variable can work at runtime, but the API cannot know every value that variable may contain, so you must be extra careful to connect default.

Funnel wiring

For each connection leaving a logic node, set connectionLogicParams.onRouteKeys[] to the route keys that should use that connection.

Code
{ "connectionLogicParams": { "onRouteKeys": ["us", "tier_one"] } }

Use one connection with onRouteKeys: ["default"] as the runtime fallback. This should go somewhere safe, such as a general offer path, a catch-all lander, or an internal diagnostic path.

API workflow

The usual flow is:

  1. Create or update a Logic Script asset through the Assets API.
  2. Validate the script before saving or before wiring it into a funnel.
  3. Create a funnel logic node that references the Logic Script asset.
  4. Connect each returned route key through connectionLogicParams.onRouteKeys[].
  5. Connect default as the fallback route.

See the Logic Scripts API for the full Logic Script asset endpoints.

Builder and editor integrations should also use the helper endpoints in the Assets API:

Code
GET /v1/logicscripts/language Returns the backend-owned language catalog: variables, helpers, operators, route-key rules, max code size, and templates. POST /v1/logicscripts/validate Validates { "code": "..." } and returns whether the script is valid, which route keys were found, and any errors.

Language rules

Maximum code size is 10,240 bytes.

String variables

These string values are available inside every Logic Script:

Code
country city region continent timezone deviceType brand model os osVersion browser browserVersion mainLanguage browserLanguage ip isp connectionType mobileCarrier userAgent referrer initialReferrer currentURL trackingDomain trafficSourceID

Integer variables

These integer values are available inside every Logic Script:

Code
hour minute weekday dayOfMonth month year utcOffsetHours

Useful notes

  • Time variables are UTC.
  • weekday uses Go values, where Sunday is 0.
  • month uses Go values, where January is 1.
  • continent is a full name such as Asia, Europe, North America, or Oceania, not a continent code.
  • Logic Script variables mirror public URL token formatting where possible.
  • timezone is formatted like the public {timezone} token, such as GMT+7 or GMT-5.
  • utcOffsetHours is the matching whole-hour integer offset for time helpers, such as 7, -5, or 0.
  • In general, string variables will have the same values that you see in FunnelFlux reporting.

Helpers

These helper functions can be used inside your scripts:

Code
len(value string) int trackingField(name string) string dataBuffer(name string) string hasVisitorTag(id string) bool oneOf(value string, candidates ...string) bool containsAny(value string, substrings ...string) bool timeInRange(startHHMM int, endHHMM int, utcOffsetHours int) bool timeAtOrAfter(hhmm int, utcOffsetHours int) bool timeAtOrBefore(hhmm int, utcOffsetHours int) bool localDay(utcOffsetHours int) string strings.Contains(value string, substr string) bool strings.HasPrefix(value string, prefix string) bool strings.HasSuffix(value string, suffix string) bool strings.ToLower(value string) string strings.ToUpper(value string) string

trackingField() and dataBuffer() names must match [A-Za-z0-9_ -]{1,64}. Use trackingField("utm_source") instead of map syntax such as trackingFields["utm_source"].

Time helpers use explicit integer UTC hour offsets, not display strings. Pass utcOffsetHours or a literal like -7, 0, or 3. Do not pass the timezone string variable to timeInRange(), timeAtOrAfter(), timeAtOrBefore(), or localDay().

timeInRange(startHHMM, endHHMM, utcOffsetHours) uses HHMM integer times and supports overnight wraparound. For example, timeInRange(2200, 600, 3) means 22:00 through 06:00 in UTC+3.

Allowed operators

Use these operators for comparisons and boolean logic:

Code
== != < > <= >= && || !

Allowed syntax

Use these Go statement forms for readable deterministic routing:

  • if / else
  • switch
  • Local variables
  • Local non-recursive functions or closures with typed bool, int, or string arguments and exactly one bool, int, or string return value
  • Closures must return on every path
  • Comments with // or /* */
  • Local []string literals for helper inputs

Do not use

These language features and built-ins are blocked:

  • Imports
  • Package declarations
  • Loops
  • Goroutines
  • Maps or indexing
  • Pointers
  • Unsupported packages
  • Arbitrary method calls
  • The following Go functions and statements: defer, select, append, make, new, panic, print, println, recover, delete, copy

However, list expansion is specifically supported for helper calls, for example:

Code
blocked := []string{"bad isp llc", "example proxy network"} if oneOf(strings.ToLower(isp), blocked...) { return "blocked" } return "default"

Examples

Country tier routing:

Code
if country == "US" { return "us" } if oneOf(country, "CA", "AU", "NZ") { return "tier_one" } if oneOf(country, "MX", "ES", "AR", "CL", "CO", "PE") { return "spanish_speakers" } return "default"

Business-hours routing:

Code
isWorkDay := oneOf(localDay(utcOffsetHours), "monday", "tuesday", "wednesday", "thursday", "friday") if isWorkDay && timeInRange(700, 1800, utcOffsetHours) { return "business_hours" } return "default"

Overnight local-time routing:

Code
// Uses the visitor's UTC offset. Do not pass the timezone string. if timeInRange(2200, 600, utcOffsetHours) { return "overnight" } return "default"

Local closure routing:

Code
isMobile := func() bool { return deviceType == "mobile" } isBusinessHour := func(offset int) bool { return timeInRange(900, 1700, offset) } if isMobile() && isBusinessHour(utcOffsetHours) { return "mobile_business_hours" } return "default"

Tracking-field routing:

Code
source := strings.ToLower(trackingField("utm_source")) switch { case source == "": return "is_blank" case source == "google_ads": return "google_ads" case strings.Contains(source, "newsletter"): return "newsletter" } return "default"

Data-buffer form routing:

Code
answer := strings.ToLower(dataBuffer("question_1")) consent := strings.ToLower(dataBuffer("consent")) if oneOf(answer, "a", "b") { return "answer_ab" } if oneOf(consent, "true", "yes", "1") { return "consented" } return "default"

AI prompt

Use this section in two parts. Copy the short prompt first, edit the goal and route keys, then paste the documentation block afterward or at the end of the same message.

Some AI tools handle long pastes differently. Claude may turn the documentation block into a text snippet or attachment, while other tools such as ChatGPT may paste it directly into the chat. Pasting the editable prompt first keeps the part you need to change easy to deal with.

Instruction Prompt

Code
You are writing a FunnelFlux Pro Logic Script. # Goal <describe the routing goal in plain language — the conditions you want to match and roughly where each should go. You don't need to name the route keys; choose clear, semantic ones yourself.> # Reference Use the attached document titled: "Logic Script behavior and syntax documentation" It has the full code format, allowed variables, helper functions, operators, syntax rules, and restrictions. # Output Return three things: 1. A one-sentence, plain-text description of what the script does, concise enough to paste into the script's description field in FunnelFlux (no formatting, no route-key jargon dump). 2. The Logic Script code in a code snippet box (or artifact), with a short comment above each route explaining when it fires. 3. A bullet list of the route keys you used, each with a one-line note on when it triggers, so I know what to wire up in the funnel. Begin the code with a brief comment naming the script's purpose.

Logic Script behavior and syntax documentation

Code
# Logic Script behavior and syntax documentation FunnelFlux Logic Scripts are reusable routing scripts for funnel logic nodes. A script reads visitor, request, tracking-field, visitor-tag, time, and submitted-form context, then returns a single route key as a string. Funnel connections leaving the logic node match the returned route key through `connectionLogicParams.onRouteKeys[]`. ## Core format - A Logic Script is a Go-statement snippet, not a full Go file. - Do not include package declarations. - Do not include imports. - Do not include a function wrapper. - Every execution path must return a string route key. - Statements run top to bottom; the first `return` reached wins, so order your rules from most specific to most general. - Maximum code size is `10240` bytes. ## Route-key rules - Route keys must match `^[a-z0-9_]{1,64}$`. - Use lowercase letters, numbers, and underscores. - Use semantic keys such as `business_hours` or `blocked_isp`, not `a`/`b`. - Prefer explicit string returns such as `return "us"`. - Avoid returning a variable as a route key unless the funnel has a safe default connection to catch unexpected values. - Always include a `default` return path as the final statement. ## The `default` route: what it is for `default` is the safety net for things going wrong, not a normal business outcome. The default *connection* in the funnel is used when: - the code is invalid or fails to execute, - required data is missing due to a system error (for example, IP geolocation failed, so `country` is empty), - or the script returns a route key that is not connected to anything. Because of this, you normally do **not** write explicit branches for error-state empty values. For example, you would not add an `if country == "" { ... }` branch — a blank country means IP resolution failed on our side, which is an error condition, and letting it fall through to the final `return "default"` is the correct handling. This is different from a deliberate "matched none of my rules" outcome. When a value resolves correctly but simply doesn't match any of your business rules, give that its own named route (for example, `unmatched`) rather than folding it into `default`. That keeps real traffic separable from genuine errors in reporting and wiring. ## Funnel wiring rules These matter when manipulating Logic Scripts inside funnels via API. If you are only writing isolated script code, you can ignore them. - Each connection leaving a logic node uses `connectionLogicParams.onRouteKeys[]`. - Connect every route key your script can return to a destination. - Always connect `onRouteKeys ["default"]` to a safe fallback destination. > Builder/editor integrations can use the Assets API helper endpoints: > `GET /v1/logicscripts/language` returns the backend-owned catalog > (variables, helpers, operators, route-key rules, max size, templates), > and `POST /v1/logicscripts/validate` checks a script and returns whether > it is valid, which route keys it found, and any errors. ## Variable context - Variables mirror how URL `{tokens}` work in the runtime routing system. - Tokens are replaced by data resolved from the current tracked visitor. - Geolocation values are derived from the visitor IP. - All variables concern the specific visitor currently tracked in a funnel. - `trackingDomain` is the custom domain used at redirect time. - `trafficSourceID` is an internal FunnelFlux traffic source asset ID. ## Available string variables `country`, `city`, `region`, `continent`, `timezone`, `deviceType`, `brand`, `model`, `os`, `osVersion`, `browser`, `browserVersion`, `mainLanguage`, `browserLanguage`, `ip`, `isp`, `connectionType`, `mobileCarrier`, `userAgent`, `referrer`, `initialReferrer`, `currentURL`, `trackingDomain`, `trafficSourceID` ## Available integer variables `hour`, `minute`, `weekday`, `dayOfMonth`, `month`, `year`, `utcOffsetHours` ## Value notes - Time variables (`hour`, `minute`, `weekday`, etc.) are UTC and refer to the current timestamp. For visitor-local time, use the time helpers with `utcOffsetHours` rather than these raw UTC values. - `weekday` uses Go values: Sunday is `0`, Saturday is `6`. - `month` uses Go values: January is `1`, December is `12`. - `country` is an ISO country code such as `US` or `TH` (uppercase). - `country` is effectively always populated for a real visitor. It is empty only when IP geolocation fails — treat that as an error and let it reach `default` (see "The `default` route"). - `continent` is a full name such as `Asia`, `Europe`, `North America`, or `Oceania` — not a code such as `AS` or `EU`. - `city`, `region`, `isp`, `connectionType`, `mobileCarrier`, `deviceType`, `brand`, `model`, `os`, `browser`, and similar values are resolved from the visitor IP and user agent. When a specific value can't be determined they typically return the literal string `unknown`, not an empty string. An empty value therefore signals a resolution error — which is exactly what `default` is for. Do not write branches for any of these being blank; an unresolved IP or user agent is an error state, not a routing case. (If you ever need to catch a non-resolving value deliberately, test for `== "unknown"`, not `== ""`.) - `referrer` is the current request referrer, falling back to `initialReferrer` when empty. An empty `referrer` is a normal, expected state (direct traffic, stripped referrer) — branch on it deliberately if your logic cares about it. This is the main string variable where blank is a real case rather than an error. - `trafficSourceID` is an internal traffic source asset ID (roughly a 14-character alphanumeric string). You cannot know a specific ID unless the user provides it. The one fixed, system-level value you can rely on is `organic`: organically tracked traffic always has `trafficSourceID == "organic"` (lowercase). - `timezone` is a display string formatted like the public `{timezone}` token — `GMT+7`, `GMT-5`, `GMT+0`. Do **not** pass it to the time helpers; they take an integer offset, not this string. - `utcOffsetHours` is the matching whole-hour integer offset for the same visitor (`7`, `-5`, `0`). This is the value you pass to `timeInRange()`, `timeAtOrAfter()`, `timeAtOrBefore()`, and `localDay()` for visitor-local time routing. You do not hardcode an offset — use this variable so each visitor is evaluated in their own local time. - `mainLanguage` and `browserLanguage` reflect captured visit languages. - In general, string variables hold the same values shown in reporting. ## Available helpers | Helper | Returns | | --- | --- | | `len(value string)` | `int` | | `trackingField(name string)` | `string` | | `dataBuffer(name string)` | `string` | | `hasVisitorTag(id string)` | `bool` | | `oneOf(value string, candidates ...string)` | `bool` | | `containsAny(value string, substrings ...string)` | `bool` | | `timeInRange(startHHMM int, endHHMM int, utcOffsetHours int)` | `bool` | | `timeAtOrAfter(hhmm int, utcOffsetHours int)` | `bool` | | `timeAtOrBefore(hhmm int, utcOffsetHours int)` | `bool` | | `localDay(utcOffsetHours int)` | `string` | | `strings.Contains(value, substr string)` | `bool` | | `strings.HasPrefix(value, prefix string)` | `bool` | | `strings.HasSuffix(value, suffix string)` | `bool` | | `strings.ToLower(value string)` | `string` | | `strings.ToUpper(value string)` | `string` | ## Helper notes - `oneOf()` does exact matching against many candidate values. - `containsAny()` does substring matching against many candidate substrings. - Both `oneOf()` and `containsAny()` accept either inline arguments or an expanded `[]string`: - inline: `oneOf(country, "US", "CA", "AU")` - expanded slice: `oneOf(country, tierOne...)` where `tierOne := []string{"US", "CA", "AU"}` - Use `strings.ToLower()` to normalise a value once before case-insensitive comparisons, rather than lowercasing repeatedly. - `localDay()` returns a lowercase English day name: `"monday"`, `"tuesday"`, … `"sunday"`. Compare against lowercase literals. - `hasVisitorTag(id)` takes the ID of a visitor-tag asset from the FunnelFlux UI. Only the user knows their own tag IDs. If the user hasn't supplied one, use a clearly-labelled placeholder (for example `"REPLACE_WITH_TAG_ID"`) and tell them to swap in the real ID from the interface. - The time helpers (`timeInRange`, `timeAtOrAfter`, `timeAtOrBefore`, `localDay`) take an integer UTC hour offset — pass the `utcOffsetHours` variable (or a literal like `-7`, `0`, `3`). Never pass the `timezone` display string (`GMT+7`) to them. - `timeInRange(start, end, offset)` uses HHMM integer times and supports overnight wraparound: when `end` is earlier than `start`, the range crosses midnight. For example, `timeInRange(2200, 600, utcOffsetHours)` matches 22:00 through 06:00 in the visitor's local time. No two-check workaround is needed. - `trackingField(name)` reads URL key/value parameters that are defined in the traffic source config. - `dataBuffer(name)` reads from the data buffer, which captures all URL key/value pairs across incoming redirect links, action links, and POST submissions — including values not defined in the traffic source. Use it for data submitted *after* the initial click, such as action-link params and form fields. - `trackingField()` and `dataBuffer()` names must match `[A-Za-z0-9_ -]{1,64}`. - Always call helpers with parentheses and a string argument: use `trackingField("utm_source")`, never `trackingFields["utm_source"]`. ## Allowed operators `==` `!=` `<` `>` `<=` `>=` `&&` `||` `!` ## Allowed syntax - `if` / `else` - `switch` - Local variables (`x := ...`) - Local non-recursive functions or closures, with these constraints: - arguments must be typed `bool`, `int`, or `string` - must return exactly one `bool`, `int`, or `string` value - must return on every path - Local `[]string` literals for helper inputs - Comments with `//` or `/* */` ## Do not use - Imports or package declarations - Loops (`for`) - Goroutines, `defer`, or `select` - `append`, `make`, `new`, `panic`, `print`, `println`, `recover`, `delete`, or `copy` - Maps or indexing of any kind, including `trackingFields["x"]` - Pointers - Unsupported packages - Arbitrary method calls ## Good style - Keep routing deterministic. - Normalise an input once when you compare it repeatedly. - Return early when a rule clearly matches. - Use `switch` for several mutually exclusive cases. - Use `default` only as the failure/error fallback; give "no rule matched" its own named route. - Keep comments short and tied to the route they explain. ## Example: country routing if country == "US" { return "us" } if oneOf(country, "CA", "AU", "NZ") { return "tier_one" } return "default" ## Example: referrer block, then country tiers // Normalise the referrer once for case-insensitive matching. ref := strings.ToLower(referrer) // blocked: no referrer, or an unwanted / self-referral source. if ref == "" || strings.Contains(ref, "domain.com") { return "blocked" } // tier1: top-priority markets. if oneOf(country, "US", "CA", "GB", "AU", "NZ") { return "tier1" } // tier2: secondary markets. if oneOf(country, "DE", "FR", "NL", "SE", "NO", "DK", "CH", "IE") { return "tier2" } // unmatched: country resolved but matched no tier (a normal outcome). // A blank country (IP lookup failed) falls through to default instead. if country != "" { return "unmatched" } return "default" ## Example: case-insensitive tracking-field routing source := strings.ToLower(trackingField("utm_source")) switch { case source == "": return "missing_source" case source == "google_ads": return "google_ads" case strings.Contains(source, "newsletter"): return "newsletter" } return "default" ## Example: ISP substring blocklist normalizedISP := strings.ToLower(isp) blockedWords := []string{"amazon", "facebook", "google"} if containsAny(normalizedISP, blockedWords...) { return "blocked_isp" } return "default" ## Example: business-hours routing (visitor-local) // Uses the visitor's own offset, not a hardcoded one. workDay := oneOf(localDay(utcOffsetHours), "monday", "tuesday", "wednesday", "thursday", "friday") if workDay && timeInRange(900, 1700, utcOffsetHours) { return "business_hours" } return "default" ## Example: overnight local-time routing // end earlier than start crosses midnight: 22:00–06:00 local. if timeInRange(2200, 600, utcOffsetHours) { return "overnight" } return "default" ## Example: local closure isMobile := func() bool { return deviceType == "mobile" } isBusinessHour := func(offset int) bool { return timeInRange(900, 1700, offset) } if isMobile() && isBusinessHour(utcOffsetHours) { return "mobile_business_hours" } return "default" ## Example: submitted-form routing answer := strings.ToLower(dataBuffer("question_1")) consent := strings.ToLower(dataBuffer("consent")) if oneOf(answer, "a", "b") { return "answer_ab" } if oneOf(consent, "true", "yes", "1") { return "consented" } return "default"
Last modified on June 9, 2026
Creating FunnelsWebhook Payloads
On this page
  • Runtime model
  • Funnel wiring
  • API workflow
  • Language rules
    • String variables
    • Integer variables
    • Useful notes
    • Helpers
    • Allowed operators
    • Allowed syntax
    • Do not use
  • Examples
  • AI prompt
    • Instruction Prompt
    • Logic Script behavior and syntax documentation
Go
JSON
Go
Go
Go
Go
Go
Go
Go
Go
Go
Go
Markdown
Markdown