Triggers play an essential role in Power Automate since we could not even start the Flows without them. Triggers can have information that could be useful in the Flow, like the details of the item that was created in Forms or the message that was published in Teams, for example. But how do we access the values of the trigger in the Flow? You can select them in the "Dynamic content" tab, but what if you need them in a formula, for example? Here's where the "triggerBody" function comes into play.
Please note that you can use the "triggerBody" with any trigger. I'm going to use the "Manually Trigger a Flow" trigger as an example but the concepts are completely transversal to any other trigger.
Let's explore how to use it.
Usage
It follows a simple pattern, and no parameters are required:
triggerBody()
It will return the list of items provided when the Flow was triggered. The return is in JSON format. In case you're not familiar with JSON, no worries; I have a general overview of what you should know here.
Here's a simple trigger and "Compose" action to show what was provided.
Let's provide some data and run it.
Here's the result.
We'll get the following:
{
"text": "Manuel Gomes",
"boolean": false,
"number": 41,
"email": "manuel@manueltgomes.com"
}
As mentioned before, we'll get a JSON object. Notice also that the field names you set in the trigger (Name, Age, etc.) are not the keys you use to reference them. There's no official mention from Microsoft on why this was done like this, but I would guess it was because the fields may contain special characters, and it would make the JSON complex or fail depending on the special character.
How to access the information?
Since it's a JSON, we can access it by doing the following:
- Call the function
- Indicate the field that we want to get the data using the square brackets and key.
For example, if we want to get the text that was typed, we'll do the following:
triggerBody()?['text']
We'll get:
Why the question mark before the brackets?
You'll notice that I write triggerBody()?['text'] and not triggerBody()['text']. That question mark is what Microsoft calls the "null ignore" operator, and it's the documented way to reach a property that might not be there. Plain square brackets are strict, so a key that is missing stops the run with the "Unable to process template language expressions" error. With the question mark, the same expression quietly returns null and we get to decide what happens next.
If you'd rather have a fallback than a null, wrap it in the "coalesce" function:
coalesce(triggerBody()?['text'], 'No value provided')
I would get into the habit of always adding it. It costs one character and saves a lot of failed runs.
How do I know the keys to get the data?
If you add multiple options in the trigger and run the Flow, you'll see Microsoft's convention. The key is the type of the field plus a number in case there are multiple of the same type.
[type]_[number]
For example:
triggerBody()?['text']
triggerBody()?['number_1']
To be sure that you're using the correct keys, you can follow the next section's steps and pick them from the "Dynamic content" or have a "Compose" action at the start of the Flow, run it once and see which values the action gives you, like this.
The result will provide you with the certainty of the value to call.
You're using it without knowing
Please note that, if you select the items from the "Dynamic content" list, Power Automate will use this function for you. Here's an example.
As you can see, when we hover the mouse, the value that you selected is the same as above, or:
triggerBody()['text']
Notice that the designer writes the plain brackets without the question mark. It's building the expression for you, so it assumes the value will be there. If that field can ever arrive empty, add the question mark yourself and make it triggerBody()?['text'], for the reasons we saw above.
Non-intuitive behaviors
It's a shortcut, not a separate source of data
Microsoft documents "triggerBody" as shorthand for trigger().outputs.body, so it isn't fetching anything the trigger didn't already hand over. That matters when the value you want simply isn't in the body, because no amount of guessing at keys will find it. In that case, step up one level with the "triggerOutputs" or "trigger" functions, which return the trigger's full output instead of only the body.
triggerBody()
trigger().outputs.body
The "When an HTTP request is received" trigger is the clearest example. Its documented output has exactly two properties, headers and body, so "triggerBody" hands you the payload and nothing else. If you need a header, you have to go one level up.
triggerOutputs()?['headers']?['Content-Type']
The "body/" prefix belongs to triggerOutputs, not triggerBody
Connectors flatten their outputs, which is why Microsoft's own Dataverse examples use keys like body/SdkMessage. That slash is part of the key when you start from "triggerOutputs". Start from "triggerBody" and you're already inside the body, so the prefix has to go.
triggerOutputs()?['body/Title']
triggerBody()?['Title']
Copying a key straight out of the trigger outputs and pasting it after "triggerBody" is one of the easiest ways to get a null back for no obvious reason.
With "split on", you get one item and not the whole payload
If your trigger returns an array and you turn on "split on" (also called debatching), Power Automate creates a separate run for each item in that array. Inside each of those runs, "triggerBody" returns just that one item, not the original payload. Microsoft also points out that once "split on" is in play, you can't reach properties that live outside the array, so anything sitting at the top level of the original response is out of reach.
Expressions written against the full payload will stop resolving the moment you switch debatching on, and they fail at runtime rather than when you save. If you turn it on, walk back through every "triggerBody" expression in the Flow.
Limitations
8,192 characters per expression
Depending on the size of your string, your expression may return an error, even if it's correct. Please note that the expressions have a max size of 8,192 characters. If you have an expression that is even longer than 1,000 characters, I would strongly advise that you break it into smaller, manageable formulas.
Since we don't have any parameters in this function, you'll only run into this limitation in case you're integrating the "triggerBody" function in other expressions.
The evaluated result has its own ceiling
There's a second, much larger limit of 131,072 characters on what an expression can evaluate to, and Microsoft calls it out for the "concat", "base64", and "string" functions. "triggerBody" on its own will never get you there, but pushing a big trigger body through one of those three can, so it's worth knowing the number exists.
Troubleshooting Common Errors
Unable to process template language expressions. The provided value is of type 'Null'
Cause: The expression reached for a property on something that came back null. That happens when the key isn't in the body, when the trigger fired without a body at all, or when a connector left an optional field out of the payload.
Solution: Add the question mark operator so the missing property returns null instead of stopping the run, and pair it with the "coalesce" function when the rest of the Flow needs a real value to work with.
coalesce(triggerBody()?['text'], '')
ExpressionEvaluationFailed
Cause: Microsoft separates the two moments an expression can break. A mistake in the expression itself is caught when you save the Flow and shows up as "InvalidTemplate". An expression that is written correctly but meets data it didn't expect, such as a trigger body without the key you asked for, only fails once the Flow runs, and that one is "ExpressionEvaluationFailed".
Solution: Open the failed run, look at the trigger outputs to see what actually arrived, then guard the expression so an empty value has somewhere to go.
if(empty(triggerBody()?['value']), 'default', triggerBody()?['value'])
Recommendations
Here are some things to keep in mind.
Use "debug" compose actions
As I mentioned above, I would keep a "Compose" action at the beginning of the Flow to ensure that I have the values returned at the start. This way, if something goes wrong with the Flow, I can check whether the values I got from the beginning are correct. If not, it will remove a lot of uncertainty since I know that the error is either inside the Flow or with the values returned.
Pick from the list
As I mentioned before, you're probably always picking the values from the "Dynamic content" list to ensure you're always using the correct value. Please note that you can do this even if you're writing an expression like this:
It's the same result and will remove many mistakes and issues.
Final Thoughts
The "triggerBody" function is one of those small building blocks that you end up using in almost every Flow, often without noticing. Get comfortable with the keys, keep a "Compose" action around while you build, and reaching into your trigger data stops being guesswork.
Sources
- Reference for functions in workflow expressions, Azure Logic Apps and Power Automate
- Workflow Definition Language schema reference, for the question mark (null ignore) operator
- Workflow triggers and actions, for "split on" debatching
- Limits of automated, scheduled, and instant flows
- Cloud flow error code reference
- Getting errors with null fields
- Receive and respond to inbound HTTPS calls
- Trigger flows when a row is added, modified, or deleted
- Power Automate expression cookbook
Back to the Power Automate Function Reference
Photo by MIOPS Trigger on Unsplash
No comments yet
Be the first to share your thoughts on this article!