Return a small JSON array as a text output from Power Automate, then use ParseJSON and ForAll in Power Apps to create a typed collection. Define the response shape yourself. Do not send an action's complete connector response and hope the app understands its wrapper and metadata.
The response contract
This example returns site options with two text fields:
[
{
"siteName": "London",
"siteCode": "LDN"
},
{
"siteName": "Bristol",
"siteCode": "BRS"
}
]
Stable JSON keys without spaces make the Power Fx easier to read. Keep the payload small and exclude columns the app does not use.
Build the flow
- Create an instant cloud flow using the Power Apps (V2) trigger.
- Add the required text input, such as
employeeId. - Query the source using a supported filter where possible.
- Use a Select action to map each result to
siteNameandsiteCode. - Add Respond to a Power App or flow.
- Create a text output named
resultJsonwith this expression:
string(body('Select'))
The action name in your flow may differ. Pick it from dynamic content or adjust the expression to its internal name.
The flow's connection identity controls what data it can read. If the flow uses an owner connection, validate the caller and filter the response. Do not turn the flow into a general data-extraction endpoint.
Parse the response in Power Apps
After adding the flow to the canvas app, call it and keep the raw response while debugging:
Set(varSiteResponse, GetSites.Run(txtEmployeeId.Text));
ClearCollect(
colSites,
ForAll(
ParseJSON(varSiteResponse.resultJson),
{
SiteName: Text(ThisRecord.siteName),
SiteCode: Text(ThisRecord.siteCode)
}
)
)
Without a second type argument, ParseJSON returns dynamic values. Explicit Text, Value, Boolean, DateValue or other conversion makes the resulting collection predictable.
Power Fx also supports a typed second argument for ParseJSON. Use it only when the app's formula version and required types are confirmed. The explicit mapping above remains useful when you want to rename fields or provide defaults.
Handle blank and failed responses
Do not equate flow failure with an empty array. Wrap the call and validate the returned text:
IfError(
Set(varSiteResponse, GetSites.Run(txtEmployeeId.Text));
If(
IsBlank(varSiteResponse.resultJson),
Notify("The flow returned no response.", NotificationType.Error),
ClearCollect(
colSites,
ForAll(
ParseJSON(varSiteResponse.resultJson),
{
SiteName: Text(ThisRecord.siteName),
SiteCode: Text(ThisRecord.siteCode)
}
)
)
),
Notify("The site list could not be loaded.", NotificationType.Error)
)
An empty valid array is [], not blank. Decide whether that means "no authorised sites" or an upstream data problem.
Delegation and scale
Moving data through a flow does not magically make an inefficient query safe. Filter at the source and return only the required rows. Power Automate actions have their own pagination, throttling and connector limits, while Power Apps collections are held locally.
If the app needs to search a large live table, use a delegable direct connector or a purpose-built API instead of downloading the table into a collection.
Test the contract
Test one row, no rows, null fields, unexpected characters, denied access, an expired connection, malformed JSON and a flow timeout. Keep a sample response in development documentation, but remove real personal data.
For help designing the smallest reliable app-flow contract, join the Power Apps Builders Space.
