spatie/twitter-streaming-api
Laravel-friendly PHP client for Twitter’s Streaming API. Keep an open HTTPS connection and react to tweets and user events in real time (no polling). Easily filter streams, listen for keywords/mentions, and handle incoming tweet payloads with callbacks.
Installation:
composer require spatie/twitter-streaming-api
Authentication: Register an app on Twitter Developer Portal to obtain:
BEARER_TOKEN (Project > Keys and tokens)API_KEY and API_SECRET_KEY (Project > Keys and tokens)First Use Case:
Stream public tweets containing a keyword (e.g., @spatie_be):
use Spatie\TwitterStreamingApi\PublicStream;
$stream = PublicStream::create(
env('TWITTER_BEARER_TOKEN'),
env('TWITTER_API_KEY'),
env('TWITTER_API_SECRET_KEY')
);
$stream->whenHears('@spatie_be', function (array $tweet) {
// Handle tweet (e.g., log, store in DB, or trigger a job)
logger()->info('Mentioned!', ['tweet' => $tweet]);
})->startListening();
Where to Look First:
PublicStream, UserStream, FilterStream).Stream Types:
PublicStream::create(...)->whenHears('#laravel')->startListening();
UserStream::create(...)->whenUserLikes(function (array $like) { ... })->startListening();
FilterStream::create(...)->addRule('track', ['#php', '#laravel'])->startListening();
Event Handling:
when* methods for specific actions (e.g., whenHears, whenUserFollows).$stream->whenHears('keyword', [TweetHandler::class, 'handleMention']);
Long-Running Processes:
// Dispatch a job to start the stream
StartTwitterStreamJob::dispatch($bearerToken, $apiKey, $apiSecretKey);
event(new TweetMentioned($tweet));
Data Persistence:
$stream->whenHears('keyword', function (array $tweet) {
Tweet::create([
'user_id' => $tweet['user']['id'],
'text' => $tweet['text'],
// ...
]);
});
$tweets = [];
$stream->whenHears('keyword', function (array $tweet) use (&$tweets) {
$tweets[] = $tweet;
if (count($tweets) >= 100) {
Tweet::insert($tweets);
$tweets = [];
}
});
Error Handling:
try-catch blocks to handle disconnections:
try {
$stream->startListening();
} catch (\Spatie\TwitterStreamingApi\Exceptions\ConnectionException $e) {
$this->reconnectAfterDelay();
}
Testing:
Mockery or Laravel's HTTP testing:
$mockStream = Mockery::mock(\Spatie\TwitterStreamingApi\PublicStream::class);
$mockStream->shouldReceive('startListening')->andReturnSelf();
Rate Limits:
Connection Drops:
queue:work --daemon or a process manager (e.g., Supervisor) to auto-restart failed jobs.Authentication Changes:
.env and use Laravel’s env() helper. Monitor for deprecation notices.Data Format:
data_get() or flatten the array for consistency:
$screenName = data_get($tweet, 'user.screen_name');
Memory Leaks:
Time Zone Handling:
$createdAt = Carbon::parse($tweet['created_at'])->timezone('America/New_York');
Log Raw Data:
logger()->debug('Raw tweet', ['tweet' => $tweet]);
Check HTTP Headers:
Authorization header is correctly set with the bearer token:
$stream->setBearerToken(env('TWITTER_BEARER_TOKEN'));
Twitter API Status:
Environment Variables:
.env for credentials:
TWITTER_BEARER_TOKEN=your_bearer_token
TWITTER_API_KEY=your_api_key
TWITTER_API_SECRET_KEY=your_api_secret
Extending the Package:
Stream class:
class CustomStream extends \Spatie\TwitterStreamingApi\Stream {
public function whenCustomEvent($callback) {
$this->on('custom.event', $callback);
return $this;
}
}
Performance:
user_id, created_at).Security:
Monitoring:
tasks or a monitoring tool (e.g., Datadog, Sentry).Fallbacks:
if (!$stream->isConnected()) {
$this->fallbackToPolling();
}
How can I help you explore Laravel packages today?