Eval Step
The Eval step executes custom JavaScript code within your flow. Use it for complex logic, custom calculations, advanced data manipulation, or anything that can’t be accomplished with other step types. Full JavaScript ES6+ support with access to common libraries.
Use Sparingly : Eval is powerful but adds complexity. Use built-in steps (Map, Rules, Functions) when possible. Reserve Eval for truly custom logic that can’t be accomplished otherwise.
How It Works
Eval executes JavaScript code and returns the result:
Simple Calculation
Data Transformation
Business Logic
Previous Step: Order data
↓
Eval: Calculate complex pricing
Code: Custom pricing algorithm
Returns: Calculated price
↓
Next Step: Use calculated price
When to Use Eval
Use Eval When Use Alternative When Complex calculations beyond Rules Simple math (use Rules) Custom algorithms not available elsewhere Standard operations (use Functions) Advanced array/object manipulation beyond Map Simple transforms (use Map) Need specific JavaScript libraries Built-in operators sufficient Complex conditional logic with edge cases Simple if/then (use Condition) Prototyping new logic before building proper step Logic is stable (build custom step)
Examples :
✅ Use Eval : Calculate compound interest with variable rates, fees, and payment schedules
❌ Use Rules instead : Simple percentage calculation
✅ Use Eval : Implement custom recommendation algorithm
❌ Use Agent instead : Interpret user needs and recommend
✅ Use Eval : Parse and validate complex data formats
❌ Use Map instead : Extract fields from JSON
Configuration
Code
JavaScript code to execute Must return a value using return statementAvailable variables :
input - Input data from previous step or trigger
context - Full flow context including all previous steps
trigger - Original trigger data
secrets - Access to secrets (read-only)
Example :// Access input
const orderTotal = input . total ;
const customerTier = input . tier ;
// Access previous steps
const agentDecision = context . agent_step . output . decision ;
// Perform calculations
let discount = 0 ;
if ( customerTier === "gold" && orderTotal > 1000 ) {
discount = orderTotal * 0.15 ;
} else if ( customerTier === "silver" && orderTotal > 500 ) {
discount = orderTotal * 0.10 ;
}
// Return result
return {
discount: discount ,
finalPrice: orderTotal - discount ,
discountApplied: discount > 0
};
Data passed to the Eval step Can reference previous steps: {
"order" : "${http_request.body}" ,
"customer" : "${customer_data}" ,
"settings" : "${config}"
}
Accessible in code as input object
Timeout
Maximum execution time in milliseconds Recommendations :
Simple logic: 1000ms (1 second)
Moderate complexity: 5000ms (5 seconds, default)
Heavy processing: 30000ms (30 seconds)
Long timeouts can slow flows. Optimize code for performance.
Available Libraries
Eval has access to common JavaScript libraries:
Utility library for arrays, objects, and more Import :const _ = require ( 'lodash' );
Common uses :// Group array by property
const grouped = _ . groupBy ( items , 'category' );
// Deep clone object
const copy = _ . cloneDeep ( original );
// Get nested value safely
const value = _ . get ( object , 'deep.nested.path' , 'default' );
// Debounce/throttle (for async operations)
const debounced = _ . debounce ( fn , 1000 );
Date and time manipulation Import :const moment = require ( 'moment' );
Common uses :// Parse and format dates
const date = moment ( '2025-10-16' ). format ( 'MMMM DD, YYYY' );
// Add/subtract time
const tomorrow = moment (). add ( 1 , 'days' );
// Compare dates
const isBefore = moment ( date1 ). isBefore ( date2 );
// Calculate duration
const duration = moment . duration ( end . diff ( start ));
const hours = duration . asHours ();
Advanced mathematical operations Import :const math = require ( 'mathjs' );
Common uses :// Complex calculations
const result = math . evaluate ( 'sqrt(3^2 + 4^2)' );
// Matrix operations
const matrix = math . matrix ([[ 1 , 2 ], [ 3 , 4 ]]);
// Statistical functions
const mean = math . mean ([ 1 , 2 , 3 , 4 , 5 ]);
const stdDev = math . std ([ 1 , 2 , 3 , 4 , 5 ]);
Cryptographic functions Import :const crypto = require ( 'crypto' );
Common uses :// Generate hash
const hash = crypto . createHash ( 'sha256' )
. update ( data )
. digest ( 'hex' );
// Generate random values
const randomBytes = crypto . randomBytes ( 16 ). toString ( 'hex' );
// HMAC signature
const hmac = crypto . createHmac ( 'sha256' , secret )
. update ( data )
. digest ( 'hex' );
All standard ES6+ features available Includes :
Array methods (map, filter, reduce, find, etc.)
Object methods (keys, values, entries, assign, etc.)
String methods (split, replace, match, etc.)
Math object (round, floor, ceil, random, etc.)
JSON parse/stringify
RegExp for pattern matching
Promises and async/await
Template literals
Destructuring
Spread operator
Common Patterns
Calculations beyond simple operators // Compound interest calculation
const principal = input . amount ;
const rate = input . annual_rate / 100 ;
const years = input . term_years ;
const compoundFreq = 12 ; // monthly
const amount = principal * Math . pow (
( 1 + rate / compoundFreq ),
compoundFreq * years
);
const totalInterest = amount - principal ;
return {
principal: principal ,
final_amount: Math . round ( amount * 100 ) / 100 ,
total_interest: Math . round ( totalInterest * 100 ) / 100 ,
monthly_payment: Math . round (( amount / ( years * 12 )) * 100 ) / 100
};
Advanced Array Processing
Complex array manipulation beyond Map const orders = input . orders ;
// Group by customer, calculate totals, filter high-value
const _ = require ( 'lodash' );
const customerTotals = _ . chain ( orders )
. groupBy ( 'customer_id' )
. map (( orders , customerId ) => ({
customer_id: customerId ,
order_count: orders . length ,
total_spent: _ . sumBy ( orders , 'amount' ),
avg_order: _ . meanBy ( orders , 'amount' ),
last_order_date: _ . maxBy ( orders , 'date' ). date
}))
. filter ( c => c . total_spent > 10000 )
. orderBy ([ 'total_spent' ], [ 'desc' ])
. value ();
return {
high_value_customers: customerTotals ,
count: customerTotals . length
};
Custom validation logic const data = input ;
const errors = [];
// Email validation
const emailRegex = / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ / ;
if ( ! emailRegex . test ( data . email )) {
errors . push ( "Invalid email format" );
}
// Phone validation (US format)
const phoneRegex = / ^ \d {3} - \d {3} - \d {4} $ / ;
if ( ! phoneRegex . test ( data . phone )) {
errors . push ( "Phone must be format: XXX-XXX-XXXX" );
}
// Age validation
const age = new Date (). getFullYear () - new Date ( data . birthdate ). getFullYear ();
if ( age < 18 ) {
errors . push ( "Must be 18 or older" );
}
// Custom business rule
if ( data . loan_amount > data . annual_income * 5 ) {
errors . push ( "Loan amount cannot exceed 5x annual income" );
}
return {
valid: errors . length === 0 ,
errors: errors ,
data: data
};
String Parsing and Formatting
Complex date logic const moment = require ( 'moment' );
const startDate = moment ( input . start_date );
const endDate = moment ( input . end_date );
// Calculate business days (exclude weekends)
let businessDays = 0 ;
let current = startDate . clone ();
while ( current . isSameOrBefore ( endDate )) {
if ( current . day () !== 0 && current . day () !== 6 ) {
businessDays ++ ;
}
current . add ( 1 , 'days' );
}
// Calculate age
const birthdate = moment ( input . birthdate );
const age = moment (). diff ( birthdate , 'years' );
// Format various ways
return {
business_days: businessDays ,
total_days: endDate . diff ( startDate , 'days' ),
weeks: endDate . diff ( startDate , 'weeks' ),
age: age ,
formatted_start: startDate . format ( 'MMMM DD, YYYY' ),
formatted_end: endDate . format ( 'MMMM DD, YYYY' )
};
Conditional Logic with Edge Cases
Complex business logic with many conditions const customer = input . customer ;
const order = input . order ;
let tier = "standard" ;
let discount = 0 ;
let shippingFee = 9.99 ;
let priority = "normal" ;
// Determine tier
if ( customer . lifetime_value > 50000 ) {
tier = "platinum" ;
} else if ( customer . lifetime_value > 10000 ) {
tier = "gold" ;
} else if ( customer . lifetime_value > 1000 ) {
tier = "silver" ;
}
// Calculate discount (complex rules)
if ( tier === "platinum" ) {
discount = 0.20 ;
shippingFee = 0 ;
priority = "high" ;
} else if ( tier === "gold" && order . total > 500 ) {
discount = 0.15 ;
shippingFee = 0 ;
} else if ( tier === "silver" && order . total > 200 ) {
discount = 0.10 ;
} else if ( order . total > 100 ) {
discount = 0.05 ;
}
// Special promotions
if ( customer . referred_by && order . is_first ) {
discount = Math . max ( discount , 0.10 ); // At least 10% for referrals
}
// Edge cases
if ( customer . account_on_hold ) {
return {
approved: false ,
reason: "Account on hold - contact support"
};
}
if ( order . shipping_country !== customer . billing_country ) {
priority = "review" ; // Flag for fraud review
}
// Calculate final pricing
const subtotal = order . total ;
const discountAmount = subtotal * discount ;
const total = subtotal - discountAmount + shippingFee ;
return {
approved: true ,
tier: tier ,
discount_percent: discount * 100 ,
discount_amount: Math . round ( discountAmount * 100 ) / 100 ,
shipping_fee: shippingFee ,
subtotal: subtotal ,
total: Math . round ( total * 100 ) / 100 ,
priority: priority
};
API Response Transformation
Proprietary scoring logic const lead = input . lead ;
let score = 0 ;
const factors = [];
// Company size scoring (0-30 points)
if ( lead . company_employees >= 1000 ) {
score += 30 ;
factors . push ({ factor: "company_size" , points: 30 , value: "1000+" });
} else if ( lead . company_employees >= 100 ) {
score += 20 ;
factors . push ({ factor: "company_size" , points: 20 , value: "100-999" });
} else {
score += 10 ;
factors . push ({ factor: "company_size" , points: 10 , value: "<100" });
}
// Budget scoring (0-30 points)
if ( lead . budget >= 100000 ) {
score += 30 ;
factors . push ({ factor: "budget" , points: 30 , value: "$100k+" });
} else if ( lead . budget >= 50000 ) {
score += 20 ;
factors . push ({ factor: "budget" , points: 20 , value: "$50k-100k" });
} else {
score += 10 ;
factors . push ({ factor: "budget" , points: 10 , value: "<$50k" });
}
// Industry fit (0-20 points)
const targetIndustries = [ "technology" , "finance" , "healthcare" ];
if ( targetIndustries . includes ( lead . industry . toLowerCase ())) {
score += 20 ;
factors . push ({ factor: "industry" , points: 20 , value: "target industry" });
}
// Engagement scoring (0-20 points)
const engagementScore = Math . min ( 20 ,
( lead . website_visits * 2 ) +
( lead . email_opens * 1 ) +
( lead . demo_requests * 5 )
);
score += engagementScore ;
factors . push ({ factor: "engagement" , points: engagementScore , value: "activity" });
// Decision maker bonus (10 points)
const decisionMakers = [ "ceo" , "cto" , "cfo" , "vp" , "director" ];
if ( decisionMakers . some ( role => lead . title . toLowerCase (). includes ( role ))) {
score += 10 ;
factors . push ({ factor: "decision_maker" , points: 10 , value: lead . title });
}
// Determine tier
let tier ;
if ( score >= 80 ) tier = "hot" ;
else if ( score >= 60 ) tier = "warm" ;
else if ( score >= 40 ) tier = "cold" ;
else tier = "unqualified" ;
return {
score: score ,
tier: tier ,
factors: factors ,
lead_id: lead . id ,
recommendation: tier === "hot" ? "contact immediately" :
tier === "warm" ? "nurture sequence" :
tier === "cold" ? "standard follow-up" :
"disqualify"
};
Real-World Examples
Example 1: Mortgage Qualification Calculator
const applicant = input . applicant ;
const property = input . property ;
// Constants
const MAX_DTI = 0.43 ; // Max debt-to-income ratio
const MIN_CREDIT_SCORE = 620 ;
const MAX_LTV = 0.80 ; // Max loan-to-value
// Calculate debt-to-income ratio
const monthlyIncome = applicant . annual_income / 12 ;
const monthlyDebts = applicant . monthly_debt_payments ;
const estimatedMortgage = ( property . price * 0.8 ) * 0.005 ; // Rough estimate
const totalMonthlyDebt = monthlyDebts + estimatedMortgage ;
const dti = totalMonthlyDebt / monthlyIncome ;
// Calculate loan-to-value
const downPayment = property . down_payment ;
const loanAmount = property . price - downPayment ;
const ltv = loanAmount / property . price ;
// Check qualifications
const qualified =
applicant . credit_score >= MIN_CREDIT_SCORE &&
dti <= MAX_DTI &&
ltv <= MAX_LTV &&
applicant . employment_years >= 2 ;
// Calculate interest rate (simplified)
let interestRate ;
if ( applicant . credit_score >= 760 && ltv <= 0.7 ) {
interestRate = 0.065 ;
} else if ( applicant . credit_score >= 720 ) {
interestRate = 0.070 ;
} else if ( applicant . credit_score >= 680 ) {
interestRate = 0.075 ;
} else {
interestRate = 0.080 ;
}
// Calculate monthly payment
const monthlyRate = interestRate / 12 ;
const numPayments = 30 * 12 ; // 30-year mortgage
const monthlyPayment = loanAmount *
( monthlyRate * Math . pow ( 1 + monthlyRate , numPayments )) /
( Math . pow ( 1 + monthlyRate , numPayments ) - 1 );
// Reasons for disqualification
const reasons = [];
if ( applicant . credit_score < MIN_CREDIT_SCORE ) {
reasons . push ( `Credit score too low ( ${ applicant . credit_score } < ${ MIN_CREDIT_SCORE } )` );
}
if ( dti > MAX_DTI ) {
reasons . push ( `Debt-to-income ratio too high ( ${ ( dti * 100 ). toFixed ( 1 ) } % > ${ MAX_DTI * 100 } %)` );
}
if ( ltv > MAX_LTV ) {
reasons . push ( `Loan-to-value too high ( ${ ( ltv * 100 ). toFixed ( 1 ) } % > ${ MAX_LTV * 100 } %)` );
}
if ( applicant . employment_years < 2 ) {
reasons . push ( `Insufficient employment history ( ${ applicant . employment_years } years < 2 years)` );
}
return {
qualified: qualified ,
reasons: reasons ,
details: {
loan_amount: Math . round ( loanAmount ),
interest_rate: interestRate ,
monthly_payment: Math . round ( monthlyPayment ),
dti_ratio: Math . round ( dti * 1000 ) / 10 ,
ltv_ratio: Math . round ( ltv * 1000 ) / 10 ,
total_interest: Math . round (( monthlyPayment * numPayments ) - loanAmount )
}
};
Example 2: Recommendation Engine
const _ = require ( 'lodash' );
const user = input . user ;
const products = input . products ;
const userHistory = input . purchase_history ;
// Calculate user preferences from history
const categoryPreferences = _ . chain ( userHistory )
. groupBy ( 'category' )
. mapValues ( items => ({
count: items . length ,
avg_rating: _ . meanBy ( items , 'rating' ),
total_spent: _ . sumBy ( items , 'price' )
}))
. value ();
// Score each product
const scoredProducts = products . map ( product => {
let score = 0 ;
// Category preference (0-40 points)
const categoryPref = categoryPreferences [ product . category ];
if ( categoryPref ) {
score += Math . min ( 40 , categoryPref . count * 5 );
}
// Price fit (0-20 points)
const avgSpent = _ . meanBy ( userHistory , 'price' );
const priceDiff = Math . abs ( product . price - avgSpent ) / avgSpent ;
score += Math . max ( 0 , 20 - ( priceDiff * 20 ));
// Rating (0-20 points)
score += ( product . rating / 5 ) * 20 ;
// Popularity (0-10 points)
score += Math . min ( 10 , ( product . purchase_count / 1000 ) * 10 );
// Recency bonus (0-10 points)
const daysOld = ( Date . now () - new Date ( product . created_at )) / ( 1000 * 60 * 60 * 24 );
if ( daysOld < 30 ) {
score += 10 ;
} else if ( daysOld < 90 ) {
score += 5 ;
}
return {
... product ,
recommendation_score: Math . round ( score ),
match_reasons: []
};
});
// Sort and take top recommendations
const recommendations = _ . chain ( scoredProducts )
. orderBy ([ 'recommendation_score' , 'rating' ], [ 'desc' , 'desc' ])
. take ( 10 )
. value ();
return {
recommendations: recommendations ,
user_preferences: categoryPreferences ,
recommendation_count: recommendations . length
};
Example 3: Fraud Detection Scoring
const transaction = input . transaction ;
const userProfile = input . user_profile ;
const moment = require ( 'moment' );
let riskScore = 0 ;
const riskFactors = [];
// Unusual amount check (0-30 points)
const avgTransaction = userProfile . avg_transaction_amount ;
const amountDeviation = Math . abs ( transaction . amount - avgTransaction ) / avgTransaction ;
if ( amountDeviation > 5 ) {
riskScore += 30 ;
riskFactors . push ( "Amount 5x higher than average" );
} else if ( amountDeviation > 2 ) {
riskScore += 15 ;
riskFactors . push ( "Amount 2x higher than average" );
}
// Location check (0-25 points)
if ( transaction . location . country !== userProfile . country ) {
riskScore += 25 ;
riskFactors . push ( "Transaction from different country" );
} else if ( transaction . location . city !== userProfile . city ) {
riskScore += 10 ;
riskFactors . push ( "Transaction from different city" );
}
// Time pattern check (0-15 points)
const hour = moment ( transaction . timestamp ). hour ();
if ( hour >= 0 && hour <= 5 ) {
riskScore += 15 ;
riskFactors . push ( "Unusual time (midnight-5am)" );
}
// Velocity check (0-20 points)
const recentTransactions = userProfile . transactions_last_24h || 0 ;
if ( recentTransactions > 10 ) {
riskScore += 20 ;
riskFactors . push ( "High transaction velocity (>10 in 24h)" );
} else if ( recentTransactions > 5 ) {
riskScore += 10 ;
riskFactors . push ( "Elevated transaction velocity" );
}
// Device fingerprint (0-10 points)
if ( transaction . device_id !== userProfile . known_device_ids . some ( id => id === transaction . device_id )) {
riskScore += 10 ;
riskFactors . push ( "Unknown device" );
}
// Determine risk level
let riskLevel ;
if ( riskScore >= 70 ) {
riskLevel = "high" ;
} else if ( riskScore >= 40 ) {
riskLevel = "medium" ;
} else {
riskLevel = "low" ;
}
// Recommended action
let action ;
if ( riskLevel === "high" ) {
action = "block_and_review" ;
} else if ( riskLevel === "medium" ) {
action = "require_verification" ;
} else {
action = "approve" ;
}
return {
risk_score: riskScore ,
risk_level: riskLevel ,
risk_factors: riskFactors ,
recommended_action: action ,
transaction_id: transaction . id ,
requires_manual_review: riskScore >= 60
};
Best Practices
Use Judiciously Only use Eval when built-in steps (Map, Rules, Functions, Condition) can’t accomplish the task. Eval adds complexity.
Always Return a Value Code must include a return statement. The returned value becomes the step output.
Handle Errors Use try-catch blocks for operations that might fail. Return error information for debugging.
Keep It Fast Optimize for performance. Long-running code slows flows. Set appropriate timeouts.
Test Thoroughly Test with real data and edge cases. Use Test Mode to verify before production.
Document Complex Logic Add comments explaining what the code does and why. Future you will thank present you.
Avoid External API Calls Use HTTP Request step for API calls, not fetch/axios in Eval. Eval is for computation, not I/O.
Validate Inputs Check that input has expected structure before processing. Return meaningful errors if not.
Troubleshooting
Causes :
Syntax error in JavaScript
Runtime error (undefined variable, null reference)
Exceeded timeout
Missing return statement
Solutions :
Check execution logs for error message
Test code separately in JavaScript console
Add try-catch blocks
Verify all variables exist before using
Add return statement
Causes :
Library not included in Eval environment
Wrong import syntax
Solutions :
Check available libraries list
Use correct require syntax: const _ = require('lodash')
For unavailable libraries, implement logic directly or use different step
Causes :
Code takes too long to execute
Infinite loop
Processing large datasets
Solutions :
Optimize algorithm
Increase timeout setting
Process data in smaller chunks
Use Map step for large array processing instead
Causes :
Logic error in code
Wrong data types
Missing edge case handling
Solutions :
Add console.log statements (appear in logs)
Test with various inputs
Verify data types match expectations
Handle null/undefined cases
Security Considerations
No External Network Access
Eval cannot make external HTTP requests. Use HTTP Request step for API calls. Blocked :
fetch()
XMLHttpRequest
axios
node-fetch
Can read secrets but not write them // Read secret
const apiKey = secrets . api_key ;
// Cannot modify
// secrets.api_key = "new_value"; // ERROR
Code runs in isolated environment
Cannot access file system
Cannot execute system commands
Cannot import arbitrary modules
Timeout enforced automatically
Next Steps