How to Order Transformations and Filters
Controlling the execution order of Transformation and Filter rules within a Connection is a powerful way to manage your event flow. It allows you to build more efficient, clean, and flexible event processing logic.
By default, transformations ran before filters, but you can decide the order that best suits your use case. This guide explains why the order matters and provides practical examples for the two primary scenarios.
Why the Order of Transformations and Filters Matters
The ability to control whether a transformation runs before or after a filter gives you more granular control over your event processing pipeline. This helps you:
- Avoid Unnecessary Processing: Prevent transformations from running on events that will be discarded by a filter anyway.
- Simplify Transformation Logic: Write cleaner transformation scripts that don't need to handle events they aren't designed for.
- Use and Remove Filter-Only Data: Remove temporary headers or body fields that are only needed for filtering.
Use Case 1: Transformations After Filters
This is the most common scenario for optimizing your event flow. By placing the filter first, you ensure that the transformation logic only executes on events that you actually intend to process and deliver.
When to use this approach:
- When you want to filter events based on the original, unmodified payload.
- To improve efficiency by not wasting resources transforming events that will be dropped.
- To clean up data that was only needed for filtering.
Example: Efficiently Processing Specific Event Types
Imagine you are receiving webhooks from Stripe, but you only care about invoice.updated
events. You can set up a filter to match these events and then run a transformation on them.
Step 1: Create a Filter
First, create a Filter rule that only allows events with the type invoice.updated
to pass through.
{
"type": "invoice.updated"
}
Step 2: Create a Transformation
Next, add a Transformation rule after the filter. This transformation script can now safely assume it will only ever receive invoice.updated
events.
addHandler("transform", (request, context) => {
// This logic only runs for "invoice.updated" events
request.body.transformed = true;
// ...perform more specific logic on the invoice payload
return request;
});
Example: Removing Filter-Only Metadata
Sometimes you might add a custom header for internal routing or filtering purposes. With the transformation running after the filter, you can use the header for filtering and then strip it out before it reaches your destination.
Filter (Header): A filter rule could check for the presence or value of x-internal-data
.
Transformation (after filter):
addHandler("transform", (request, context) => {
// The event has already been filtered based on the header
// Now we can safely remove it
delete request.headers["x-internal-data"];
return request;
});
Use Case 2: Transformations Before Filters
There are still important use cases where you need to modify an event before the filter logic is applied.
When to use this approach:
- When you need to normalize disparate data structures from multiple sources into a consistent format for filtering.
- When you want to compute a derived value to simplify complex filter conditions.
Example: Normalizing Payloads for Consistent Filtering
If you receive webhooks from two different providers that use different field names for the same concept (e.g., event_type
vs. type
), you can use a transformation to standardize them first.
Step 1: Create a Transformation
This script checks for event_type
and maps it to type
.
addHandler("transform", (request, context) => {
if (request.body.event_type) {
request.body.type = request.body.event_type;
}
return request;
});
Step 2: Create a Filter
Now, your filter rule can reliably check the type
field, regardless of the original source.
{
"type": "some.event"
}
Example: Computing Derived Values for Simpler Filters
You can use a transformation to perform complex logic and add a boolean flag to the payload, making the subsequent filter much simpler.
Step 1: Create a Transformation
This script checks the event's status and adds a should_alert
field.
addHandler("transform", (request, context) => {
const status = request.body.status;
request.body.should_alert = status === "failed" || status === "timeout";
return request;
});
Step 2: Create a Filter
The filter logic is now a simple boolean check.
{
"should_alert": true
}
This approach keeps your filter rules declarative and your transformation logic encapsulated.
How to Reorder Rules
You can change the order of rules in the Hookdeck Dashboard by dragging and dropping them into the desired sequence.
You can also manage the order via the connections API endpoint by updating the rules[]
array in a connection.
Related Hookdeck Features & Documentation
Powerful Payload Transformations ->
Deep dive into writing transformation scripts.
Conditionally Filtering Events ->
Learn how to create filter rules.
Understanding Connections ->
The link between Sources and Destinations.