Topic Filters

Filters let you narrow message delivery to specific entities within a topic. Instead of receiving all updates, subscribe with filters and only get the messages you care about.

Why Filters?

Without filters, subscribing to a topic delivers every message published to it. For a dashboard showing 3 bookings out of thousands, this means receiving updates for all bookings and discarding most of them client-side.

Filters solve this at the infrastructure level. Subscribe to bookings with filters ["booking_1", "booking_2"] and only updates for those two bookings are delivered. When the user navigates to different bookings, swap filters dynamically, no resubscribe needed.

How It Works

Each filter value becomes a separate subscription at the infrastructure level, so filtering happens before messages reach your client, not by inspecting message payloads. This means zero wasted bandwidth.

No filters (wildcard, receives everything on the topic):
subscribe("bookings")
With filter, only receives matching updates:
subscribe("bookings", { filters: ["booking_1"] })
Publish targeting filtered subscribers:
publish("bookings", data, { filter: "booking_1" })
Publish without filter:
publish("bookings", data) // only wildcard subscribers receive this

Subscribe with Filters

Pass a filters array when subscribing to a topic:

import { NoLag } from '@nolag/js-sdk'

const client = NoLag('your_access_token')
await client.connect()

const room = client.setApp('dashboard').setRoom('ops')

// Subscribe with filters: only receive updates for these bookings
room.subscribe('bookings', {
  filters: ['booking_1', 'booking_2']
})

// Listen for messages (only matching filters arrive)
room.on('bookings', (data, meta) => {
  console.log('Booking update:', data)
  console.log('Filter:', meta.filter)  // e.g. 'booking_1'
})

Dynamic Filter Management

Change filters at any time without unsubscribing and resubscribing. New filters are subscribed before old ones are removed to minimize message gaps.

// Replace all filters (full swap)
room.setFilters('bookings', ['booking_3', 'booking_4'])

// Add filters to existing set
room.addFilters('bookings', ['booking_5'])
// Now active: ['booking_3', 'booking_4', 'booking_5']

// Remove specific filters
room.removeFilters('bookings', ['booking_3'])
// Now active: ['booking_4', 'booking_5']

// Remove all filters (switch to wildcard, receives everything)
room.setFilters('bookings', [])

Publishing with Filters

Specify a filter when publishing to target specific subscribers:

// Publish to a specific filter
room.emit('bookings', { status: 'confirmed' }, {
  filter: 'booking_1'
})
// Only subscribers with 'booking_1' in their filters receive this

// Publish without a filter
room.emit('bookings', { type: 'system_update' })
// Only wildcard subscribers (no filters) receive this
// Filtered subscribers do NOT receive filterless publishes
Important: Messages published without a filter are only delivered to wildcard (no-filter) subscribers. Filtered subscribers do NOT receive filterless publishes. Use a separate topic for broadcasts if needed.

Example: Real-time Dashboard

The most common use case for filters is dashboards where users view a subset of entities that update in real-time:

// Real-time dashboard: user views 3 bookings out of thousands
const room = client.setApp('dashboard').setRoom('ops')

// Subscribe only to the bookings currently visible
const visibleBookingIds = ['booking_42', 'booking_87', 'booking_153']
room.subscribe('bookings', {
  filters: visibleBookingIds
})

room.on('bookings', (data, meta) => {
  updateBookingCard(meta.filter, data)
})

// User navigates to a different page of bookings
function onPageChange(newBookingIds: string[]) {
  room.setFilters('bookings', newBookingIds)
}

// User opens a booking detail view, add it to filters
function onBookingOpen(bookingId: string) {
  room.addFilters('bookings', [bookingId])
}

// User closes a booking detail view, remove it
function onBookingClose(bookingId: string) {
  room.removeFilters('bookings', [bookingId])
}

Filter Rules

  • Max 100 filters per topic per connection
  • Filter values must not contain /, #, or + (reserved characters)
  • Filters are persisted, on reconnect, your filters are automatically restored
  • Filters work with load balancing, each filter topic uses the shared subscription group
  • Setting filters to an empty array switches back to wildcard mode (receives everything)

Filters vs Wildcards

ScenarioApproach
Receive all messages on a topicSubscribe without filters (wildcard)
Receive updates for specific entitiesSubscribe with filters
Change which entities to tracksetFilters / addFilters / removeFilters
Broadcast to all subscribersUse a separate topic (filtered subscribers won't receive filterless publishes)

Next Steps