The RAW element is your escape hatch for unlimited customization. When FunnelFox’s built-in elements don’t quite fit your needs, RAW lets you write custom code to create exactly what you want.
RAW element in Visual Editor

Common Use Cases

Custom Calculations

BMI calculators, loan estimators, or any complex math based on user inputs

Third-Party Widgets

Embed calendars, maps, chat widgets, or social media feeds

Advanced Styling

Create unique visual effects or animations not available in standard elements

External Integrations

Connect to APIs, track custom events, or sync with external services

Properties

Element Tab

RAW element HTML editor

HTML Content

The main code editor where you write your HTML, CSS, and JavaScript. Supports full HTML5 syntax with embedded styles and scripts.
<div style="padding: 20px;">
  <h3>Custom Content</h3>
  <button onclick="alert('Hello!')">Click Me</button>
</div>

<script>
  // Your JavaScript here
  console.log('RAW element loaded');
</script>

<style>
  /* Your CSS here */
  h3 { color: blue; }
</style>

Preserve Formatting

  • No (default): Element renders with its own styling
  • Yes: Inherits theme styles (fonts, colors) from funnel settings
Important: When visibility is set to “No”, the RAW element is not rendered in the DOM, so scripts won’t execute. Use this to conditionally run code based on user segments.
For common properties (ID, Visibility, Styles), see Elements Overview.

Working with the Fox API

Access FunnelFox functionality through the global fox object:
<script>
// Get user input values
const name = fox.inputs.get('name');
const age = parseInt(fox.inputs.get('age'));

// Calculate and store result
const category = age < 18 ? 'junior' : 'adult';
fox.inputs.set('user-category', category);

// Navigate based on logic
if (category === 'junior') {
  fox.navigation.goToId('youth-offer');
} else {
  fox.navigation.goToId('standard-offer');
}
</script>
See Custom Code & Fox API for complete API reference.

Examples

BMI Calculator

Calculate BMI from user inputs and display results:
<div id="bmi-result" style="padding: 20px; text-align: center;">
  <h3>Your BMI Result</h3>
  <p id="bmi-value" style="font-size: 24px; font-weight: bold;"></p>
  <p id="bmi-category"></p>
</div>

<script>
// Get height and weight from previous inputs
const weight = parseFloat(fox.inputs.get('weight'));
const height = parseFloat(fox.inputs.get('height'));

// Calculate BMI
const bmi = weight / ((height/100) * (height/100));

// Determine category
let category;
if (bmi < 18.5) category = "Underweight";
else if (bmi < 25) category = "Normal weight";
else if (bmi < 30) category = "Overweight";
else category = "Obese";

// Display results
document.getElementById('bmi-value').textContent = bmi.toFixed(1);
document.getElementById('bmi-category').textContent = category;

// Store for use in next screens
fox.inputs.set('bmi', bmi.toFixed(1));
fox.inputs.set('bmi-category', category);
</script>

Embedded Video

Add a responsive video player:
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe 
    src="https://www.youtube.com/embed/VIDEO_ID"
    style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
    frameborder="0"
    allowfullscreen>
  </iframe>
</div>

Custom Timer

Create urgency with a countdown:
<div id="timer" style="text-align: center; padding: 20px;">
  <h2>Offer expires in:</h2>
  <div id="countdown" style="font-size: 32px; color: red;"></div>
</div>

<script>
// Set timer for 10 minutes
let timeLeft = 600; // seconds

function updateTimer() {
  const minutes = Math.floor(timeLeft / 60);
  const seconds = timeLeft % 60;
  
  document.getElementById('countdown').textContent = 
    `${minutes}:${seconds.toString().padStart(2, '0')}`;
  
  if (timeLeft > 0) {
    timeLeft--;
    setTimeout(updateTimer, 1000);
  } else {
    document.getElementById('countdown').textContent = "EXPIRED";
    // Optionally navigate to expired offer page
    fox.navigation.goToId('offer-expired');
  }
}

updateTimer();
</script>

Dynamic Content Based on Time

Show different content based on time of day:
<div id="greeting" style="padding: 20px;"></div>

<script>
const hour = new Date().getHours();
const greetingEl = document.getElementById('greeting');

if (hour < 12) {
  greetingEl.innerHTML = '<h2>Good Morning! ☀️</h2><p>Start your day with 20% off</p>';
} else if (hour < 18) {
  greetingEl.innerHTML = '<h2>Good Afternoon! 🌤</h2><p>Midday special: Buy 2 get 1 free</p>';
} else {
  greetingEl.innerHTML = '<h2>Good Evening! 🌙</h2><p>Night owl discount: 30% off</p>';
}
</script>

External API Integration

Fetch data from your backend:
<div id="user-data" style="padding: 20px;">
  <p>Loading your account...</p>
</div>

<script>
async function loadUserData() {
  const email = fox.inputs.get('email');
  
  try {
    const response = await fetch('https://your-api.com/user', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email })
    });
    
    const data = await response.json();
    
    document.getElementById('user-data').innerHTML = `
      <h3>Welcome back, ${data.name}!</h3>
      <p>Your account balance: $${data.balance}</p>
      <p>Member since: ${data.joinDate}</p>
    `;
    
    // Store user data for later use
    fox.inputs.set('user-name', data.name);
    fox.inputs.set('user-balance', data.balance);
    
  } catch (error) {
    document.getElementById('user-data').innerHTML = 
      '<p>Unable to load account data. Please try again.</p>';
  }
}

loadUserData();
</script>

Execution Context

When Code Runs

  • Scripts execute immediately when the screen loads
  • Code runs every time a user navigates to the screen
  • No need for DOMContentLoaded or similar wrappers
  • Fox API is available immediately as window.fox

Available APIs

Full access to browser APIs:
  • DOM: All document methods and properties
  • Window: Global window object and methods
  • Fetch: For API calls
  • Local Storage: For persistent data
  • All JavaScript: ES6+, async/await, promises

Scope and State

  • Each RAW element runs in the global scope
  • Variables persist within the same screen
  • State doesn’t carry between screens (use fox.inputs.set())
  • Multiple RAW elements on same screen share scope

Best Practices

Keep It Simple

Use RAW only when built-in elements won’t work. Native elements are faster and more reliable.

Test Thoroughly

Always test in preview mode across different devices and browsers before publishing.

Handle Errors

Wrap risky code in try-catch blocks. One JavaScript error can break the entire funnel.

Optimize Performance

Minimize external requests, avoid heavy computations, and load resources asynchronously.

Security Considerations

  • No server-side code: Everything runs client-side
  • Validate inputs: Never trust user data
  • Secure API calls: Use HTTPS and proper authentication
  • No sensitive data: Don’t embed API keys or secrets
  • XSS prevention: Sanitize any user-generated content

Performance Tips

// ❌ Bad: Blocking external script
<script src="https://heavy-library.com/lib.js"></script>

// ✅ Good: Async loading
<script async src="https://heavy-library.com/lib.js"></script>

// ❌ Bad: Repeated DOM queries
for (let i = 0; i < 100; i++) {
  document.getElementById('result').innerHTML += i;
}

// ✅ Good: Single DOM update
let content = '';
for (let i = 0; i < 100; i++) {
  content += i;
}
document.getElementById('result').innerHTML = content;

Limitations

  • No server-side execution: All code runs in the browser
  • No file system access: Can’t read/write local files
  • Same-origin policy: CORS restrictions apply to API calls
  • No Node.js: Browser JavaScript only
  • Memory limits: Heavy operations may slow/crash browser

Troubleshooting

Next Steps