Skip to main content
These are the jobs people most often give an Execute Code node, each with the workflow around it, the code, and what to watch for. Copy one, change the keys and names to yours, and test it with a few records first. New to the node? Start with Execute Code for how inputs, outputs and the editor work, and Execute Code integrations for calling apps.

Which node for the job?

Code is one of several ways to do work in a workflow. Pick the simplest one that fits:
A rule of thumb: when every item gets the same treatment, loop in code. It runs the calls back to back in one step, with no model turn per item. When each item needs judgment, or a person, use a Loop node around the nodes that provide it.

Clean up incoming data

The job: a web form posts leads with messy names, emails in capitals and phone numbers full of spaces. Clean them before they reach your CRM.
In the Integration Action, map each field from this step, for example Email to {{clean_lead.result.email}}. Watch for:
  • Use body.get("field") rather than body["field"]. A form that leaves a field out would otherwise stop the step with a KeyError.
  • Return a valid flag and branch on it with a Condition, rather than failing the step on bad input.

Act on every row of a sheet

The job: every morning, post each qualified lead in a Google Sheet to Slack, and report any that failed.
Bind Google Sheets with the Batch get action and Slack with Send message, then:
sheet_id is a workflow variable holding the spreadsheet’s ID. Watch for:
  • Google Sheets leaves out empty cells at the end of a row, so a row can be shorter than you expect. (row + ["", "", ""])[:3] pads it.
  • Catching IntegrationError inside the loop means one bad row doesn’t stop the rest. failed tells you which rows to look at.
  • Every message counts toward the limit of 200 app calls per run. For bigger sheets, handle a batch per run, as in the next scenario.
  • Calls already made are not undone. If the step runs twice, the messages go out twice, so remember what you’ve done.

Handle only what’s new since the last run

The job: a sheet keeps growing. Each hour, handle only the rows added since the last run, at most 150 at a time.
Add a workflow variable rows_done of type Number, starting at 0. It remembers how many rows are already handled:
Watch for:
  • set_variable runs once, at the end. If the step fails halfway, rows_done keeps its old value and the next run sends that batch again. When a repeat would hurt, call set_variable after each row instead. That’s up to 100 calls per run.
  • This counts rows, so it assumes rows are only ever added at the bottom. If people insert or delete rows, remember an ID or a date instead: store the newest one you’ve handled, and skip anything older.

Build a report and send it as a file

The job: every Monday, total last week’s orders by region into an Excel file and email it.
In the email step, insert {{weekly_report.files[0]}} into the attachment field. Use {{weekly_report.result.revenue}} in the message text. Watch for:
  • Save the file under a plain name, like weekly-sales.xlsx. Files in subfolders are not attached.
  • float(...) turns pandas’ number into a plain one, so output_data can store it.
  • Charts work the same way: matplotlib and plotly are installed, and plt.savefig("chart.png") produces a file to attach.

Score a lead and route it

The job: score each new lead by fixed rules, then send hot leads to sales and the rest to a nurture list.
Watch for:
  • Form values often arrive as text. int(...) makes "120" a number before you compare it.
  • Code gives the same answer for the same lead every time, and costs no model call. When the decision needs reading a free-text message, use an LLM instead, or let code do the arithmetic and an LLM the reading.

Pull facts out of a document

The job: invoices arrive as PDFs. Pull out the invoice number, date and total.
Watch for:
  • Let Read File turn the PDF into text. The code works on its content.
  • Patterns fit documents from the same sender. When layouts vary a lot, an LLM reads them more reliably.
  • Return None for a field you couldn’t find, and check it in a Condition, rather than guessing.

Call a web service that isn’t in the app list

The job: look up public data, such as an exchange rate, from a service without an app in the catalog.
Watch for:
  • Always pass a timeout. Without one, a slow service can hold the step until the 30-minute limit.
  • raise_for_status() stops the step on an error answer instead of returning bad data.
  • Everyone who can edit the workflow can read the code. For a service that needs a key or a login, connect it as an app, or use the HTTP Request node.

Habits that keep code steps reliable

Wrap the work for each record in try / except, and collect what failed in the output. One bad record then costs one record, not the whole run.
A step can run twice: a retry, a re-run, an overlapping schedule. Before creating something, check whether it exists, or remember what you’ve done in a workflow variable. Calls already made are never undone.
One run has 30 minutes, 200 app calls and 100 set_variable calls. For big jobs, handle a batch per run and remember where you stopped.
Anything written to the error stream fails the step, warnings included. Silence the warnings you expect with warnings.filterwarnings("ignore").
Not sure what an earlier node or an app call returns? print() it once and read stdOut after a test run. Then read the fields with .get() so a missing one doesn’t stop the step.
A node that cleans, scores and sends is hard to fix. Split it into steps with clear names; each one’s output shows in the run history.

Execute Code

Inputs, outputs, files, variables, the editor and limits.

Execute Code integrations

Bind apps and call them from Python.

Loop

Run several nodes for every item.

Condition

Branch on a value your code returned.