Introduction
When working with loops in Pega Data Transforms, understanding the built-in parameters
is key to writing efficient and clean logic. One of the most useful, and often
overlooked, parameters is Param.pyForEachCount. This article provides a comprehensive
guide on what it is, how it works, and how you can use it in your day-to-day development.
What is Param.pyForEachCount?
In the Pega Platform, Param.pyForEachCount is a special, system-provided parameter
that is only available within the context of a For Each Page In or
For Each Embedded Page loop in a Data Transform.
Its primary function is to act as a loop counter.
- It holds the current iteration number of the loop.
- The count starts at 1 for the first item in the list.
- It automatically increments by 1 for each page processed.
Note — Nested Rule Calls:
If your Data Transform (or Activity) calls another rule from within the loop
and the “Pass current parameter page” option is enabled on that call,
Param.pyForEachCountis also available to the called rule during that iteration.
This is a subtle but important behaviour: it means nested rules can use the same
counter value without needing to pass it explicitly as a separate parameter.
Developers who are unaware of this sometimes duplicate the counter logic
unnecessarily, so it is worth keeping in mind.
Param.pyForEachCount vs. <CURRENT>
A common point of confusion is the difference between Param.pyForEachCount and the
<CURRENT> keyword. Both are used within loops but serve very different purposes.
| Keyword | Type | Represents | Usage |
|---|---|---|---|
Param.pyForEachCount |
Number (Integer) | The current loop iteration number (1, 2, 3…). | Use it when you need the position or index of the item. |
<CURRENT> |
Page (ClipboardPage) | The actual page being processed in the current iteration. | Use it to read or write properties on the current page. |
In short:
Param.pyForEachCountanswers: “Which item number am I on?”<CURRENT>answers: “Which page am I currently working on?”
You will often use both together. For example:
Set <CURRENT>.Sequence = Param.pyForEachCount
Practical Examples in Data Transform Row Format
Here’s how you would implement logic using Param.pyForEachCount in the actual
Data Transform rule form.
Example 1: Numbering Each Item in a Page List
Let’s assume you have a Page List named .Items and you want to populate a sequence
number for each entry.
| Action | Target | Relation | Source |
|---|---|---|---|
| For Each Page In | .Items |
||
| Set | <CURRENT>.Sequence |
equal to | Param.pyForEachCount |
| Set | <CURRENT>.Status |
equal to | "Processed" |
Example 2: Conditional Logic for the First Item
You can use a When condition to apply logic only to specific items in the loop.
| Action | Target | Relation | Source / Condition |
|---|---|---|---|
| For Each Page In | .Items |
||
| When | Param.pyForEachCount == 1 |
||
| Set | <CURRENT>.IsFirst |
equal to | true |
| When | Param.pyForEachCount > 1 |
||
| Set | <CURRENT>.IsFirst |
equal to | false |
Example 3: Tracking Matched Iterations with a Custom Counter
Use this when you want to track how many conditions matched.
| Action | Target | Relation | Source / Condition |
|---|---|---|---|
| Set | Param.MatchCount |
equal to | 0 |
| For Each Page In | .Items |
||
| When | [Condition true] |
||
| Comment | Your logic |
||
| Set | Param.MatchCount |
equal to | @toInt(Param.MatchCount)+1 |
Example 4: Creating a Display Label
This is useful for creating user-friendly labels that include the item’s position.
| Action | Target | Relation | Source |
|---|---|---|---|
| For Each Page In | .OrderLines |
||
| Set | <CURRENT>.DisplayLabel |
equal to | "Line " + Param.pyForEachCount |
Example 5: Nested Loops and Preserving the Outer Page Reference (Advanced)
When you work with nested For Each Page In loops, the step page context shifts inward with each level. Inside the inner loop, <CURRENT> refers to the inner item, and <PARENT> refers only one level up.
If you need to hold on to the outer loop’s current page while processing the inner loop, <PARENT> alone is not always enough, especially when the nesting is deeper or when you need to pass that reference to another rule.
This is where @pxGetStepPageReference() becomes essential.
What does @pxGetStepPageReference() return?
@pxGetStepPageReference() is an OOTB Pega utility function (RUF) that returns the full clipboard path of the current step page as a string — for example: pyWorkPage.OrderLines(3).
You capture it with a Set step at the beginning of the outer loop iteration, storing the result in a Param. That stored string keeps pointing to the outer item even after the context has shifted into the inner loop.
Note: In Activity Java steps, the equivalent call is
tools.getStepPage().getReference(). In Data Transforms, use the expression@pxGetStepPageReference().
Practical Example: Two-Level Nested Loop
Scenario: You have a Page List .OrderLines, and each order line has a nested Page List .LineItems. For each line item, you need to write back a value to its parent order line — the outer loop’s current item.
| Action | Target | Relation | Source / Condition |
|---|---|---|---|
| For Each Page In | .OrderLines |
||
| Set | Param.OuterPageRef |
equal to | @pxGetStepPageReference() |
| For Each Page In | <CURRENT>.LineItems |
||
| Set | Param.OuterPageRef.TotalQty |
equal to | @toInt(Param.OuterPageRef.TotalQty) + @toInt(<CURRENT>.Qty) |
What’s happening here:
- Before entering the inner loop,
Param.OuterPageRefcaptures the string path of the current order line — for example,pyWorkPage.OrderLines(2). - Inside the inner loop,
<CURRENT>now refers to eachLineItem. The outer order line is no longer reachable via<CURRENT>or<PARENT>. - But
Param.OuterPageRef.TotalQtystill resolves correctly — Pega treats the stored string path as a live clipboard reference, so writing toParam.OuterPageRef.TotalQtywrites directly topyWorkPage.OrderLines(2).TotalQty.
Common Mistake to Avoid
Incorrect — trying to use <PARENT> two levels up:
Set ..TotalQty equal to ...
This does not work as expected in Data Transforms. <PARENT> goes only one level up, and chaining <PARENT>.<PARENT> is not supported syntax in this context.
Correct — store the reference before entering the inner loop:
Set Param.OuterPageRef equal to @pxGetStepPageReference()
Then use Param.OuterPageRef.YourProperty inside the inner loop to target the outer page.
When to use @pxGetStepPageReference()
| Situation | Use it? |
|---|---|
Single-level For Each Page In — writing back to <CURRENT> |
<CURRENT> directly |
| Two-level nesting — need to update the outer item from the inner loop | Param.OuterPageRef before inner loop |
| Passing the current page’s path to a called sub-Data Transform | @pxGetStepPageReference() as a parameter |
| Evaluating a When rule that lives on the outer page’s class | |
| Nesting deeper than two levels |
Best practice: Even with
@pxGetStepPageReference()available, keep nesting to a maximum of five levels in a single Data Transform. If complexity grows beyond that, modularize into a separate called Data Transform — it keeps each rule under ~20 steps and much easier to debug.
Common Mistakes to Avoid
Mistake 1 — Treating the counter as a page
A frequent mistake is to confuse the counter with the page itself.
Param.pyForEachCount is just a number; you cannot set properties on it.
Incorrect:
Set Param.pyForEachCount.Status = "X"
Correct:
Set <CURRENT>.Status = "X"
Mistake 2 — Writing directly to Param.pyForEachCount
Param.pyForEachCount is a system-maintained value. The platform manages it
automatically throughout the loop — you should never attempt to override it manually.
Writing to it directly (for example, Set Param.pyForEachCount = 5) is unsupported
and produces unpredictable results. If you need a custom counter with different
starting or stepping logic, use a separate property (e.g., .MyCounter) and
manage it yourself with explicit Set actions.
Incorrect:
Set Param.pyForEachCount = 5
Correct — use a custom property instead:
Set .MyCounter = .MyCounter + 2
Summary
Param.pyForEachCountis your loop counter, starting at 1.- Use it to get the position of the current item in the list.
- Use
<CURRENT>to access the properties of the current item. - Combine them to update pages based on their position in a list (e.g., assigning
sequence numbers or display labels). - It is most commonly used in
Setactions andWhenconditions. - When calling nested rules inside the loop, enable “Pass current parameter page”
to makeParam.pyForEachCountavailable to the called rule automatically. - Never write to
Param.pyForEachCountdirectly — it is system-maintained and
read-only by design.
Conclusion
Param.pyForEachCount is one of Pega’s most practical built-in loop utilities, yet
it often goes undocumented in focused, standalone form.
Understanding it properly,especially the distinction from <CURRENT>, the nested-rule propagation behaviour, and the system-maintained constraint, helps developers write cleaner, more intentional Data Transform logic without unnecessary workarounds.
The examples in this article cover the most common real-world use cases and should serve as a reliable day-to-day reference for any Pega developer working with Page List iteration.
References
-
Pega Platform Documentation — Repeating steps in an activity
(primary source forpyForEachCountbehaviour and “Pass current parameter page”
option)
Pegasystems Documentation -
Pega Platform Documentation — Data Transform form: For Each Page In and Exit
For Each actions
(confirms availability in Data Transform loop types,<CURRENT>keyword behaviour,
and system-maintained parameter semantics)
Pegasystems Documentation