Skip to content

CEL Filtering

CEL (Common Expression Language) allows you to perform server-side filtering on event payloads. This significantly reduces bandwidth by only sending matching events to your client.

Basic Syntax

Browser (Singleton):

import { ironflow } from "@ironflow/browser";
await ironflow.subscribe("events:order.*", {
filter: 'data.total > 100.00',
onEvent: (e) => console.log("High-value order:", e.data),
});

Node.js (Instance):

import { createSubscriptionClient } from "@ironflow/node";
const subClient = createSubscriptionClient({
serverUrl: "http://localhost:9123",
apiKey: "...",
});
await subClient.connect();
await subClient.subscribe("events:payment.*", {
filter: 'data.status == "failed"',
onEvent: (e) => notifyOps(e.data),
});

String & Logic Operators

CEL supports standard string methods and logical operators for complex filtering.

  • Contains: data.email.contains("@company.com")
  • Regex: data.id.matches("^[0-9]+$")
  • Logic: data.priority == "high" && data.urgent == true
  • Lists: data.category in ["billing", "auth"]

Available Variables

VariableDescription
dataThe event payload (JSON object).
topicThe full event topic string.
nameAlias for topic — the full topic string, not the bare event name.
timestampThe event creation time.

Which of these the server actually fills depends on the delivery path, and an unfilled variable still compiles — it evaluates to an empty value, so a filter that reads one silently matches nothing rather than erroring. The one exception is timestamp, which falls back to evaluation time, not the event’s.

Delivery pathPopulated
WebSocket fan-out (Go SubscriptionClient)data, topic, name, timestamp
ConnectRPC fan-out (@ironflow/browser, @ironflow/node)data, topic
Consumer groupdata, topic

data and topic are the only two every path fills — write filters against those unless you are on the WebSocket path and know it.

CEL fields like event, metadata, source, and eventNamespace belong to the event-trigger matching path. They are declared in the pub/sub environment too, so they compile, but no pub/sub path populates them: metadata is an empty map, source and eventNamespace are empty strings, and event mirrors the activation above rather than the raw event envelope.

Performance

Because filtering happens before the event is serialized for the network, using CEL filters is highly recommended for high-throughput streams (like system.run.>).