On this page

Subscribe Filters

PubNub's subscribe filters provide comprehensive server-side message filtering capabilities. You can route messages based on payload content, metadata, and complex business logic.

Filters are applied before messages reach your client, reducing bandwidth and improving application performance.

Filtering App Context data

You can filter App Context data (users, channels, memberships) using App Context Filtering.

Overview

Subscribe filters use a powerful expression language to evaluate messages against your criteria. Only messages that match your filter expressions are delivered to your subscribers. Non-matching messages are filtered out server-side.

Core benefits:

  • Real-time personalization - Each subscriber receives only relevant messages based on their preferences, location, permissions, or context without requiring separate channels
  • Dynamic multi-tenancy - Single channel serves multiple user segments with different filtering rules, enabling scalable SaaS architectures without channel proliferation
  • Intelligent event routing - Route messages based on complex business logic combining user roles, content types, geographic boundaries, and priority levels in real-time
  • Scalable sampling & analytics - Filter high-volume data streams for analytics, monitoring, and sampling without overwhelming downstream systems or clients

Filter expression fundamentals

Use filters against two data sources: message payload (data.*) and message metadata (meta.*).

Data access

Subscribe filters can access two main data sources within each message:

PrefixData SourceExample FieldsAccess Pattern
data.*
Message payload
data.text, data.type, data.score
Any field in published message content
meta.*
Message metadata
meta.priority, meta.region, meta.level
Metadata attached via meta parameter when publishing

Supported operators

CategoryOperatorsDescriptionExamples
Comparison
==, !=, >, <, >=, <=
Standard comparisons
meta.level > 5, data.score >= 80
Pattern
LIKE, CONTAINS
Wildcard and substring matching
meta.category LIKE "news*", data.text CONTAINS "urgent"
Logical
&&, ||, !
Boolean logic operators
(meta.priority == "high") && (data.type == "alert")
Arithmetic
+, -, *, /, %
Mathematical operations
meta.userId % 10 == 0, data.score > (meta.threshold + 5)
Access
[index], ["key"]
Array and object access
meta.tags[0] == "urgent", meta.user["role"] == "admin"

Basic filtering

Use simple expressions to match fields in data.* or meta.*; start with strings, then numbers.

String filtering

1// Exact string matching
2pubnub.setFilterExpression('meta.priority == "high"');
3pubnub.setFilterExpression('data.category != "test"');
4
5// Multiple string conditions
6pubnub.setFilterExpression('meta.region == "San Francisco" && data.type == "alert"');

Numeric filtering

1// Numeric comparisons
2pubnub.setFilterExpression('meta.level > 10');
3pubnub.setFilterExpression('data.score >= 80');
4pubnub.setFilterExpression('meta.priority <= 3');
5
6// Range filtering
7pubnub.setFilterExpression('meta.score >= 80 && meta.score <= 100');
8
9// Calculated thresholds
10pubnub.setFilterExpression('data.usage > (data.limit * 0.8)');

Pattern matching

Use LIKE for wildcard matches and CONTAINS for substring searches on fields in data.* and meta.*.

LIKE operator (wildcard matching)

The LIKE operator provides powerful pattern matching with wildcard support.

Wildcard rules include:

  • Use * for wildcard matching
  • * can be at start, end, or both: "*middle*", "prefix*", "*suffix"
  • Escape literal asterisks with backslash: "literal\*"
  • Pattern matching is case-insensitive
1// Wildcard patterns
2pubnub.setFilterExpression('meta.category LIKE "news*"'); // Starts with "news"
3pubnub.setFilterExpression('data.title LIKE "*breaking*"'); // Contains "breaking"
4pubnub.setFilterExpression('meta.version LIKE "2.1*"'); // Version prefix
5
6// Complex pattern combinations
7pubnub.setFilterExpression('data.subject LIKE "*[URGENT]*" && data.body CONTAINS "maintenance"');
1// Substring search
2pubnub.setFilterExpression('meta.tags CONTAINS "urgent"');
3pubnub.setFilterExpression('data.description CONTAINS "error"');
4
5// Multiple substring conditions
6pubnub.setFilterExpression('data.text CONTAINS "urgent" && meta.category CONTAINS "alert"');

Advanced filtering

Use these patterns to access arrays and objects, perform arithmetic, and handle booleans in subscribe filter expressions.

Array and object access

Subscribe filters support direct access to array elements and object properties within both payload and metadata.

