- Publishing & Subscribing
- CEL Filtering
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),});sub, _ := subClient.Subscribe(ctx, "events:order.*", &ironflow.SubscribeOptions{ Filter: `data.status == "completed"`,})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
| Variable | Description |
|---|---|
data | The event payload (JSON object). |
topic | The full event topic string. |
name | Alias for topic — the full topic string, not the bare event name. |
timestamp | The 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 path | Populated |
|---|---|
WebSocket fan-out (Go SubscriptionClient) | data, topic, name, timestamp |
ConnectRPC fan-out (@ironflow/browser, @ironflow/node) | data, topic |
| Consumer group | data, 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.>).