Subscribe Filter Details

PubNub's subscribe filters provide comprehensive server-side message filtering capabilities, enabling sophisticated real-time message routing based on payload content, metadata, and complex business logic. Filters are applied before messages reach your client, dramatically reducing bandwidth and improving application performance.

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, while non-matching messages are filtered out server-side.

Core benefits include:

  • 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

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

// Exact string matching
pubnub.setFilterExpression('meta.priority == "high"');
pubnub.setFilterExpression('data.category != "test"');

// Multiple string conditions
pubnub.setFilterExpression('meta.region == "San Francisco" && data.type == "alert"');

Numeric filtering

// Numeric comparisons
pubnub.setFilterExpression('meta.level > 10');
pubnub.setFilterExpression('data.score >= 80');
pubnub.setFilterExpression('meta.priority <= 3');

// Range filtering
pubnub.setFilterExpression('meta.score >= 80 && meta.score <= 100');

// Calculated thresholds
pubnub.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
// Wildcard patterns
pubnub.setFilterExpression('meta.category LIKE "news*"'); // Starts with "news"
pubnub.setFilterExpression('data.title LIKE "*breaking*"'); // Contains "breaking"
pubnub.setFilterExpression('meta.version LIKE "2.1*"'); // Version prefix

// Complex pattern combinations
pubnub.setFilterExpression('data.subject LIKE "*[URGENT]*" && data.body CONTAINS "maintenance"');
// Substring search
pubnub.setFilterExpression('meta.tags CONTAINS "urgent"');
pubnub.setFilterExpression('data.description CONTAINS "error"');

// Multiple substring conditions
pubnub.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.

// Array element access
pubnub.setFilterExpression('meta.tags[0] == "urgent"'); // First element
pubnub.setFilterExpression('data.recipients[1] LIKE "*@company.com"'); // Second element

// Object property access
pubnub.setFilterExpression('meta.user["role"] == "admin"'); // Object key access
pubnub.setFilterExpression('data.config["enabled"] == "true"'); // Nested object

// Combined array and object access
pubnub.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

// Modulo operations for sampling
pubnub.setFilterExpression('meta.userId % 10 == 0'); // 10% sampling
pubnub.setFilterExpression('meta.messageId % 100 == 0'); // 1% sampling

// Arithmetic calculations in filters
pubnub.setFilterExpression('data.score > (meta.baseline + 10)');
pubnub.setFilterExpression('meta.attempts < (meta.maxRetries - 1)');

// Complex arithmetic expressions
pubnub.setFilterExpression('(data.total - data.used) > (data.limit * 0.2)');

Boolean value handling

// Boolean values as strings (recommended approach)
pubnub.setFilterExpression('meta.enabled == "true"');
pubnub.setFilterExpression('meta.active == "false"');
pubnub.setFilterExpression('meta.verified != "false"');

// Numeric boolean flags (alternative)
pubnub.setFilterExpression('meta.isActive == 1'); // 1 for true
pubnub.setFilterExpression('meta.isDisabled == 0'); // 0 for false
Boolean literal limitation

Do not use boolean literals (true/false) in filter expressions. Always use string comparison ("true"/"false") or numeric flags (1/0). JSON boolean values are stored as strings in the filtering system.

Complex expressions

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

Compound logic

// AND expressions
pubnub.setFilterExpression('(meta.priority == "high") && (data.type == "alert")');
pubnub.setFilterExpression('meta.level > 5 && meta.region == "San Francisco"');

// OR expressions
pubnub.setFilterExpression('(meta.priority == "high") || (meta.priority == "critical")');
pubnub.setFilterExpression('data.category == "news" || data.category == "sports"');

// Nested logical expressions
pubnub.setFilterExpression('((meta.priority == "high") || (meta.priority == "critical")) && (data.score > 80)');

// Cross-field filtering
pubnub.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

// Moderator message filtering
// This filter ensures only messages from moderators or admins with non-empty text are received,
// useful for administrative channels where only staff communications should be visible.
pubnub.setFilterExpression('(meta.user["role"] == "moderator" || meta.user["role"] == "admin") && data.text != ""');

// Direct message targeting
// This filter delivers messages only to users who are participants in a specific conversation,
// ensuring private messages reach only the intended recipients.
pubnub.setFilterExpression('meta.conversation["participants"] CONTAINS "' + currentUserId + '" && data.type == "direct_message"');

// Block list filtering
// This filter blocks messages from multiple specific users that have been blocked by the current user,
// providing a comprehensive user blocking mechanism for chat applications.
pubnub.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"');

Geolocation filtering

// Geo-fence filtering (100m rectangular boundary)
// This filter creates a rectangular boundary around a specific location, useful for location-based
// notifications like nearby restaurant deals or local event announcements.
pubnub.setFilterExpression('(data.location["lat"] >= 37.7849 && data.location["lat"] <= 37.7869) && (data.location["lng"] >= -122.4094 && data.location["lng"] <= -122.4074)');

