> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cogniagent.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Loop Node

> Repeat the same steps for each item in a list

The Loop node repeats the same actions for every item in a list. If you have 10 emails to process, it does the same thing 10 times - once for each email.

Think of it like a factory assembly line: each item comes through, gets the same treatment, then moves on.

<Frame caption="Loop configuration — point at an array of items and name the per-iteration variable.">
  <img src="https://mintcdn.com/glorium/eqWkhSfBUec9afZU/images/nodes/node-loop-form.png?fit=max&auto=format&n=eqWkhSfBUec9afZU&q=85&s=da0d051ccd3236f7f04bc2566120960e" alt="Loop node configuration form" width="1440" height="1200" data-path="images/nodes/node-loop-form.png" />
</Frame>

## When to Use

* **Processing lists** - Handle each email, each row in a spreadsheet, each file
* **Sending to multiple people** - Send personalized emails to everyone on a list
* **Processing data** - Do the same thing to every item
* **Collecting results** - Gather what you learned from each item

## Example: Process Email Attachments

Extract and analyze each attachment from an email:

<Steps>
  <Step title="Receive email with attachments">
    Use Event from App (Gmail) to trigger on emails with attachments.
  </Step>

  <Step title="Loop over attachments">
    Add a Loop node:

    * Iterable data: `{{event_from_app_1.email.attachments}}`
  </Step>

  <Step title="Process each attachment">
    Inside the loop:

    * Read File (current attachment)
    * Ask AI (analyze content)
    * Update Variable (append results)
  </Step>

  <Step title="After loop">
    Send summary of all analyzed attachments.
  </Step>
</Steps>

**Workflow:**

```
├── Event from App (Gmail with attachments)
├── Update Variable (results = [], initialize)
├── Loop (over attachments)
│   ├── Read File ({{loop_1.currentItem}})
│   ├── Ask AI (analyze: {{parse_file_1.content}})
│   └── Update Variable (results, append {{llm_1.response}})
└── External API (Slack: "Processed {{loop_1.completedCount}} files")
```

## Example: Send Personalized Emails

Send individual emails to a list of recipients:

```
├── HTTP Request (get recipient list from CRM)
├── Loop (over {{http_request_1.body.contacts}})
│   ├── Ask AI (generate personalized message for {{loop_1.currentItem.name}})
│   └── External API (Gmail: send to {{loop_1.currentItem.email}})
└── Update Variable (log: sent {{loop_1.completedCount}} emails)
```

**Accessing item properties:**

```
Name: {{loop_1.currentItem.name}}
Email: {{loop_1.currentItem.email}}
Company: {{loop_1.currentItem.company}}
```

## Example: Process Spreadsheet Rows

Handle each row from a Google Sheet:

```
├── External API (Google Sheets: get all rows)
├── Loop (over {{external_api_1.values}})
│   ├── Condition (row has email?)
│   │   ├── Met:
│   │   │   ├── Ask AI (classify lead)
│   │   │   └── External API (HubSpot: create/update contact)
│   │   └── Unmet: (skip row)
└── External API (Slack: "Processed {{loop_1.completedCount}} leads")
```

## Collecting Results from Each Loop

If you want to remember what happened with each item:

### Save Results as You Go

```
├── Update Variable (allResults = [], create empty list first)
├── Loop (over items)
│   ├── Ask AI (analyze the item)
│   └── Update Variable (allResults, add this result to the list)
└── Ask AI (summarize all the results)
```

This way, after the loop ends, you have a list of everything that happened.

### Process Results with Code

```python theme={null}
# Get all the results we collected
results = input["set_variable_1"]["value"]

# Count successes and failures
successful = [r for r in results if r["success"]]
failed = [r for r in results if not r["success"]]

return {
    "total": len(results),
    "successful": len(successful),
    "failed": len(failed)
}
```

## Loops Inside Loops

Sometimes you need to loop through a list that's inside another list:

