Skip to Content
No-Code EditorCustom JavaScript

Custom JavaScript

The Custom JS system lets you inject JavaScript into your funnels for advanced behavior that goes beyond the visual editor. Your code interacts with the funnel through the window.appfunnel API.

Open the Code tab (code icon) in the left sidebar to access the editor.

Three Scopes

Global JS

Code that runs on every page of the funnel. Subscriptions and state persist across page navigation. Use this for analytics, global event handlers, or initialization code.

// Track every page view appfunnel.on('page.view', (e) => { analytics.track('page_view', { pageId: e.pageId }); });

Page JS

Code that runs only on the current page. All event subscriptions are automatically cleaned up when the user navigates away — no manual teardown needed.

// Validate a field on this page only appfunnel.on('variable.update', (e) => { if (e.variableName === 'user.email') { const isValid = e.newValue.includes('@'); appfunnel.setVariable('data.emailValid', isValid); } });

Preload

Preload external resources (stylesheets, scripts, images, fonts, fetch requests) so they’re ready before the user needs them. Add a URL, select its type, and the browser fetches it in the background.

TypeUse case
stylesheetExternal CSS files
scriptExternal JavaScript
imageHero images, backgrounds
fontCustom web fonts
fetchAPI data to prefetch

The appfunnel API

When your funnel runs, window.appfunnel is available with the following interface.

Methods

setVariable(variableId, value, operation?)

Set or modify a variable.

appfunnel.setVariable('user.name', 'Jane') // set appfunnel.setVariable('user.count', null, 'increment') // increment appfunnel.setVariable('user.count', null, 'decrement') // decrement appfunnel.setVariable('user.active', null, 'toggle') // toggle boolean
ParamTypeDescription
variableIdstringe.g. user.myVariable
valueanyThe value to set (ignored for increment/decrement/toggle)
operationstring?'set' (default), 'increment', 'decrement', 'toggle'

toggleArrayItem(variableId, item)

Add or remove an item from a stringArray variable.

appfunnel.toggleArrayItem('user.selections', 'option1')

goToNextPage()

Navigate forward by evaluating the current page’s routing rules.

goBack()

Navigate to the previous page in the session history.

callEvent(eventName, eventData?)

Emit a custom event. Integrations (Meta Pixel, GTM, webhooks) receive it, and you can subscribe to it via appfunnel.on().

appfunnel.callEvent('quiz_completed', { goal: appfunnel.getVariable('answers.goal'), });

selectProduct(productId)

Select a product by its UUID.

appfunnel.selectProduct('product-uuid-here')

openUrl(url)

Open a URL in a new tab.

appfunnel.openUrl('https://example.com')

Getters

getVariable(variableId)

Returns the current value of a variable.

const name = appfunnel.getVariable('user.name')

getVariables()

Returns an object with all variable IDs as keys and their current values.

const allVars = appfunnel.getVariables()

getCurrentPageId()

Returns the current page ID, or null.


Event Subscriptions

Subscribe to events with appfunnel.on(eventType, callback). It returns an unsubscribe function.

const unsub = appfunnel.on('page.view', (e) => { console.log('Page:', e.pageName); }); // Later: unsub()

You can also unsubscribe via appfunnel.off(eventType, callback).

Built-in Events

EventFires whenEvent data
page.viewPage finishes loadingpageId, pageName
page.exitBefore leaving a pagepageId, pageName
variable.updateAny variable changesvariableId, variableName, oldValue, newValue
navigation.nextgoToNextPage() is calledfromPageId, fromPageName
navigation.prevgoBack() is calledfromPageId, fromPageName

You can also subscribe to custom events emitted via callEvent():

appfunnel.on('my_custom_event', (data) => { console.log(data); });

Debugging

Enable debug logging to see all internal operations in the browser console:

appfunnel.debug = true

This logs script execution, event emission, subscription changes, variable updates, navigation, and errors.


Examples

Track time on page

// Global JS let start = null; appfunnel.on('page.view', (e) => { start = Date.now(); }); appfunnel.on('page.exit', (e) => { appfunnel.callEvent('time_on_page', { pageId: e.pageId, duration: Date.now() - start, }); });

Auto-navigate when a score reaches a threshold

// Page JS appfunnel.on('variable.update', (e) => { if (e.variableName === 'user.score' && e.newValue >= 100) { appfunnel.goToNextPage(); } });

Log all variable changes (debug helper)

// Global JS appfunnel.on('variable.update', (e) => { console.log(`${e.variableName}: ${e.oldValue} → ${e.newValue}`); });

Best Practices

  • Use Page JS for page-specific logic — subscriptions are auto-cleaned, preventing memory leaks.
  • Use Global JS sparingly — only for truly cross-page behavior like analytics.
  • Wrap code in try-catch — an unhandled error in your JS won’t break the funnel, but it’s good practice.
  • Don’t block navigation — avoid long-running synchronous operations.
  • Test with debug modeappfunnel.debug = true surfaces issues quickly.
Last updated on