How to Use For Loops in Robot Framework
Learn Robot Framework FOR loops for lists, ranges, paired values, and dictionaries, with control flow, version notes, runnable examples, and troubleshooting.
Use a block loop in Robot Framework: start with FOR, choose IN or a specialized marker such as IN RANGE, put the repeated keyword calls in the body, and close the loop with END. The examples below use the current syntax; legacy :FOR syntax was removed in Robot Framework 4.0.
1. Basic FOR loop syntax
A loop assigns the next value to its loop variable on each iteration. Loop markers are case-sensitive. Indent the body to make the block easier to scan.
*** Test Cases ***
Process Items
FOR ${item} IN apple banana cherry
Log Processing ${item}
END
Use the same structure in a test case or a user keyword. For a list variable, expand the list with @{} in the loop header:
*** Test Cases ***
Process Items From List
@{items}= Create List apple banana cherry
FOR ${item} IN @{items}
Log Processing ${item}
END
Each pass assigns one list item to ${item}. Keep the loop body focused; move complicated work into a user keyword so the test reads as a sequence of actions.
2. Choose the loop form that matches your data
| Input or need | Loop form | What gets assigned |
|---|---|---|
| Values or a list | FOR ${item} IN ... |
One value per iteration |
| Generated numeric positions | FOR ${index} IN RANGE ... |
Numbers in a range; the end is excluded |
| Value and its position | FOR ${index} ${item} IN ENUMERATE ... |
Index and corresponding item |
| Corresponding values in lists | FOR ${a} ${b} IN ZIP ... |
One value from each list in each pass |
| Dictionary entries | FOR ${key} ${value} IN ${dict} |
Key and value |
Iterate over a numeric range
IN RANGE generates numeric values. A single argument is the exclusive end, so IN RANGE 10 produces 0 through 9. You can provide start, end, and step; a negative step counts downward. Float parameters are supported.
*** Test Cases ***
Check Rows
FOR ${index} IN RANGE 1 4
Log Checking row ${index}
END
This iterates over 1, 2, and 3. Avoid assuming the end value is included.
Keep an item and its index with IN ENUMERATE
IN ENUMERATE assigns an index and item together. The default index begins at zero. Robot Framework 4.0 and later supports a custom starting index using start=.
*** Test Cases ***
Log Numbered Items
@{items}= Create List alpha beta
FOR ${index} ${item} IN ENUMERATE @{items}
Log ${index}: ${item}
END
Start Numbering At One
@{items}= Create List alpha beta
FOR ${index} ${item} IN ENUMERATE @{items} start=1
Log ${index}: ${item}
END
Process related lists with IN ZIP
Use IN ZIP when values from different lists belong together by position. The number of loop variables should match the number of collections.
*** Test Cases ***
Check User Records
@{ids}= Create List u-101 u-102
@{names}= Create List Ada Lin
FOR ${id} ${name} IN ZIP ${ids} ${names}
Log Checking ${id} for ${name}
END
Iterate over dictionary entries
Use two loop variables with a dictionary to receive each key and its value:
*** Test Cases ***
Log Settings
&{settings}= Create Dictionary theme=dark retries=3
FOR ${key} ${value} IN &{settings}
Log ${key}=${value}
END
Assign several values per iteration
A loop can have multiple variables before IN. In an ordinary value sequence, the values must divide evenly among the loop variables. Choose a specialized form such as IN ZIP when it better expresses paired collections.
3. Nested loops and loop control
Nested FOR loops are supported from Robot Framework 4.0. They are useful for simple combinations, such as rows and cells. Keep multiple levels readable, and extract complex actions into user keywords.
*** Test Cases ***
Visit Table Cells
@{rows}= Create List header body
@{columns}= Create List name status
FOR ${row} IN @{rows}
FOR ${column} IN @{columns}
Log Checking ${row}, ${column}
END
END
BREAK exits the loop, while CONTINUE skips the rest of the current iteration. Put either control keyword inside the loop body, including within a conditional structure. They cannot be placed in a separate keyword called by the loop body.
*** Test Cases ***
Stop When Found
@{items}= Create List first target later
FOR ${item} IN @{items}
IF $item == 'target'
Log Found target
BREAK
END
Log Still searching: ${item}
END
Skip Empty Values
@{items}= Create List alpha ${EMPTY} beta
FOR ${item} IN @{items}
IF $item == $EMPTY
CONTINUE
END
Log Processing ${item}
END
4. When to use Repeat Keyword instead
If the goal is only to run one keyword a fixed number of times, a full loop may add unnecessary structure. Robot Framework’s BuiltIn Repeat Keyword can express that directly:
*** Test Cases ***
Retry A Simple Action
Repeat Keyword 3 times Log Checking again
For a series of values, conditions, indexes, or multiple calls per pass, use a FOR loop instead. The official Robot Framework User Guide notes that test libraries can provide loop constructs and that loop logic often belongs in libraries.
5. Version and syntax notes
- Use the block form
FOR ... ENDin current code. - Nested
FORloops and the customstart=option forIN ENUMERATEare available from Robot Framework 4.0. - The older
:FORsyntax was deprecated in Robot Framework 3.2 and removed in 4.0. - For exact behavior and version-specific details, consult the Robot Framework 7.4.2 User Guide, Control Structures.
6. Troubleshooting common loop errors
| Symptom | Likely cause | Fix |
|---|---|---|
| Parser rejects a loop or reports an unexpected token | A block is missing END, or FOR/IN casing is wrong. |
Use uppercase markers and close each block with its own END row. |
| Old loop example fails on a current Robot Framework version | It uses the removed :FOR form. |
Rewrite it as a FOR ... IN ... END block. |
| Loop runs zero times or misses the expected final number | IN RANGE excludes its end value. |
Adjust the end argument if you need that value included. |
| Paired data appears mismatched | Lists are not aligned by position, or multiple loop variables do not divide evenly into the values. | Check collection ordering and lengths; use IN ZIP for corresponding list elements. |
| Nested loop or custom enumerate start is rejected | The Robot Framework version is older than 4.0. | Upgrade to version 4.0 or later, or rewrite without the unsupported feature. |
BREAK or CONTINUE is rejected |
The control keyword is outside a loop body or inside a called keyword. | Move it into the loop’s body, optionally under an IF. |
| Loop body is difficult to maintain | Too much branching or work is packed into the loop. | Move the work into a well-named user keyword or a library keyword. |
7. Performance, reliability, and cost
Choose the loop form that matches the input and avoid repeating expensive setup work inside every iteration when it can be done once before the loop. Keep iteration count bounded when deriving values from external input, and make failures identify the current item or index so a test report is actionable. The cited loop documentation provides no benchmark or cost figures, so performance depends on the keywords and systems each iteration invokes; a loop over local values is not equivalent to repeating browser or network work.
8. Capture screenshots from a Robot Framework loop
A loop can also drive repeated website captures—for example, capturing several URLs in a regression check. For a DIY browser workflow, put the browser setup and capture keywords in a user keyword, then call it once per URL. This Robot Framework example uses the Browser library keyword interface, so install and configure the library in the project before running it:
*** Settings ***
Library Browser
*** Test Cases ***
Capture Pages
@{urls}= Create List https://example.com https://robotframework.org
FOR ${url} IN @{urls}
New Browser chromium headless=True
New Page ${url}
Take Screenshot filename=${OUTPUT DIR}/${url}.png
Close Browser
END
When applying this pattern in a real suite, use safe filenames derived from each URL and ensure the browser is closed even if navigation or capture fails. The loop syntax itself is built into Robot Framework; browser keywords come from the configured library.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Replace local browser lifecycle code with one request per URL. See the ScreenshotNeo API documentation for the request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents screenshot tools. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.
9. FAQ
Can a loop run in a user keyword?
Yes. The same block-loop form works in test cases and user keywords.
Does IN RANGE include its end?
No. Its end is exclusive.
Can BREAK stop only one nested loop?
Use it in the loop body whose execution you want to stop, and structure nested control flow so the intended loop is clear.
Where can I check the full supported syntax?
See the official Robot Framework User Guide control structures section.


