Overview
The Loop node enables iteration in workflows. It supports two modes: iterating over arrays (forEach) and repeating while conditions are true (doWhile). Loop nodes are containers that execute child nodes repeatedly.
Loop Modes
forEach
Iterate over an array, executing child nodes for each item.
Set to forEach for array iteration.
Context variable name containing the array to iterate over.
Loop Variables:
${data.item} - Current array item
${data.index} - Current iteration index (0-based)
Example:
{
"type" : "loop" ,
"data" : {
"mode" : "forEach" ,
"arrayVariable" : "products"
}
}
// Inside loop:
// ${data.item.name} - Product name
// ${data.item.price} - Product price
// ${data.index} - Current index
doWhile
Repeat child nodes while a condition is true.
Set to doWhile for conditional looping.
Condition to evaluate after each iteration. Condition types:
selector - Check if element exists
url - Check if URL matches
javascript - Custom JavaScript condition
Maximum iterations to prevent infinite loops.
JavaScript code to execute after each iteration (e.g., increment counter).
Loop Variables:
${data.index} - Current iteration index (0-based)
${data.item} - Set to null (not used in doWhile)
Configuration
Loop mode: forEach or doWhile
If true, errors in loop setup log warnings but don’t stop execution.
Examples
forEach Loops
Iterate Products
Process URLs
API Requests
// First, extract products
{
"type" : "dataExtractor" ,
"data" : {
"containerSelector" : ".product-card" ,
"fields" : [
{ "name" : "title" , "selector" : ".title" , "extract" : "text" },
{ "name" : "price" , "selector" : ".price" , "extract" : "text" }
],
"outputVariable" : "products"
}
}
// Then, loop over products
{
"type" : "loop" ,
"data" : {
"mode" : "forEach" ,
"arrayVariable" : "products"
},
"children" : [
{
"type" : "javascriptCode" ,
"data" : {
"code" : "console.log(`Product ${context.getData('index')}: ${context.getData('item').title} - ${context.getData('item').price}`)"
}
}
]
}
doWhile Loops
Click Next Until Done
Scroll Until Bottom
Poll Until Success
{
"type" : "loop" ,
"data" : {
"mode" : "doWhile" ,
"condition" : {
"type" : "selector" ,
"value" : "button.next-page" ,
"visibility" : "visible"
},
"maxIterations" : 10
},
"children" : [
{
"type" : "action" ,
"data" : {
"action" : "click" ,
"selector" : "button.next-page"
}
},
{
"type" : "wait" ,
"data" : {
"waitType" : "timeout" ,
"value" : 2000
}
}
]
}
Complex Iterations
Nested Loops
Conditional Processing
// Outer loop: categories
{
"type" : "loop" ,
"data" : {
"mode" : "forEach" ,
"arrayVariable" : "categories"
},
"children" : [
{
"type" : "navigation" ,
"data" : {
"action" : "navigate" ,
"url" : "https://example.com/${data.item.slug}"
}
},
{
"type" : "dataExtractor" ,
"data" : {
"containerSelector" : ".product" ,
"fields" : [ ... ],
"outputVariable" : "categoryProducts"
}
},
// Inner loop: products in category
{
"type" : "loop" ,
"data" : {
"mode" : "forEach" ,
"arrayVariable" : "categoryProducts"
},
"children" : [
{
"type" : "javascriptCode" ,
"data" : {
"code" : "console.log(context.getData('item').name)"
}
}
]
}
]
}
Loop Variables Access
In JavaScript Code
In Selectors
In API URLs
const currentIndex = context . getData ( 'index' );
const currentItem = context . getData ( 'item' );
console . log ( `Processing item ${ currentIndex } ` );
console . log ( `Item data:` , currentItem );
// Modify item data
context . setData ( 'processedItem' , {
... currentItem ,
processed: true
});
Loop Control Patterns
Early Exit
// Inside loop JavaScript Code node
const item = context . getData ( 'item' );
if ( item . shouldStop ) {
// Set flag to exit
context . setData ( 'breakLoop' , true );
}
Skip Items
// Conditional processing
const item = context . getData ( 'item' );
if ( item . skip ) {
return ; // Skip to next iteration
}
// Continue processing
Accumulate Results
// Collect results from iterations
const results = context . getData ( 'loopResults' ) || [];
const currentResult = context . getData ( 'currentResult' );
results . push ( currentResult );
context . setData ( 'loopResults' , results );
Common Use Cases
[
// Navigate to first page
{
"type" : "navigation" ,
"data" : { "action" : "navigate" , "url" : "https://example.com/page/1" }
},
// Loop through pages
{
"type" : "loop" ,
"data" : {
"mode" : "doWhile" ,
"condition" : {
"type" : "selector" ,
"value" : ".next-page" ,
"visibility" : "visible"
},
"maxIterations" : 50
},
"children" : [
{ "type" : "dataExtractor" , "data" : { ... } },
{ "type" : "action" , "data" : { "action" : "click" , "selector" : ".next-page" } },
{ "type" : "wait" , "data" : { "waitType" : "timeout" , "value" : 1000 } }
]
}
]
Batch Processing
{
"type" : "loop" ,
"data" : {
"mode" : "forEach" ,
"arrayVariable" : "filePaths"
},
"children" : [
{
"type" : "apiRequest" ,
"data" : {
"url" : "https://api.example.com/upload" ,
"method" : "POST" ,
"formFiles" : [{ "name" : "file" , "filePath" : "${data.item}" }]
}
}
]
}
Notes
The maxIterations parameter in doWhile loops prevents infinite loops by limiting the maximum number of iterations.
Loop variables (item and index) are overwritten in nested loops. Store values in separate context variables if needed for outer loop access.
The doWhile loop always executes at least once before checking the condition.