Stop copy-pasting your data filter: build a reusable Kamelet in Kaoto

Sep 24, 2026·
Shivam
Shivam
· 9 min read
blog

What you’ll learn

  • Why the Content Filter pattern belongs in a reusable Kamelet, not copy-pasted route steps
  • How a multi-route Camel file makes the sensitive data leak obvious before you fix it
  • How to build a custom action Kamelet in Kaoto with an allowlist property
  • How each route configures its own allowlist in the step form — without duplicating filter logic

The problem: when your data filter lives in two places, it breaks in one

Imagine a shipping integration. Orders arrive with everything fulfillment needs: customer name, email, address, SKU, amount. Downstream you also feed analytics and an external partner (for example a carrier status API). Those consumers must not see personally identifiable information (PII) — things like a customer’s name, email address, or physical address.

Someone adds a few Camel steps on the analytics route to keep only safe fields. It works — until the partner export needs the same rule. Then someone pastes the steps again. Then a field is renamed (customer_name becomes first_name and last_name). Then one route is updated and the other isn’t. The “policy” was never a policy; it was a snippet.

That snippet is the Content Filter pattern: remove data from a message so the receiver only sees what it should. The filter is company policy. Policy is exactly what you want as a reusable building block.

Apache Camel already has that building block: Kamelets. Kaoto makes the last mile pleasant — create the Kamelet in the editor, save it into the workspace, and the tile shows up in the catalog so you can wire it into routes visually.

What we’re building

A four-route integration in one YAML file that fans an incoming order out to fulfillment, analytics, and a partner export:

RouteRoleShould see PII?
order-ingestCreates a sample order and fans outYes (source of truth)
order-fulfillmentWarehouse / ops — needs contact dataYes
order-analyticsInternal metrics — must not see PIINo
order-partner-exportCarrier / partner feed — must not see PIINo

The build goes in three steps:

  1. Start with all four routes without a filter (analytics and partner-export still log everything — the bug is visible).
  2. Build a custom content-filter-action Kamelet in Kaoto with one allowlist property.
  3. Place that Kamelet on analytics and partner-export, then set a different allowlist on each route.

Step 1: Four routes, one file (no filter yet)

Create orders.camel.yaml (or any *.camel.yaml file Kaoto recognises). Paste the YAML below as-is from the View YAML tab. Notice on the Image Preview tab that analytics and partner-export do not call a Kamelet yet — they log the full body, including PII.

Toggle Image
Expanded Image

What you should see when it runs (before the fix)

Fulfillment correctly has identity fields, Analytics and partner-export incorrectly have the same full payload:

Toggle Image
Expanded Image

That’s the teachable moment: two different consumers (metrics vs partner API), one shared mistake — no Content Filter yet.

Step 2: Build the custom Content Filter Kamelet in Kaoto

You’re not going to paste a hard-coded allowlist into every route, and you’re not going to clone setBody JSON on each route either. Instead, you’ll create the Kamelet once in Kaoto:

  1. Create a new Kamelet by clicking on New File in Kaoto view(perspective) integrations nav bar, set the name to content-filter-action and the type to action — not source (which produces messages) or sink (which consumes them), but action, because this Kamelet sits between existing steps in a route and transforms the message in place.
  2. Add a single property: allowlist (string) — one control that each route will configure independently.
  3. Give it a sensible default: the company baseline of safe shipping fields (no customer identity).
  4. On the Kamelet canvas, wire kamelet:source → unmarshal JSON → setBody to keep only the fields named in {{allowlist}} → marshal JSON.
  5. Save the Kamelet into the workspace (for example content-filter-action.kamelet.yaml). No IDE restart needed.

Reference YAML

Use this as a check against Source Code view after building in Kaoto — or paste the code from the YAML Source directly if you’re skipping the visual designer:

Toggle Image
Expanded Image

Save if you edited source. Workspace Kamelets are picked up automatically when Kaoto refreshes the catalog tiles.

Alternative: one boolean property per field

If you’d rather give teams explicit toggles in the form (one checkbox per field), define properties such as includeOrderId, includeAmount, … (type: boolean, defaults true) and branch in Groovy with if ({{includeOrderId}}) out.put('order_id', src['order_id']).

