Overview
The Custom Code action lets you run JavaScript/TypeScript code within your workflow to transform data, make API calls, or perform custom logic.
How It Works
- Input: Access all workflow data via
inputData - Execute: Your code runs in a secure sandbox
- Output: Store results in
outputfor subsequent actions
Input Data
The inputData object contains all data available at this point in your workflow - including data from previous actions, user context, and system variables.
1 2 3 4 5 6// Access workflow data const userName = inputData.user_name; const previousResult = inputData.api_response; // Use optional chaining for nested data const city = inputData.address?.city;
Output
Assign values to the output object to pass data to subsequent actions:
1 2 3 4 5 6output.result = "processed"; output.total = inputData.items.length; output.summary = { success: true, count: 42 };
Handling Sensitive Data
When working with sensitive values like API keys, client secrets, or tokens, use the redact() function to prevent them from appearing in execution logs.
1 2 3 4 5 6 7 8 9 10const clientSecret = redact('client_secret'); const response = await fetch('https://api.example.com/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `grant_type=client_credentials&client_id=${inputData.client_id}&client_secret=${clientSecret}` }); const data = await response.json(); output.access_token = data.access_token;
How it works:
redact('field_name')returns the value frominputDatajust likeinputData.field_name- The value is automatically scrubbed from execution logs
- Use this for any sensitive data that shouldn't appear in workflow execution logs
The redact() function only works with top-level fields in inputData. Pass the field name as a string, not the value itself.
1 2 3 4 5// ✅ Correct const secret = redact('client_secret'); // ❌ Incorrect - this won't redact anything const secret = redact(inputData.client_secret);
Runtime & Limits
| Runtime | Deno 1.46.1 (not Node.js) |
| Timeout | 5 seconds |
| Memory | 64 MB |
| Fetch requests | 5 per execution |
| External libraries | None available |
Full ES support: async/await, optional chaining, nullish coalescing, etc.
Examples
Basic Transformation
1 2 3 4 5 6 7 8const items = inputData.raw_items ?? []; output.processed = items.map(item => ({ id: item.id, name: item.name.toUpperCase() })); output.count = items.length;
API Call
1 2 3 4 5 6 7 8 9 10 11 12 13try { const response = await fetch("https://api.example.com/data", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: inputData.user_id }) }); output.result = await response.json(); output.success = true; } catch (error) { output.error = error.message; output.success = false; }
Common Gotchas
- Deno, not Node: Node-specific APIs (like
require()) won't work - No libraries: lodash, axios, etc. are not available - use native JS
- 5 fetch limit: Scripts making more than 5 HTTP requests will fail
- 5 second timeout: Long-running operations will be killed
- Always use
redact()for sensitive data: If your code handles API keys, secrets, or tokens, wrap them withredact('field_name')to prevent them from appearing in execution logs