```
├── Loop (for each department)
│   └── Loop (for each employee in that department)
│       └── Send email to that employee
```

<Warning>
  Be careful with loops inside loops - the numbers multiply! 10 departments with 50 employees each = 500 total emails.
</Warning>

## Conditional Processing

Skip items that don't meet criteria:

```
├── Loop (over items)
│   ├── Condition (should process?)
│   │   ├── Met: Process item
│   │   └── Unmet: (skip - no action)
```

The unmet branch doesn't need to connect to anything.

## Using Index and Position

**First item handling:**

```
├── Loop
│   ├── Condition ({{loop_1.isFirst}})
│   │   ├── Met: Send "Starting batch of {{loop_1.totalCount}} items"
│   │   └── Unmet: (continue)
│   └── Process item
```

**Last item handling:**

```
├── Loop
│   ├── Process item
│   ├── Condition ({{loop_1.isLast}})
│   │   ├── Met: Send "Completed all {{loop_1.totalCount}} items"
│   │   └── Unmet: (continue)
```

**Using index for numbering:**

```
Item {{loop_1.currentIndex + 1}} of {{loop_1.totalCount}}: {{loop_1.currentItem.name}}
```

## Loop Completion

The nodes connected after the loop (not inside it) execute once after all iterations complete:

```
├── Loop (over 10 items)
│   └── [Executes 10 times]
└── After Loop [Executes 1 time after loop completes]
```

## Error Handling

By default, if one iteration fails, the loop continues with remaining items. To handle errors:

```
├── Loop (over items)
│   ├── HTTP Request (call API)
│   ├── Condition (success?)
│   │   ├── Met: Update Variable (successes, append)
│   │   └── Unmet: Update Variable (failures, append)
```

Then after the loop, check failures and alert if needed.

## How Long Will It Take?

<Warning>
  Items are processed one at a time. If you have 100 items and each takes 3 seconds, that's 5 minutes total.
</Warning>

**If your loop is slow:**

* Some services let you send multiple items at once - check if yours does
* Test with just a few items first before running the full list
* Make sure your timeout is long enough

## Tips

<Tip>
  Create your results list before the loop starts. Use `Update Variable` to create an empty list `[]`, then add to it inside the loop.
</Tip>

<Tip>
  Use `isFirst` to send a "starting now" message, and `isLast` to send a "all done" message.
</Tip>

<Tip>
  While building and testing, add a condition that only processes the first 3 items. Once everything works, remove that condition.
</Tip>

## Settings

<ParamField path="name" type="string" default="Loop">
  What to call this node (shown on the canvas).
</ParamField>

<ParamField path="key" type="string" default="loop_1">
  A short code to reference this node's data.
</ParamField>

<ParamField path="iterableData" type="string" required>
  The list to loop through. Examples:

  * `{{http_request_1.body.items}}` - items from a web request
  * `{{event_from_app_1.email.attachments}}` - files attached to an email
  * `{{external_api_1.values}}` - rows from a spreadsheet
</ParamField>

## Outputs

During each loop iteration:

<ParamField path="currentItem" type="any">
  The item being processed right now.
</ParamField>

<ParamField path="currentIndex" type="number">
  Which number item this is (starts at 0, so the first item is 0, second is 1, etc.).
</ParamField>

<ParamField path="isFirst" type="boolean">
  True if this is the first item.
</ParamField>

<ParamField path="isLast" type="boolean">
  True if this is the last item.
</ParamField>

<ParamField path="totalCount" type="number">
  How many items there are in total.
</ParamField>

After the loop finishes:

<ParamField path="completedCount" type="number">
  How many items were processed.
</ParamField>

## Related Nodes

<CardGroup cols={2}>
  <Card title="Condition" icon="code-branch" href="/nodes/logic/condition">
    Filter items within loops.
  </Card>

  <Card title="Update Variable" icon="database" href="/nodes/actions/update-variable">
    Accumulate results across iterations.
  </Card>
</CardGroup>