1// Array element access
2pubnub.setFilterExpression('meta.tags[0] == "urgent"'); // First element
3pubnub.setFilterExpression('data.recipients[1] LIKE "*@company.com"'); // Second element
4
5// Object property access
6pubnub.setFilterExpression('meta.user["role"] == "admin"'); // Object key access
7pubnub.setFilterExpression('data.config["enabled"] == "true"'); // Nested object
8
9// Combined array and object access
10pubnub.setFilterExpression('meta.permissions[0] == "read" && data.user["department"] == "engineering"');
Single-level access only

Array and object access supports one level of indexing (meta.array[0], meta.object["key"]). Multi-level chained access (meta.data["array"][0]) is not supported.

Arithmetic operations

1// Modulo operations for sampling
2pubnub.setFilterExpression('meta.userId % 10 == 0'); // 10% sampling
3pubnub.setFilterExpression('meta.messageId % 100 == 0'); // 1% sampling
4
5// Arithmetic calculations in filters
6pubnub.setFilterExpression('data.score > (meta.baseline + 10)');
7pubnub.setFilterExpression('meta.attempts < (meta.maxRetries - 1)');
8
9// Complex arithmetic expressions
10pubnub.setFilterExpression('(data.total - data.used) > (data.limit * 0.2)');

Boolean value handling

1// Boolean values as strings (recommended approach)
2pubnub.setFilterExpression('meta.enabled == "true"');
3pubnub.setFilterExpression('meta.active == "false"');
4pubnub.setFilterExpression('meta.verified != "false"');
5
6// Numeric boolean flags (alternative)
7pubnub.setFilterExpression('meta.isActive == 1'); // 1 for true
8pubnub.setFilterExpression('meta.isDisabled == 0'); // 0 for false
Boolean literal limitation

Use string comparison ("true"/"false") or numeric flags (1/0) in filter expressions. The filtering system treats JSON boolean values as strings.

Complex expressions

Build complex filters by combining conditions (AND/OR), nesting expressions, and using parentheses for clarity.

Compound logic

1// AND expressions
2pubnub.setFilterExpression('(meta.priority == "high") && (data.type == "alert")');
3pubnub.setFilterExpression('meta.level > 5 && meta.region == "San Francisco"');
4
5// OR expressions
6pubnub.setFilterExpression('(meta.priority == "high") || (meta.priority == "critical")');
7pubnub.setFilterExpression('data.category == "news" || data.category == "sports"');
8
9// Nested logical expressions
10pubnub.setFilterExpression('((meta.priority == "high") || (meta.priority == "critical")) && (data.score > 80)');
11
12// Cross-field filtering
13pubnub.setFilterExpression('(meta.userRole == "admin") && (data.action == "delete") && (data.target["type"] == "production")');

Operator precedence

Expressions are evaluated according to standard mathematical precedence:

  1. Parentheses: ()
  2. Unary operators: ! (logical NOT), ~ (bitwise NOT)
  3. Arithmetic: *, /, % (left-to-right)
  4. Arithmetic: +, - (left-to-right)
  5. Comparison: ==, !=, <, >, <=, >=, LIKE, CONTAINS
  6. Logical AND: &&
  7. Logical OR: ||
Parentheses for clarity

Use parentheses to make precedence explicit in complex expressions.

Real-world applications

Use these examples to apply subscribe filters in chat, geolocation, IoT, and trading scenarios.

Chat application filtering

1// Moderator message filtering
2// This filter ensures only messages from moderators or admins with non-empty text are received,
3// useful for administrative channels where only staff communications should be visible.
4pubnub.setFilterExpression('(meta.user["role"] == "moderator" || meta.user["role"] == "admin") && data.text != ""');
5
6// Direct message targeting
7// This filter delivers messages only to users who are participants in a specific conversation,
8// ensuring private messages reach only the intended recipients.
9pubnub.setFilterExpression('meta.conversation["participants"] CONTAINS "' + currentUserId + '" && data.type == "direct_message"');
10
11// Block list filtering
12// This filter blocks messages from multiple specific users that have been blocked by the current user,
13// providing a comprehensive user blocking mechanism for chat applications.
14pubnub.setFilterExpression('meta.publisher != "user123" && meta.publisher != "user456" && meta.publisher != "user789" && meta.publisher != "user101" && meta.publisher != "user202" && meta.publisher != "user303" && meta.publisher != "user404" && meta.publisher != "user505" && meta.publisher != "user606" && meta.publisher != "user707"');
15

Geolocation filtering