That approach makes it harder to accidentally request a PII field by typo, but it needs heavier logic to process all seven boolean properties. For this post we stick with a single allowlist string.

Step 3: Wire the policy into your routes

This is the step that turns a Camel feature into a team practice.

Open the integration in Kaoto

Open orders.camel.yaml in VS Code with the Kaoto extension. You should see all four routes on the canvas.

Find the Kamelet in the catalog — no catalog rebuild needed

  1. Confirm content-filter-action.kamelet.yaml is saved in the workspace.
  2. On the order-analytics route, open the catalog (add step before the log).
  3. Switch to the Kamelets tab and search for content-filter or Content Filter.
Catalog modal with content filter tile

Content Filter Kamelet tile on the catalog modal

Expected: The tile appears without regenerating a Camel catalog archive. Workspace Kamelets are merged in automatically when Kaoto refreshes its catalog tiles.

Apply it where PII must not leave

Fulfillment stays as a plain log step — ops still need contact data.

Analytics and partner-export each get the same Kamelet tile inserted before their log step. The difference is the allowlist value you set on each:

  1. Insert Content Filter on order-analytics.
  2. Open the step’s configuration form — you’ll see a single Fields to keep / allowlist control.
  3. Leave analytics on the default (full safe set), or edit the comma-separated list as needed.
  4. Insert Content Filter on order-partner-export.
  5. On that step’s form, set a narrower allowlist — for example, drop amount and shipping_priority.

You’re editing the allowlist per route usage, through the Kamelet parameter — not by duplicating filter YAML into each route.

After wiring, the source looks like this:

- route:
    id: order-analytics
    description: Analytics
    from:
      uri: direct:analytics
      steps:
        - to:
            uri: kamelet:content-filter-action
            id: to-4189
        - log:
            loggingLevel: INFO
            message: "ANALYTICS: ${body}"
- route:
    id: order-partner-export
    description: Partner
    from:
      uri: direct:partner-export
      steps:
        - to:
            uri: kamelet:content-filter-action
            id: content-filter-kamelet-on-order-partner-export
            parameters:
              allowlist: order_id,item_sku,quantity,destination_country,status
        - log:
            loggingLevel: INFO
            message: "PARTNER-EXPORT: ${body}"

Same tile, two allowlist values. Fulfillment still has no filter.

Config form of content filter node on order-partner-export

Config form (Modified tab) of the Content Filter node on the order-partner-export route

What you should see after the fix

Toggle Image
Expanded Image

Partner-export has no amount or shipping_priority — configured on that step only. The analytics route uses the same Kamelet but with a different allowlist configured.

Two ways to change policy

ChangeWhereEffect
Per-route allowlistKaoto form / parameters.allowlist on that to: kamelet:... stepOnly that consumer’s field set changes
Baseline defaultKamelet definition properties.allowlist.defaultWhat every new usage starts with before you edit the form

To change what one consumer receives, edit that step’s allowlist in Kaoto. To change the starting default for all new usages, update the property default in the Kamelet editor, save, and re-open the step form.

Takeaways

  1. Show the leak first — a multi-route file makes it obvious that analytics and partner-export share the same problem.
  2. Build the Content Filter as a Kamelet of type action — actions sit mid-route and transform the message, which is exactly what a filter does. One template, many call sites, zero duplication.
  3. Kaoto closes the loop — save the Kamelet → catalog tile appears → drop it onto routes → edit each allowlist in the form.
  4. Keep PII out of allowlists by convention — the property description and code review are your guardrails.

The same approach works beyond data filtering. Anywhere you catch yourself copy-pasting the same transformation, enrichment, or validation logic across routes — currency conversion, audit stamping, schema validation, payload size trimming — a custom action Kamelet is the right fix. Define the logic once, expose the variable parts as properties, and let each route configure its own values through the Kaoto form.

Further reading

Let’s build it together

Let us know what you think by joining us in the GitHub discussions. Do you have an idea for improving Kaoto’s Kamelet support? Would you love to see a useful feature implemented or simply ask a question? Please create an issue.

Give it a try

Happy integrating! 🚀