Skip to main content

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.

Action functions let your backend script perform side-effects — set session data, cookies, redirect the visitor, inject template variables, or send custom responses.

Session

Read and write values in the visitor’s server-side session.
session.set('my_key', 'my_value');
session.set('visit_count', 5);

var count = session.get('visit_count');  // 5
var missing = session.get('nonexistent'); // null
Session values set here are immediately available to funnel script rules that run after the backend script.
Session keys and values should be simple types (strings, numbers, booleans). Complex objects are serialized as JSON internally.
For security, some session keys are reserved and cannot be read or written via session.get() / session.set(). Use your own key names (e.g. my_key, visit_count) for custom data.

session.setCustomer(fields)

Establish an authenticated customer session from a custom login flow — magic link, external OTP, SSO callback, or any mechanism outside the built-in purchase pipeline. Writes the runtime’s canonical customer fields (is_customer, email, customer_id, customer) so downstream pages, template variables, and access rules see the visitor as logged in.
// Verify a one-time code your app generated...
var code = getVariable('submitted_code');
var email = getVariable('submitted_email');
var ok = verifyMyOtp(email, code);

if (ok) {
  session.setCustomer({ email: email, name: 'Jane Doe' });
  redirect('/dashboard');
}
FieldTypeRequiredDescription
emailstringyesThe customer’s email (must contain @).
namestringnoFull display name. If omitted, derived from first_name + last_name.
first_namestringnoFirst name. Merged into session.customer.first_name.
last_namestringnoLast name. Merged into session.customer.last_name.
idanynoInternal customer id. When set, also writes session.customer_id.
Returns true on success, false on invalid input or quota exhaustion.
setCustomer merges over any existing session.customer object, so tracking fields such as total, currency, or order_ids set by earlier checkout flows are preserved.

session.getToken(ttlSeconds?) / session.setFromToken(token)

Mint and consume short-lived encrypted tokens that carry the current customer identity across brand-owned domains. Used for cross-domain session continuity — see Cross-domain session handoff for the full protocol and a worked example.
// On the source domain: mint a 60-second token
var token = await session.getToken();        // null if no customer
var url = 'https://app.example.com/welcome?ef_session=' + encodeURIComponent(token);
redirect(url);

// On the destination domain: most of the time you don't need this — the
// EF runtime auto-consumes `?ef_session=<token>` on every request. Call
// setFromToken() manually only if you need to consume a token from a
// header, body, or non-query-string location.
var ok = await session.setFromToken(headerToken);
session.getToken(ttlSeconds?) returns the token string (or null if the session has no customer). ttlSeconds defaults to 60 and is capped at 600. session.setFromToken(token) returns true on success, false on any failure (tamper, expiry, replay, wrong brand). It never throws.

Cookies

Set or delete cookies on the visitor’s browser.
cookie.set('promo_seen', 'true', { maxAge: 3600, path: '/' });
cookie.delete('old_cookie');
OptionTypeDescription
maxAgenumberCookie lifetime in seconds
pathstringCookie path (default: '/')
Clears the cookie by name.
Some cookie names are reserved and cannot be set or deleted. Use your own cookie names for custom data.

Redirect

Redirect the visitor to a different URL. This stops page rendering — the visitor is immediately sent to the new URL.
redirect('/login');           // 302 temporary redirect
redirect('/new-page', 301);   // 301 permanent redirect
redirect('https://example.com/page'); // external redirect
When redirect() is called, the entire funnel flow and page rendering are skipped. The visitor receives only the redirect response.
Only relative paths (/path) and http:// / https:// URLs are allowed. Other schemes (e.g., javascript:, data:) are blocked for security.

Template Variables

Inject values into the template engine. These become available as {{ var.key }} in page HTML.
setVariable('discount', '50%');
setVariable('show_banner', true);
setVariable('user_tier', 'premium');
setVariable('user', { name: 'Sam', email: 'sam@example.com' });
setVariable('categories', [
  { slug: 'marketing', name: 'Marketing', courses: [...] },
  { slug: 'design', name: 'Design', courses: [...] },
]);
In your page HTML:
<h1>Get {{ var.discount }} off!</h1>

@if(var.show_banner)
  <div class="banner">Premium member</div>
@endif

<!-- Objects work too -->
<p>Welcome, {{ var.user.name }}</p>

<!-- Debug: dump the full object as JSON -->
<pre>{{ dump(var.user) }}</pre>
setVariable('name', value) stores the value under the var namespace. Always access it as var.name in templates — e.g. {{ var.name }}, {{ dump(var.name) }}, @if(var.name). Using {{ name }} or {{ dump(name) }} without the var. prefix will not find the variable.

Scoping inside @foreach

When you iterate over a variable with @foreach, the loop variable is its own scope — it does not use the var. prefix:
<!-- var.categories needs the var. prefix (it came from setVariable) -->
@foreach(cat in var.categories)
  <!-- cat is a loop variable — access its properties directly, no var. prefix -->
  <h2>{{ cat.name }}</h2>
  <p>{{ cat.slug }}</p>

  <!-- nested arrays on the loop variable also work directly -->
  @foreach(course in cat.courses)
    <div>{{ course.title }}</div>
  @endforeach
@endforeach
In short: var. is only for the top-level reference to variables set by setVariable. Once a value is assigned to a loop variable (cat, course, etc.), you access its properties directly. Variables set with setVariable take precedence over brand variables with the same key.

Response Headers

Set custom HTTP response headers.
setHeader('X-Custom-Header', 'my-value');
setHeader('Cache-Control', 'no-store');
For security, certain response headers cannot be set (e.g. those that control cookies, CORS, or connection). Header values are sanitized.

Custom Response

Send a custom response instead of the rendered page. These stop page rendering.

response.status(code)

Set the HTTP status code (used with response.send() or response.json(), or with the normal page render).
response.status(403);
response.send('<h1>Access Denied</h1>');

response.json(data)

Send a JSON response. Skips page rendering.
response.json({ error: false, user: customer.email });

response.send(html)

Send raw HTML. Skips page rendering.
response.send('<html><body><h1>Maintenance</h1></body></html>');

Logging and errors

console.log, console.info, console.warn, and console.error are captured and stored in execution logs. Use them for debugging.
console.log('Visitor IP:', request.ip);
console.log('Customer:', customer);
Logs and errors are visible in the Debug Window (Page Events tab) for the page request. If your script throws an error or times out, the visitor still receives the normal page (no error message is shown); the error is logged there and may be reported to admins.