1// Geo-fence filtering (100m rectangular boundary)
2// This filter creates a rectangular boundary around a specific location, useful for location-based
3// notifications like nearby restaurant deals or local event announcements.
4pubnub.setFilterExpression('(data.location["lat"] >= 37.7849 && data.location["lat"] <= 37.7869) && (data.location["lng"] >= -122.4094 && data.location["lng"] <= -122.4074)');
5
6// Neighborhood-level filtering
7// This filter targets messages to specific neighborhoods or districts, ideal for community apps,
8// local news, or area-specific services combining geographic boundaries with content type filtering.
9pubnub.setFilterExpression('meta.address["neighborhood"] LIKE "*mission*" && data.type == "local_event"');
10
11// Emergency services - nearby incidents
12// This filter delivers high-priority emergency alerts to users in specific geographic areas,
13// essential for emergency response systems and public safety notifications.
14pubnub.setFilterExpression('meta.emergency["priority"] >= 3 && data.location["zipcode"] == "94110" && meta.services CONTAINS "fire"');

IoT data stream filtering

1// Sensor data filtering
2// This filter monitors specific sensor types and triggers alerts when values exceed predefined thresholds,
3// essential for environmental monitoring and automated alert systems in smart buildings or industrial facilities.
4pubnub.setFilterExpression('data.sensor["type"] == "temperature" && data.value > meta.thresholds["high"]');
5
6// Device health monitoring
7// This filter identifies devices that need attention by monitoring battery levels and critical errors,
8// enabling proactive maintenance and preventing device failures in IoT deployments.
9pubnub.setFilterExpression('meta.device["status"] != "maintenance" && (data.battery < 20 || data.errors[0] CONTAINS "critical")');
10
11// Time-based sampling
12// This filter collects periodic reports from a subset of devices to reduce data volume while maintaining visibility,
13// useful for large-scale IoT deployments where continuous monitoring of all devices would be overwhelming.
14pubnub.setFilterExpression('meta.deviceId % 60 == 0 && data.timestamp LIKE "*:00:*"'); // Hourly reports

Financial trading filters

1// Trading signal filtering
2// This filter delivers cryptocurrency price alerts only when prices exceed user-defined thresholds,
3// enabling personalized trading notifications while filtering out irrelevant market movements.
4pubnub.setFilterExpression('data.symbol LIKE "CRYPTO*" && data.price > meta.user["minPrice"]');
5
6// Risk management
7// This filter enforces trading limits and compliance rules by monitoring position sizes and account restrictions,
8// providing automated risk controls to prevent unauthorized or excessive trading activity.
9pubnub.setFilterExpression('data.position["size"] <= meta.limits["maxPosition"] && !(meta.restrictions CONTAINS "dayTrading")');
10
11// Market event filtering
12// This filter identifies significant market movements by analyzing trade volume and price changes,
13// delivering alerts only for high-impact events that meet minimum transaction value and volatility criteria.
14pubnub.setFilterExpression('(data.volume * data.price) > meta.filters["minValue"] && data.changePercent > 5');

Best practices

  • Design metadata with filtering in mind from the start
  • Use specific field names rather than generic terms
  • Include computed values to avoid complex arithmetic
  • Flatten nested structures where possible for performance
  • Keep data types consistent across similar fields

You can filter by a non-filterable value by adding the value to metadata or the payload and of the message, then filtering on it.

Publisher filtering

To filter by publisher, include publisher information in metadata:

1// Publishing with publisher info in metadata
2await pubnub.publish({
3 channel: 'updates',
4 message: { text: 'Hello World' },
5 meta: {
6 publisher: pubnub.getUserId(), // Include publisher in metadata
7 region: 'San Francisco'
8 }
9});
10
11// Filter based on publisher metadata
12pubnub.setFilterExpression('meta.publisher != "' + pubnub.getUserId() + '"'); // Filter out own messages

Message type filtering

To filter by the custom message type, include the message type in the message payload or metadata when you add the customMessageType parameter during a publish.

Publish with type in payload

