Skip to main content

Script Task ⚡

Executes JavaScript or Python code directly within the workflow.

Node type: scriptTask Category: Logic Actor: scriptTask (2 threads)


Description

The Script Task runs arbitrary code for data transformation, computation, custom logic, or string manipulation. Scripts are executed in an isolated GraalVM Polyglot sandbox — they cannot access the file system, network, or JVM classes directly.

Scripts receive all current workflow variables as inputs and can set new variables or override existing ones by returning a result object.


Properties

PropertyTypeRequiredDescription
scriptFormatselectYesjavascript or python
scriptcodeYesThe script body to execute

Script Environment

Available Variables

All current workflow variables are injected into the script execution context:

// All these are automatically available:
console.log(customerName); // workflow variable {customerName}
console.log(orderTotal); // workflow variable {orderTotal}
console.log(items); // workflow variable {items} (if it's an array/object)

Returning Results

Return an object to set or update workflow variables:

return {
formattedTotal: `$${parseFloat(orderTotal).toFixed(2)}`,
itemCount: items.length,
isLargeOrder: parseFloat(orderTotal) > 1000
};

After this script runs, {formattedTotal}, {itemCount}, and {isLargeOrder} are available to all downstream nodes.

If the script returns null or nothing, no variables are modified.


JavaScript Examples

String Manipulation

// Normalize phone number to E.164 format
const digits = phoneNumber.replace(/\D/g, '');
const e164 = digits.startsWith('1') ? `+${digits}` : `+1${digits}`;

return {
normalizedPhone: e164,
phoneValid: e164.length === 12
};

Date Formatting

// Format a date for email display
const date = new Date(appointmentTimestamp);
const formatted = date.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});

return { formattedDate: formatted };

Data Transformation

// Transform API response array into summary stats
const orders = JSON.parse(ordersJson);

const total = orders.reduce((sum, o) => sum + o.amount, 0);
const avgOrder = total / orders.length;
const highestOrder = Math.max(...orders.map(o => o.amount));

return {
orderCount: orders.length,
totalRevenue: total.toFixed(2),
averageOrder: avgOrder.toFixed(2),
highestOrder: highestOrder.toFixed(2)
};

Conditional Processing

// Parse AI classification response and validate
let classification;
try {
const parsed = JSON.parse(aiResponse);
classification = parsed.classification;
} catch (e) {
// Fallback if AI returned non-JSON
classification = 'general';
}

const validClasses = ['billing', 'technical', 'account', 'general'];
const isValid = validClasses.includes(classification);

return {
classification: isValid ? classification : 'general',
classificationConfident: isValid
};

Python Examples

# Calculate order discount
discount_rate = 0.15 if float(orderTotal) > 500 else 0.05
discount_amount = float(orderTotal) * discount_rate
final_total = float(orderTotal) - discount_amount

return {
"discountRate": discount_rate,
"discountAmount": round(discount_amount, 2),
"finalTotal": round(final_total, 2)
}
# Parse and validate email list
emails = recipientEmails.split(',')
valid_emails = [e.strip() for e in emails if '@' in e and '.' in e.split('@')[-1]]

return {
"validEmails": valid_emails,
"emailCount": len(valid_emails),
"hasValidEmails": len(valid_emails) > 0
}

Sandbox Restrictions

Scripts run in GraalVM Polyglot sandbox with these restrictions:

CapabilityAvailable?
Standard math/string/array operations
JSON.parse / JSON.stringify
Date operations
Regular expressions
console.log (captured in execution logs)
File system access
Network calls (fetch, http)
JVM class access
require() / import (external modules)

For network calls or external integrations, use the appropriate Service Task nodes instead.


Error Handling

ScenarioBehavior
Script throws an uncaught exceptionNode fails, error message in {_error}, takes errorFlow
Script returns non-objectNo variables modified, execution continues
Script syntax errorNode fails immediately at execution start
Timeout exceededTakes timeoutFlow; script is interrupted
// Good pattern: wrap risky operations in try/catch
try {
const data = JSON.parse(rawApiResponse);
return { parsedData: data, parseSuccess: true };
} catch (e) {
return { parsedData: null, parseSuccess: false, parseError: e.message };
}

Connections

ConditionConnection
Script completed without errorsuccessFlow or sequenceFlow
Script threw uncaught exceptionerrorFlow
TimeouttimeoutFlow

Best Practices

  • Wrap risky operations (JSON.parse, type conversions) in try/catch
  • Always return an object — this makes variable changes explicit
  • Set a timeout (5–10 seconds) — infinite loops will block the actor thread
  • Log intermediate values with console.log() — they appear in execution logs
  • Keep scripts focused on one transformation — chain multiple Script Tasks for complex processing
  • Test scripts locally before deploying (they're pure functions with simple inputs)