for_loop_node to repeat actions for each value in a list, or for each element matching a Playwright locator on the page—processing search results, downloading multiple files, or clicking through table rows.
Exactly one of variable_name or locator is required.
Structure
Variable loop
Locator loop
locator_timeout for the first match to attach, then waits until the match count stays unchanged for 1 second (so slowly streaming rows are not missed), snapshots that count once, and iterates 0 .. count-1. An empty match set runs zero iterations with a warning (same as an empty list variable — the run does not fail).
Properties
The Index Variable
Variable loops
Inside a variable loop,{variable[index]} references the current iteration’s value. The token index comes from index_variable_name (default "index"):
Locator loops
Locator loops use the same shape as variable loops:{locator[index]} is the current match (like {order_ids[index]}), and bare {index} is the numeric index:
index_variable_name: "row":
There is no
{index_of(locator)} counterpart to {index_of(<variable>)}. It would carry no per-loop name, so in nested locator loops the outer loop would bind the inner loop’s occurrences. Use the bare {<index_variable_name>} form, which is scoped per level.
Using Multiple Variables in a Loop
You can iterate over multiple parameters in parallel by passing a comma-separated list tovariable_name.
Important: The first in variable_name is the main loop variable that controls:
- How many iterations run (loop length)
- Which index is used for each step
variable_name: "primary_var,secondary_var"→ loop length comes fromprimary_var{primary_var[index]}and{secondary_var[index]}both use the sameindexon each iteration
{variable[index]} is expanded for every name in the list:
primary_var = ["Value A1", "Value A2"]secondary_var = ["Value B1", "Value B2"]
- Iteration 1 uses
{primary_var[index]}→"Value A1"and{secondary_var[index]}→"Value B1" - Iteration 2 uses
{primary_var[index]}→"Value A2"and{secondary_var[index]}→"Value B2"
Waiting for Matches
Locator loops only.count() does not auto-wait, and the sleep after an action returns as soon as the page has loaded — which is immediately for an SPA that re-renders without navigating. Counting straight away would see zero rows and skip the loop body silently, so a locator loop:
- Waits up to
locator_timeout(default 5s) for the first match to attach - Then waits until the match count stays unchanged for 1 second, so rows that appear shortly after the first paint are included
Raise
locator_timeout for slow grids; set it to 0 to skip the first-match wait when rows are already on the page (the 1s stability wait still applies).
Storing One Value Per Iteration
output_variable_name is expanded like any other placeholder, so template it to give each iteration its own variable:
Nested Loops
for_loop_node can contain another for_loop_node. Give each loop a distinct index_variable_name so the outer index stays usable inside the inner loop:
The inner loop’s list must already exist when that loop starts (for example, extract
items inside the outer iteration before the inner for_loop_node).
An inner loop’s locator is itself expanded by the outer loop, so a locator loop can be scoped to the outer iteration — "locator": "{locator[row]}.locator(\"td\")" inside a loop over tr elements iterates that row’s cells. The inner count is taken from the already-scoped locator.
Data Sources
Loop variables can come from:
For dynamic iteration, extract values first:
Reset Nodes
Actions that run after each iteration to return the browser to a known state. Essential for loops that navigate away from the starting page. Reset nodes also receive the current iteration’s placeholder bindings.Reset Strategy Recommendations
Error Handling
Common Patterns
Click Every Matching Element
Download Multiple Files
Download One File Per Matched Row
When the rows are on the page but their identifiers aren’t known in advance, loop the locator and use the index for the filename.{row} works in any field, not just command:
invoice_0.pdf, invoice_1.pdf, invoice_2.pdf. Keep the index in download_filename — a constant name makes every iteration overwrite the previous file.
Process Items and Return
Limitations
- Variable loops require the list to be populated before loop execution
- Locator loops wait for a stable
count()(unchanged for 1s) once at start; DOM changes mid-loop do not change how many iterations run. Setmax_iterationsas a guard and re-check state inside the loop rather than relying on the initial count - Use
{locator[index]}for the current match and bare{index}for the numeric index - When nesting locator loops, give each a distinct
index_variable_nameand reference{locator[row]}/{locator[cell]}so each level keeps its own match token - Locator loops that mutate the matched set (remove/add rows) should use
reset_nodesand/or prefer extracting a stable list into a variable loop - Deep nesting is allowed; keep
index_variable_namedistinct per nesting level when you need both indexes