Skip to main content
The Filtered Stream endpoints let you receive real-time Posts that match your filter rules. Create rules using powerful operators, then connect to a persistent stream to receive matching Posts as they’re published.

Overview

Real-time delivery

Receive Posts within seconds of publication

Persistent rules

Add and remove rules without disconnecting

Powerful operators

Match on keywords, hashtags, users, and more

Webhook delivery

Optionally receive Posts via webhooks

How it works

  1. Create rules — Define filter rules using operators
  2. Connect to stream — Establish a persistent HTTP connection
  3. Receive Posts — Get matching Posts in real-time
┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│ Create/     │      │ Connect to  │      │ Receive     │
│ manage      │  →   │ streaming   │  →   │ matching    │
│ rules       │      │ endpoint    │      │ Posts       │
└─────────────┘      └─────────────┘      └─────────────┘

Endpoints

MethodEndpointDescription
GET/2/tweets/search/streamConnect to the stream
POST/2/tweets/search/stream/rulesAdd or delete rules
GET/2/tweets/search/stream/rulesList current rules

Access levels

FeaturePay-per-useEnterprise
Rules per project1,00025,000+
Rule length1,024 chars2,048 chars
Connections1Multiple
All operators

Contact for Enterprise

Get higher limits and additional features

Building rules

Rules use the same operators as search queries:
(AI OR "machine learning") lang:en -is:retweet

Example rules

RuleMatches
#pythonPosts with #python hashtag
from:elonmuskPosts by @elonmusk
"breaking news" has:imagesPosts with phrase and images
(@XDevelopers OR @X) -is:retweetMentions, excluding retweets

Build a rule

Learn rule syntax and operators

Connecting to the stream

Establish a persistent HTTP connection to receive Posts:
import requests

def stream_posts(bearer_token):
    url = "https://api.x.com/2/tweets/search/stream"
    headers = {"Authorization": f"Bearer {bearer_token}"}
    
    response = requests.get(url, headers=headers, stream=True)
    
    for line in response.iter_lines():
        if line:
            print(line.decode("utf-8"))

Keep-alive signals

The stream sends blank lines (\r\n) every 20 seconds to maintain the connection. If you don’t receive data or a keep-alive for 20 seconds, reconnect.

Webhook delivery

Instead of maintaining a persistent connection, you can receive Posts via webhooks:

Webhook delivery

Set up webhook delivery for filtered stream

Post edits

The stream delivers edited Posts with their edit history. Each edit creates a new Post ID:
{
  "data": {
    "id": "1234567893",
    "text": "Hello world! (edited)",
    "edit_history_tweet_ids": ["1234567890", "1234567891", "1234567893"]
  }
}

Edit Posts fundamentals

Learn more about Post edits

Getting started

Prerequisites

Advanced topics