1// Publish with type in payload
2const ALERT_TYPE = 'alert'; // pass custom message type value to publish and message payload
3
4// Filter by message type via message payload
5pubnub.setFilterExpression(`data.type == "${ALERT_TYPE}"`); // filter via payload
6
7// Publish with type in payload
8await pubnub.publish({
9 channel: 'alerts',
10 message: {
11 text: 'System Alert',
12 type: ALERT_TYPE // include type in payload for filtering
13 },
14 meta: {
15 priority: 'high'
show all 18 lines

Publish with type in metadata

1// Publish with type in metadata
2const ALERT_TYPE = 'alert'; // pass custom message type value to publish and message payload
3
4// Filter by message type in metadata
5pubnub.setFilterExpression(`meta.msgType == "${ALERT_TYPE}"`); // filter via metadata
6
7// Publishing with type information in metadata
8await pubnub.publish({
9 channel: 'alerts',
10 message: {
11 text: 'System Alert',
12 },
13 meta: {
14 msgType: ALERT_TYPE, // include type in metadata for filtering
15 priority: 'high'
show all 18 lines

Performance optimization

Use these guidelines to keep filter evaluation fast and resource‑efficient at scale.

Filter efficiency guidelines

EfficiencyTechniqueExample
Most efficient
Direct field comparisons
meta.priority == "high"
Most efficient
Numeric operations
data.score > 100
Most efficient
Simple AND conditions
field1 == "value" && field2 > 5
Moderately efficient
Pattern matching
field LIKE "prefix*"
Moderately efficient
Array/object access
meta.array[0] == "value"
Moderately efficient
Arithmetic operations
meta.id % 10 == 0
Use sparingly
Complex arithmetic
(field1 + field2) * field3 > threshold
Use sparingly
Long OR chains
Many || conditions
Use sparingly
Nested patterns
Multiple LIKE/CONTAINS in one expression

Metadata design for filtering

Structure your metadata to optimize filter performance:

1// Efficient metadata structure
2meta: {
3 priority: "high", // Direct string access
4 userTier: "premium", // Flattened user information
5 categoryFlags: "news,urgent", // Comma-separated for CONTAINS
6 computedScore: 85, // Pre-calculated values
7 permissions: { // Single-level nesting
8 read: "true",
9 write: "false"
10 }
11}
12
13// Less efficient structure
14meta: {
15 user: {
show all 23 lines

Troubleshooting

Use these checks to diagnose and fix filter expression problems.

Common filter expression errors

Start with these frequent mistakes.

Syntax issues

1// INCORRECT: Boolean literal
2meta.active == true
3
4// CORRECT: String comparison
5meta.active == "true"
6
7// WRONG: Assignment operator
8meta.priority = "high"
9
10// CORRECT: Equality operator
11meta.priority == "high"

Field access issues

1// INCORRECT: Direct envelope field access
2publisher == "alice"
3uuid == "user123"
4
5// CORRECT: Include in metadata
6meta.publisher == "alice" // (must be included when publishing)
7meta.uuid == "user123" // (must be included when publishing)
8// Or
9data.publisher == "alice" // (must be included in message payload)
10data.uuid == "user123" // (must be included in message payload)

Object access issues

1// INCORRECT: Multi-level chaining
2meta.data["users"][0] == "alice"
3
4// CORRECT: Single-level access
5meta.users[0] == "alice"

Filter expression reference

This section lists supported operators and data types for subscribe filter expressions.

Complete operator support

OperatorTypeDescriptionExample
==
Comparison
Equality
meta.status == "active"
!=
Comparison
Inequality
data.type != "debug"
>
Comparison
Greater than
meta.level > 5
<
Comparison
Less than
data.score < 100
>=
Comparison
Greater or equal
meta.priority >= 3
<=
Comparison
Less or equal
data.size <= 1024
LIKE
Pattern
Wildcard matching
meta.title LIKE "news*"
CONTAINS
Pattern
Substring search
data.tags CONTAINS "urgent"
&&
Logical
AND
meta.active == "true" && data.score > 50
||
Logical
OR
meta.priority == "high" || data.urgent == "true"
!
Logical
NOT
!(data.type == "system")
%
Arithmetic
Modulo
meta.userId % 10 == 0
+
Arithmetic
Addition
meta.base + 5 > 20
-
Arithmetic
Subtraction
data.total - data.used < 10
*
Arithmetic
Multiplication
meta.rate * 100 > 50
/
Arithmetic
Division
data.total / data.count > 5
[n]
Access
Array element
meta.tags[0] == "urgent"
["key"]
Access
Object property
meta.user["role"] == "admin"

Data type support

Data TypeSyntaxExampleNotes
String
"value"
meta.name == "Alice"
Always quote string values
Number
123, 3.14
data.score > 85
No quotes for numeric values
Boolean
"true", "false"
meta.enabled == "true"
Use strings, not literals
Array
[index]
meta.tags[0]
Zero-based indexing
Object
["key"]
meta.user["role"]
Use double quotes for keys
Last updated on