How to use Param.pyForEachCount in Pega Data Transforms

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.

:memo: 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.pyForEachCount is 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.pyForEachCount answers: “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.OuterPageRef captures the string path of the current order line — for example, pyWorkPage.OrderLines(2).
  • Inside the inner loop, <CURRENT> now refers to each LineItem. The outer order line is no longer reachable via <CURRENT> or <PARENT>.
  • But Param.OuterPageRef.TotalQty still resolves correctly — Pega treats the stored string path as a live clipboard reference, so writing to Param.OuterPageRef.TotalQty writes directly to pyWorkPage.OrderLines(2).TotalQty.

Common Mistake to Avoid

:cross_mark: 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.

:white_check_mark: 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> :cross_mark: Not needed — use <CURRENT> directly
Two-level nesting — need to update the outer item from the inner loop :white_check_mark: Yes — capture with Param.OuterPageRef before inner loop
Passing the current page’s path to a called sub-Data Transform :white_check_mark: Yes — pass @pxGetStepPageReference() as a parameter
Evaluating a When rule that lives on the outer page’s class :white_check_mark: Yes — use the stored reference for context switching
Nesting deeper than two levels :white_check_mark: Yes — capture at each level before going deeper

:light_bulb: 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.

:cross_mark: Incorrect:
Set Param.pyForEachCount.Status = "X"

:white_check_mark: 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.

:cross_mark: Incorrect:
Set Param.pyForEachCount = 5

:white_check_mark: Correct — use a custom property instead:
Set .MyCounter = .MyCounter + 2


Summary

  • Param.pyForEachCount is 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 Set actions and When conditions.
  • When calling nested rules inside the loop, enable “Pass current parameter page”
    to make Param.pyForEachCount available to the called rule automatically.
  • Never write to Param.pyForEachCount directly — 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

  1. Pega Platform Documentation — Repeating steps in an activity
    (primary source for pyForEachCount behaviour and “Pass current parameter page”
    option)
    Pegasystems Documentation

  2. 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

Appreciate your patience to compile a very good article @LeandroTaveira. This is a very detailed and important information for people who are working on complex logic in data transforms involving pagelists.

Additionally, want to mention about the pxGetStepPageReference() and getStepPageName() OOTB functions to get the current/step page reference or just the page name respectively in DT’s or activities so that the page context can be moved around multiple rules in accordance with parameters of type Page Name.

Regards

JC

@JayachandraSiddipeta
Thanks for your comment. I’ve updated the article and added @pxGetStepPageReference() to make that part clearer and more complete.

Regarding getStepPageName(), that method is more specific to the Activity/Java context, so including it here would broaden the scope of the article beyond what I originally intended. That said, it is a valuable point and could definitely deserve its own coverage in a separate article focused on Activity and Java usage.

I appreciate you bringing it up — I’ll keep it in mind for a future write-up.