SNS subscription filter policies

Write SNS subscription filter policies that match what you mean — attribute vs message-body scope, exact, anything-but (with prefix, suffix, wildcard), equals-ignore-case, prefix, suffix, wildcard, cidr, numeric ranges and exists — how String.Array attributes match, the limits (5 keys, 150 combinations, 256 KB, 200 policies per topic) and the 15-minute propagation delay.

markdownreferencev4WHD6-N7Q4stage: referencetrust: officialservice: snsinterface: anySNS filter policyFilterPolicyScope MessageAttributes MessageBodySNS filter on message bodyanything-butprefixsuffixwildcardequals-ignore-casecidrnumeric filter SNSexists filterString.ArrayNumber attributefilter policy 150 combinationsfilter policy 5 keysFilterPolicyLimitExceededExceptionfilter policy takes 15 minutesSNS filter not workingcase sensitive

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

**A filter policy sits on the subscription, not the topic, and every key in it must match. Without a policy, the subscriber receives everything. Policies filter message attributes unless the subscription's FilterPolicyScope is MessageBody, in which case the published message must be well-formed JSON. Changes can take up to 15 minutes** to take effect, so a test right after editing proves nothing.

Syntax

A policy maps each property name to a list of allowed values or operators. Values in one list are alternatives (OR); different keys must all match (AND). Properties the policy doesn't mention are ignored.

WantPolicy fragment
Exact (any of)"customer_interests": ["rugby", "tennis"]
Anything but"customer_interests": [{"anything-but": ["rugby", "tennis"]}]
Anything but a prefix / suffix / wildcard"event": [{"anything-but": {"prefix": "order-"}}], [{"anything-but": {"suffix": "ball"}}], [{"anything-but": {"wildcard": "*ball"}}]
Case-insensitive"customer_interests": [{"equals-ignore-case": "tennis"}]
Prefix / suffix[{"prefix": "bas"}] / [{"suffix": "ball"}]
Wildcard"customer_interests": [{"wildcard": "*ball"}]
IP range"source_ip": [{"cidr": "10.0.0.0/24"}]
Number equals"price_usd": [{"numeric": ["=", 301.5]}]
Number range"price_usd": [{"numeric": [">", 0, "<=", 150]}]
Number anything-but"price": [{"anything-but": [100, 500]}]
Key present / absent"store": [{"exists": true}] / "store": [{"exists": false}]

Matching rules:

  • Strings are case-sensitive. Quote strings; don't quote numbers.
  • Numbers range from −10⁹ to 10⁹ with five decimal places. Number attributes have type Number or Number.Array.
  • String.Array attributes: each element is matched separately, so any matching element passes. anything-but passes an array only if none of its elements is listed.
  • exists: true needs a non-null, non-empty value. exists: false matches only if the message has at least one attribute, so a message with no attributes at all doesn't match. exists works on leaf keys only.
  • anything-but can be combined with "exists": false.
  • OR across different keys ($or) has its own page, which wasn't collected. Check the SNS guide's "AND/OR logic" before using it.

Message-body scope

aws sns set-subscription-attributes --subscription-arn <arn> \
  --attribute-name FilterPolicyScope --attribute-value MessageBody
aws sns set-subscription-attributes --subscription-arn <arn> \
  --attribute-name FilterPolicy --attribute-value '{"detail":{"status":["PAID"]}}'

With body scope, nest the policy to mirror the JSON structure; only leaf keys count toward the key limit.

Limits

LimitValue
Keys per policy5 (leaf keys for nested policies)
Value combinations150: the product of the value counts per key, times the nesting level for nested keys
Policy size256 KB
Filter policies per topic / per accountDefault quotas; the account one can be raised through Service Quotas. Read the live values rather than assuming them (FilterPolicyLimitExceededException when hit)

When filtering seems wrong

SymptomCheck
Subscriber gets nothingScope: the policy targets attributes, but the publisher put the field in the body, or the other way round. Case differences. exists: false on a message with no attributes. Edited less than 15 minutes ago
Subscriber gets everythingNo FilterPolicy on this subscription. Policies are per subscription
Raw-delivery queue loses messages that pass the filterMore than 10 attributes with raw delivery: discarded (patterns/sns-to-sqs-fanout.md)

EventBridge has a similar but richer pattern language (reference/eventbridge/event-patterns.md).

Read this document as markdown — the same bytes an agent receives.