Using Waku’s Content‑Topic Bloom Filters to Cut Unwanted Traffic
Learn how Waku’s content‑topic bloom filters let lightweight clients subscribe only to the topics they need, reducing bandwidth with a predictable false‑positive rate.
05 Mar 2026, 04:50 UTC

Problem: Receiving every message wastes bandwidth
When a decentralized chat or IoT app runs on Waku, each node subscribes to the pubsub router and, by default, receives all messages broadcast on the network. For lightweight clients this can quickly exhaust mobile data plans or saturate a constrained link, especially as the number of unrelated topics grows.
Thesis: Waku’s filter protocol lets you tell the network which content topics you care about, using a fixed‑size bloom filter so relays forward only matching messages.
How the filter protocol works
Waku v2 defines the /waku/2/rs/0.x libp2p protocol. Each peer advertises a filter vector – a 256‑bit bloom filter – that encodes the hash of the content topics it wants. Relays keep the union of all vectors they have seen; when a message arrives, they test the message’s topic hash against the union. If the test passes, the message is forwarded; otherwise it is dropped. The protocol includes a periodic re‑advertisement so that changes in subscriptions propagate through the mesh.
Configuring a node to use filters
Start the official Go wakunode with the --filter flag. The node will automatically participate in the filter vector exchange.
# Run as a regular user; no root privileges needed.
wakunode \
--listen-address /ip4/0.0.0.0/tcp/30303 \
--filter \
--discv5 \
--nat=any \
--datadir ./waku-data
Where to run: any machine with Go 1.22+ and the wakunode binary in $PATH. Permissions: read/write access to the chosen datadir. Risk: enabling the filter adds a small CPU cost for bloom‑filter checks; if the filter is too small you may see false‑positive traffic.
Worked example: a chat app subscribing to chat/app1
Determine the bit position for the topic. In the reference implementation the hash of
chat/app1maps to bit 57 (0‑indexed).Set that bit in your local filter. Most clients expose a helper; pseudo‑code:
filter := NewBloomFilter(256) filter.SetBit(57) // chat/app1 SetLocalFilter(filter) // wakunode RPC or configPublish the updated filter to peers. The node does this automatically; you can see the vector on the libp2p pubsub topic
/waku/2/rs/0.x/filterusing a libp2p inspector.When a peer publishes a message with content topic
chat/app1, the relay’s union filter will have bit 57 set, the test passes, and you receive the message. Messages for other topics (e.g.,sensor/temp) will most often be dropped.
Trade‑offs and limitations
- False positives: a 256‑bit bloom filter yields roughly a 1 % false‑positive rate for typical topic sets. This means you may still receive about 1 % of irrelevant messages. Increase the filter size (e.g., 512 bits) to lower the rate at the cost of larger vector messages.
- Propagation delay: filter updates are gossiped every few seconds. A new subscription can take up to that interval to be recognized by all relays, leading to temporary message loss if you rely on immediate delivery.
- Stateful: enabling the filter changes the node’s behavior; disabling it (
--filterremoved) returns to the default “receive all” mode.
Actionable closing
To verify that the filter is working:
- Start two wakunode instances, A and B, both with
--filterenabled. - On node A, set the bit for
chat/app1as shown above. - From node B, publish a test message to
chat/app1usingwakucli publish --topic chat/app1 --payload hello. - Check node A’s logs; you should see the message received.
- Clear the bit on node A, repeat the publish, and confirm that node A no longer logs the message.
If you observe extra traffic, consider increasing the filter size or accepting the modest false‑positive trade‑off. With these steps you can cut unnecessary bandwidth while staying compatible with the Waku v2 mesh.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.