// Neighborhood-level filtering
// This filter targets messages to specific neighborhoods or districts, ideal for community apps,
// local news, or area-specific services combining geographic boundaries with content type filtering.
pubnub.setFilterExpression('meta.address["neighborhood"] LIKE "*mission*" && data.type == "local_event"');

// Emergency services - nearby incidents
// This filter delivers high-priority emergency alerts to users in specific geographic areas,
// essential for emergency response systems and public safety notifications.
pubnub.setFilterExpression('meta.emergency["priority"] >= 3 && data.location["zipcode"] == "94110" && meta.services CONTAINS "fire"');

IoT data stream filtering

// Sensor data filtering
// This filter monitors specific sensor types and triggers alerts when values exceed predefined thresholds,
// essential for environmental monitoring and automated alert systems in smart buildings or industrial facilities.
pubnub.setFilterExpression('data.sensor["type"] == "temperature" && data.value > meta.thresholds["high"]');

// Device health monitoring
// This filter identifies devices that need attention by monitoring battery levels and critical errors,
// enabling proactive maintenance and preventing device failures in IoT deployments.
pubnub.setFilterExpression('meta.device["status"] != "maintenance" && (data.battery < 20 || data.errors[0] CONTAINS "critical")');

// Time-based sampling
// This filter collects periodic reports from a subset of devices to reduce data volume while maintaining visibility,
// useful for large-scale IoT deployments where continuous monitoring of all devices would be overwhelming.
pubnub.setFilterExpression('meta.deviceId % 60 == 0 && data.timestamp LIKE "*:00:*"'); // Hourly reports

Financial trading filters

// Trading signal filtering
// This filter delivers cryptocurrency price alerts only when prices exceed user-defined thresholds,
// enabling personalized trading notifications while filtering out irrelevant market movements.
pubnub.setFilterExpression('data.symbol LIKE "CRYPTO*" && data.price > meta.user["minPrice"]');

// Risk management
// This filter enforces trading limits and compliance rules by monitoring position sizes and account restrictions,
// providing automated risk controls to prevent unauthorized or excessive trading activity.
pubnub.setFilterExpression('data.position["size"] <= meta.limits["maxPosition"] && !(meta.restrictions CONTAINS "dayTrading")');

// Market event filtering
// This filter identifies significant market movements by analyzing trade volume and price changes,
// delivering alerts only for high-impact events that meet minimum transaction value and volatility criteria.
pubnub.setFilterExpression('(data.volume * data.price) > meta.filters["minValue"] && data.changePercent > 5');

Limitations and workarounds

Use these workarounds when a field isn’t directly filterable. Add the value to metadata or the payload and filter on it.

Publisher filtering workaround

Since you cannot directly filter on publisher UUID, include publisher information in metadata:

// Publishing with publisher info in metadata
await pubnub.publish({
channel: 'updates',
message: { text: 'Hello World' },
meta: {
publisher: pubnub.getUserId(), // Include publisher in metadata
region: 'San Francisco'
}
});

// Filter based on publisher metadata
pubnub.setFilterExpression('meta.publisher != "' + pubnub.getUserId() + '"'); // Filter out own messages

Message type filtering workaround

// Include message type in payload or metadata
await pubnub.publish({
channel: 'alerts',
message: {
text: 'System Alert',
type: 'alert' // Include type in payload for filtering
},
meta: {
msgType: 'alert', // Alternative: include in metadata
priority: 'high'
}
});

// Filter by message type
pubnub.setFilterExpression('data.type == "alert"'); // Via payload
show all 16 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:

// Efficient metadata structure
meta: {
priority: "high", // Direct string access
userTier: "premium", // Flattened user information
categoryFlags: "news,urgent", // Comma-separated for CONTAINS
computedScore: 85, // Pre-calculated values
permissions: { // Single-level nesting
read: "true",
write: "false"
}
}

// Less efficient structure
meta: {
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

// INCORRECT: Boolean literal
meta.active == true

// CORRECT: String comparison
meta.active == "true"

// WRONG: Assignment operator
meta.priority = "high"

// CORRECT: Equality operator
meta.priority == "high"

Field access issues

// INCORRECT: Direct envelope field access
publisher == "alice"
uuid == "user123"

// CORRECT: Include in metadata
meta.publisher == "alice" // (must be included when publishing)

Object access issues

// INCORRECT: Multi-level chaining
meta.data["users"][0] == "alice"

// CORRECT: Single-level access
meta.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

Best practices

Use these guidelines to design, implement, and monitor efficient filters.

Filter design

  • 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

Expression construction

  • Start simple; test equality before adding complexity
  • Use parentheses to make operator precedence explicit
  • Put selective conditions first in AND expressions
  • Build complex filters incrementally

Performance monitoring

  • Monitor filter impact on message throughput
  • Prefer numeric comparisons over string operations when possible
  • Cache filter expressions instead of rebuilding them

Subscribe filters provide a comprehensive solution for sophisticated real-time message routing, enabling fine-grained control over message delivery based on content, metadata, and complex business logic while maintaining optimal performance characteristics.

Last updated on