Server-side subscribe filter expressions

A subscribe filter is an expression PubNub evaluates on the server against each message before deciding whether to deliver it to a given client. This syntax reference covers the expression language. A subscribe filter can read only named fields in the payload (data.fieldName) and in meta (meta.fieldName), not other message-envelope fields.

(meta.priority == "high") && (data.score > 80)

This expression delivers only messages whose metadata priority is high and whose payload score is greater than 80.

For what a filter is, where it fits among the other ways to narrow a stream, and the design constraints around it, refer to Filter on the server. For the calls that set an expression on a client, refer to Filter received messages.

Data sources​

PrefixReadsExample
data.fieldNameA named field in the unencrypted message payloaddata.text, data.type, data.user["role"]
meta.fieldNameA named field in the metadata attached with meta at publish timemeta.priority, meta.region, meta.user["role"]

Reference a specific named field by its full path, such as data.score or meta.region. data.fieldName and meta.fieldName are placeholders, not literal syntax. A bare data.* or meta.*, or any expression that reads a whole payload or metadata object, is not supported. For example, data.* > 30 is not a valid filter. PubNub evaluates the filter against every message on the stream, and scanning whole payloads is costly for large messages.

danger
Always prefix with data. or meta.

Write meta.fieldName or data.fieldName every time. An unprefixed name such as publisher == "alice" is not a supported form. Refer to Unprefixed field names.

When message encryption is enabled, a subscribe filter cannot read data.fieldName fields. meta.fieldName fields remain unencrypted and filterable, so never put a secret in meta.

Operators​

CategoryOperatorsData typesExample
Equality==, !=String, numbermeta.status == "active", data.score != 0
Ordering>, <, >=, <=Number only. Not supported on strings, booleans, arrays, or objectsdata.score > 100, meta.count <= 5
PatternLIKE, CONTAINSStringmeta.title LIKE "news*", data.tags CONTAINS "urgent"
Logical&&, ||, !The result of a comparison, pattern, or logical expressionmeta.active == "true" && data.score > 50
Arithmetic+, -, *, /, %Numbermeta.userId % 10 == 0, data.score > (meta.baseline + 10)
Access[n], ["key"]Array element, object property, one level deepmeta.tags[0], meta.user["role"]

The ordering operators >, <, >=, and <= accept numbers only. On a string, boolean, array, or object, the result is undefined. The server doesn't return an error today, but that isn't guaranteed and may change. To compare strings, use ==, !=, LIKE, or CONTAINS.

Operator precedence​

An expression evaluates in this order, from tightest-binding to loosest:

  1. Parentheses: ()
  2. Unary logical NOT: !
  3. Multiplicative arithmetic: *, /, %
  4. Additive arithmetic: +, -
  5. Comparison and pattern: ==, !=, <, >, <=, >=, LIKE, CONTAINS
  6. Logical AND: &&
  7. Logical OR: ||

Parenthesize a compound expression instead of relying on this order. ((meta.priority == "high") || (meta.priority == "critical")) && (data.score > 80) states the intended grouping directly, so it stays correct if a clause is added later.

Data types​

Data typeSyntaxExample
StringAlways quoted: "value"meta.name == "Alice"
NumberUnquoted: 123, 3.14data.score > 85
BooleanCompared as the string "true" or "false", or as a numeric flag such as 1 or 0meta.enabled == "true"
Array elementfield[index], zero-based, one level deepmeta.tags[0] == "urgent"
Object propertyfield["key"], one level deepmeta.user["role"] == "admin"

Expression efficiency​

Relative costExpressionGuidance
LowestDirect field comparison or numeric comparisonPrefer these when they express the rule.
HigherPattern matching or arithmeticUse them only when a direct comparison cannot express the rule.
Depends on order&& expressionPut the most selective condition first.

Pattern matching: LIKE and CONTAINS​

LIKE matches a string against a wildcard pattern. * stands for zero or more characters and can appear at the start, the end, or both:

meta.category LIKE "news*"       // starts with "news"
data.title LIKE "*breaking*" // contains "breaking"
meta.version LIKE "2.1*" // starts with "2.1"

Matching is case-insensitive. A backslash escapes a literal asterisk, as in "literal\*".

CONTAINS matches a substring, with no wildcard syntax:

meta.tags CONTAINS "urgent"
data.description CONTAINS "error"

Array and object access​

field[index] reads an array element, and field["key"] reads an object property, on a named data or meta field. Access is one level deep. meta.tags[0] and meta.user["role"] are valid. Chaining a second level, such as meta.config["alerts"]["email"] or meta.data["users"][0], is not.

meta.tags[0] == "urgent"                 // array element
data.recipients[1] LIKE "*@company.com" // array element, pattern match
meta.user["role"] == "admin" // object property
data.config["enabled"] == "true" // object property

Boolean comparison​

A filter expression sees a JSON boolean in the payload or metadata as a string, not as the literal true or false. Compare it as a string, or use a numeric flag such as 1 or 0 instead:

meta.enabled == "true"
meta.active != "false"
meta.isActive == 1

Filterable and non-filterable properties​

FilterablePropertyAccessNotes
YesMessage payloaddata.fieldNameA named field in the published message content. Not the whole payload
YesMessage metadatameta.fieldNameA named field attached with meta at publish time. Not the whole metadata object
NoPublisher's User IDn/aNot addressable. Include it in meta or the payload, for example as meta.publisher, to filter on it
NoChannel namen/aNot addressable. Include it in meta or the payload to filter on it
NoTimetokenn/aNot addressable
NoCustom or internal message typen/aNot addressable. Include it in meta or the payload to filter on it

Common invalid expressions​

InvalidValidWhy
meta.active == truemeta.active == "true"Boolean values compare as strings, not literals
meta.priority = "high"meta.priority == "high"= is assignment, not comparison. Use ==
meta.priority > "low"Use a numeric field, or == and != for strings>, <, >=, <= accept numbers only. Results on strings, booleans, arrays, or objects are undefined and may become errors
publisher == "alice"meta.publisher == "alice"No meta. or data. prefix. Envelope fields such as the publisher's User ID aren't addressable. Include the value in meta or the payload at publish time. Refer to Unprefixed field names
data.* > 30 or meta.*data.score > 30Wildcards and whole-payload access aren't supported. Reference a specific named field
meta.data["users"][0] == "alice"meta.users[0] == "alice"Array and object access is one level deep. Chained access isn't supported

Unprefixed field names​

Unsupported legacy fallback

A filter that omits the prefix, such as publisher == "alice", currently resolves on the server as meta.publisher == "alice". The server doesn't mark it invalid or return an error. This fallback exists only to keep existing integrations working. It isn't supported, so don't rely on it. It may change or start returning errors. Always write the explicit meta.fieldName or data.fieldName form.

Next steps​

Was this page useful?

Last updated on