Execute custom JavaScript code to transform data, parse JSON, extract fields, and implement business logic between workflow nodes. Sandboxed execution ensures security.
The JavaScript node is one of the most versatile nodes in TopFlow. It enables you to write custom JavaScript code that runs during workflow execution, allowing you to transform data, implement business logic, parse complex responses, and manipulate data structures between nodes.
codestringJavaScript code to execute. Code must return a value using the return keyword. Inputs from upstream nodes are available as variables: input1, input2, input3, etc.
console.log() statements for debugging (output appears in execution logs).// Parse JSON and extract specific field
const data = JSON.parse(input1)
return data.user.email
// Calculate severity score
const score = (input1.critical * 10) + (input1.high * 5)
return score >= 50 ? "HIGH" : "MEDIUM"
// Transform array
const threats = JSON.parse(input1)
return threats
.filter(t => t.severity === "CRITICAL")
.map(t => t.title)
.join(", ")When nodes connect to the JavaScript node, their outputs become available as numbered input variables:
input1Output from the first upstream node (leftmost connection)input2Output from the second upstream nodeinput3Output from the third upstream node...And so on for additional connectionsinput1.Your JavaScript code must return a value using the return keyword. This value becomes the output that downstream nodes can access.
// Return string
return "HIGH"
// Return number
return 42
// Return object
return {
severity: "CRITICAL",
count: 5,
timestamp: new Date().toISOString()
}
// Return array
return ["threat1", "threat2", "threat3"]
// Return boolean
return score >= 50TypeScript interface defining the JavaScript node's configuration and execution state:
export type JavaScriptNodeData = {
// Configuration
code: string // JavaScript code to execute
// Execution state (managed by system)
status?: "idle" | "running" | "completed" | "error"
output?: any // Return value from executed code
error?: string
}HTTP Request node returns complex JSON. You need to extract just the email addresses.
{
"status": 200,
"data": {
"users": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
]
}
}// Parse the HTTP response and extract emails
const response = input1
const users = response.data.users
// Map to just email addresses
const emails = users.map(user => user.email)
// Return as comma-separated string
return emails.join(", ")"alice@example.com, bob@example.com"Text Model node analyzes security events and returns threat counts. Calculate a severity score to determine alerting priority.
{
"critical": 2,
"high": 5,
"medium": 10,
"low": 20
}// Parse threat counts
const threats = JSON.parse(input1)
// Calculate weighted severity score
// Critical: 10 points, High: 5 points, Medium: 2 points, Low: 1 point
const score =
(threats.critical * 10) +
(threats.high * 5) +
(threats.medium * 2) +
(threats.low * 1)
// Determine severity level
let severity
if (score >= 50) severity = "CRITICAL"
else if (score >= 25) severity = "HIGH"
else if (score >= 10) severity = "MEDIUM"
else severity = "LOW"
// Return structured result
return {
score: score,
severity: severity,
requires_immediate_action: score >= 50,
threat_summary: `${threats.critical} critical, ${threats.high} high, ${threats.medium} medium, ${threats.low} low`
}{
"score": 65,
"severity": "CRITICAL",
"requires_immediate_action": true,
"threat_summary": "2 critical, 5 high, 10 medium, 20 low"
}Two parallel HTTP Request nodes fetch user data and threat data. Merge them into a single report.
// input1 - User data from API
{
"user_id": "123",
"username": "john.doe",
"department": "Engineering"
}
// input2 - Threat data from security system
{
"threats_detected": 3,
"last_incident": "2024-01-15",
"risk_level": "HIGH"
}// Parse both inputs
const userData = JSON.parse(input1)
const threatData = JSON.parse(input2)
// Merge into comprehensive report
return {
report_timestamp: new Date().toISOString(),
user: {
id: userData.user_id,
name: userData.username,
department: userData.department
},
security: {
threat_count: threatData.threats_detected,
last_incident: threatData.last_incident,
risk_level: threatData.risk_level,
requires_review: threatData.threats_detected > 0
},
summary: `User ${userData.username} has ${threatData.threats_detected} threats detected. Risk level: ${threatData.risk_level}`
}{
"report_timestamp": "2024-01-15T10:30:00.000Z",
"user": {
"id": "123",
"name": "john.doe",
"department": "Engineering"
},
"security": {
"threat_count": 3,
"last_incident": "2024-01-15",
"risk_level": "HIGH",
"requires_review": true
},
"summary": "User john.doe has 3 threats detected. Risk level: HIGH"
}HTTP Request node returns list of CVEs. Filter to only critical vulnerabilities affecting your systems.
{
"threats": [
{
"id": "CVE-2024-1234",
"severity": "CRITICAL",
"cvss": 9.8,
"affected_systems": ["web-server-01", "api-gateway"]
},
{
"id": "CVE-2024-5678",
"severity": "MEDIUM",
"cvss": 6.5,
"affected_systems": ["marketing-site"]
},
{
"id": "CVE-2024-9012",
"severity": "CRITICAL",
"cvss": 9.1,
"affected_systems": ["gitlab-enterprise"]
}
]
}// Parse threat data
const data = JSON.parse(input1)
// Filter to critical threats only
const criticalThreats = data.threats.filter(threat =>
threat.severity === "CRITICAL"
)
// Transform to simplified format
const summary = criticalThreats.map(threat => ({
cve: threat.id,
score: threat.cvss,
systems: threat.affected_systems.join(", "),
priority: threat.cvss >= 9.5 ? "URGENT" : "HIGH"
}))
// Return count and details
return {
critical_count: criticalThreats.length,
threats: summary,
alert_message: `⚠️ ${criticalThreats.length} critical vulnerabilities detected requiring immediate attention`
}{
"critical_count": 2,
"threats": [
{
"cve": "CVE-2024-1234",
"score": 9.8,
"systems": "web-server-01, api-gateway",
"priority": "URGENT"
},
{
"cve": "CVE-2024-9012",
"score": 9.1,
"systems": "gitlab-enterprise",
"priority": "HIGH"
}
],
"alert_message": "⚠️ 2 critical vulnerabilities detected requiring immediate attention"
}Text Model generates security analysis. Format it for Slack notification with proper markdown and emoji.
{
"event_type": "Suspicious Login",
"severity": "HIGH",
"user": "john.doe",
"ip_address": "203.0.113.42",
"country": "Unknown",
"timestamp": "2024-01-15T10:30:00Z",
"recommendation": "Force password reset and review account activity"
}// Parse security event
const event = JSON.parse(input1)
// Map severity to emoji
const severityEmoji = {
"CRITICAL": "🔴",
"HIGH": "🟠",
"MEDIUM": "🟡",
"LOW": "🟢"
}
// Format timestamp
const date = new Date(event.timestamp)
const formattedTime = date.toLocaleString("en-US", {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZoneName: "short"
})
// Build Slack-formatted message
return {
text: `${severityEmoji[event.severity]} Security Alert: ${event.event_type}`,
blocks: [
{
type: "header",
text: {
type: "plain_text",
text: `${severityEmoji[event.severity]} Security Alert: ${event.event_type}`
}
},
{
type: "section",
fields: [
{ type: "mrkdwn", text: `*Severity:*\n${event.severity}` },
{ type: "mrkdwn", text: `*User:*\n${event.user}` },
{ type: "mrkdwn", text: `*IP Address:*\n${event.ip_address}` },
{ type: "mrkdwn", text: `*Time:*\n${formattedTime}` }
]
},
{
type: "section",
text: {
type: "mrkdwn",
text: `*Recommendation:*\n${event.recommendation}`
}
}
]
}{
"text": "🟠 Security Alert: Suspicious Login",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "🟠 Security Alert: Suspicious Login"
}
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Severity:*\nHIGH" },
{ "type": "mrkdwn", "text": "*User:*\njohn.doe" },
{ "type": "mrkdwn", "text": "*IP Address:*\n203.0.113.42" },
{ "type": "mrkdwn", "text": "*Time:*\nJan 15, 10:30 AM UTC" }
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Recommendation:*\nForce password reset and review account activity"
}
}
]
}new Function(). While this provides basic isolation, it's not a full security sandbox. Avoid executing untrusted code.input1, input2, etc.JSON.parse(), JSON.stringify()new Date(), date formattingfs module, can't read/write filesfetch(), XMLHttpRequest, or HTTP clientswindow, document, process, require()setTimeout(), setInterval(), Promise (code runs synchronously)import or require()new Function() which still has access to closures and the outer scope. This is NOT a fully secure sandbox. Do not execute untrusted or user-provided code.Always validate input data before processing. Check for null/undefined, expected data types, and required fields.
Use try-catch blocks for operations that might fail (JSON parsing, property access on undefined objects).
JavaScript execution has a timeout (30 seconds). Infinite loops will cause workflow failure.
Each JavaScript node should do one thing well. Break complex logic into multiple nodes for better debugging and reusability.
The JavaScript node is validated before execution. Validation errors will block workflow execution.
codeinput3 with only 2 connections)return statement found (code will return undefined)When you export your workflow to TypeScript code, the JavaScript node's code is embedded directly into the generated function:
// JavaScript Node: Calculate severity score
const node_javascript1 = (() => {
// Your JavaScript code is inserted here
const threats = JSON.parse(input1)
const score =
(threats.critical * 10) +
(threats.high * 5) +
(threats.medium * 2) +
(threats.low * 1)
let severity
if (score >= 50) severity = "CRITICAL"
else if (score >= 25) severity = "HIGH"
else if (score >= 10) severity = "MEDIUM"
else severity = "LOW"
return {
score: score,
severity: severity,
requires_immediate_action: score >= 50
}
})()
// Result is available for downstream nodes
const javascript1_result = node_javascript1export async function POST(req: Request) {
// ... previous nodes ...
// JavaScript Node: Calculate severity score
try {
const node_javascript1 = (() => {
// Input variables from upstream nodes
const input1 = node_textModel1
// Your JavaScript code
const threats = JSON.parse(input1)
const score =
(threats.critical * 10) +
(threats.high * 5) +
(threats.medium * 2) +
(threats.low * 1)
let severity
if (score >= 50) severity = "CRITICAL"
else if (score >= 25) severity = "HIGH"
else if (score >= 10) severity = "MEDIUM"
else severity = "LOW"
return {
score: score,
severity: severity,
requires_immediate_action: score >= 50
}
})()
const javascript1_result = node_javascript1
} catch (error) {
return Response.json(
{ error: `JavaScript execution failed: ${error.message}` },
{ status: 500 }
)
}
// ... downstream nodes ...
return Response.json({
success: true,
outputs: { javascript1: javascript1_result }
})
}return keyword so downstream nodes have data to work withwindow, document, process are not availableinput3try {
const data = JSON.parse(input1)
return data.someField
} catch (error) {
console.log("JSON parse error:", error.message)
return null
}// Use optional chaining and nullish coalescing
const email = data?.user?.email ?? "unknown@example.com"
const count = data?.threats?.length ?? 0if (!input1 || typeof input1 !== "string") {
return { error: "Invalid input: expected string" }
}
const data = JSON.parse(input1)
if (!data.threats || !Array.isArray(data.threats)) {
return { error: "Invalid data structure" }
}
// Proceed with processing...Learn common patterns for data transformation and processing in multi-node workflows
Understand how data flows between nodes and how to use variable interpolation effectively
Combine JavaScript calculations with conditional branching for dynamic workflows