Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twitter Laravel Package

laravel-notification-channels/twitter

Send Twitter notifications from Laravel using this notification channel. Integrate tweets and direct messages into Laravel’s notification system via the Twitter API, with a simple channel driver for queued or on-demand notifications.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and wire up credentials. The package reads from config/services.php, not a dedicated config file:

composer require laravel-notification-channels/twitter:^8.3
// config/services.php
'twitter' => [
    'consumer_key'    => env('TWITTER_CONSUMER_KEY'),
    'consumer_secret' => env('TWITTER_CONSUMER_SECRET'),
    'access_token'    => env('TWITTER_ACCESS_TOKEN'),
    'access_secret'   => env('TWITTER_ACCESS_SECRET'),
],

As of v8.3.0 the package no longer supports abraham/twitteroauth 7.x — that line only exists in the v9 branch. So the major you pick is dictated by your OAuth dependency, not by preference: ^8.3 for twitteroauth 6.x (drop-in for existing Laravel apps), ^9.0 if something else in your stack pins twitteroauth 7.x. Check what Composer resolves before writing any message code.

You need an X/Twitter developer app with Read and write permission and an access token generated after that permission was set (see Gotchas — this trips up almost everyone).

2. Write a notification. The channel is just another Laravel notification channel:

use Illuminate\Notifications\Notification;
use NotificationChannels\Twitter\TwitterChannel;
use NotificationChannels\Twitter\TwitterMessage;

class StatusTweet extends Notification
{
    public function __construct(public string $text) {}

    public function via($notifiable): array
    {
        return [TwitterChannel::class];
    }

    public function toTwitter($notifiable): TwitterMessage
    {
        return TwitterMessage::create($this->text);
    }
}

3. Send it. Notification::route() works too, so you don't strictly need a Notifiable model — handy for one-off ops scripts.

Where to look first: open src/TwitterChannel.php and src/TwitterMessage.php before reading the README, then read the require block in composer.json to confirm which twitteroauth major the installed tag expects. The entire public surface is those two classes, one exception type, and a thin wrapper around abraham/twitteroauth. Reading ~150 lines tells you more than the docs, which occasionally lag the released tag.

Best first use case: one-way operational broadcasting to an account you own — deploy notices, incident status, "nightly build failed". This is the shape the package is built for: single account, low volume, write-only. It is not a social-media management tool.

Implementation Patterns

Conditional channel routing. Gate on the presence of a route so notifications don't blow up for users who haven't linked an account:

public function via($notifiable): array
{
    return $notifiable->routeNotificationFor('twitter')
        ? [TwitterChannel::class]
        : [];
}

Or, in a fan-out notification, use $this->via() composition with Notification::route() for system events that have no user.

Always queue it. The channel makes a blocking HTTP call. Implement ShouldQueue on every notification that includes TwitterChannel, and handle failure explicitly:

public function failed(Throwable $e): void
{
    Log::error('Tweet failed', ['message' => $e->getMessage()]);
}

Media attachments. TwitterMessage supports an image with alt text; because upload is a separate round-trip, the path must be resolvable at send time — queued jobs that reference a temp file will fail. Persist first, then pass Storage::path(...).

Direct messages. The message class exposes a DM factory; the recipient comes from routeNotificationForTwitter() on the notifiable, which must return the numeric user ID (not a @handle). Check TwitterMessage in your installed version for the exact factory name, as it has changed across majors.

Multi-account sending. There is one credential set in config, so a second account requires mutating config immediately before dispatch:

config(['services.twitter' => $credentialsFor($account)]);
$user->notify(new StatusTweet($text));

This is not concurrency-safe. If you genuinely need multiple accounts, resolve the channel from the container per-account ($this->app->make(TwitterChannel::class)) with a scoped config swap, or wrap the channel in a small TwitterClient interface with account-scoped instances. Do the wrapper anyway — it costs an hour and decouples you from the package.

Testing. Notification::fake() + assertSentTo() verifies routing and payload without touching the network. For the channel itself, swap TwitterChannel in the container for a spy (see Gotchas — Http::fake() will not intercept it).

Reading data is out of scope. Timelines, mentions, likes, follower counts — none of it is here. For anything beyond posting and DMs, inject Abraham\TwitterOAuth\TwitterOAuth directly or write your own client. Keep the package for outbound notifications only.

Gotchas and Tips

  • Permission changes invalidate tokens. If you flip the app to "Read and write" after generating an access token, the token keeps its old scope and you get 403s that look like auth bugs. Regenerate the token and secret.
  • 403s are usually policy, not code. X's API tiers gate posting volume and DM access. Read the response body — the package throws CouldNotSendNotification with the API's message, which is far more informative than the exception class. Log $e->getMessage() verbatim; you'll see "duplicate content", "rate limit exceeded", or "not authorized for this endpoint".
  • Duplicate tweets fail. Posting identical text twice within a window returns an error. Append a timestamp or build id to templated messages.
  • Character limits are enforced server-side, and with URLs/X premium tiers the counting is not simple strlen(). Truncate defensively rather than trusting a 280-char check.
  • Http::fake() won't catch it. TwitterOAuth uses its own cURL transport. To test the channel in isolation, bind a fake TwitterChannel in the container, or bind a mocked TwitterOAuth instance; do not reach for the HTTP fake client.
  • Config caching. php artisan config:cache freezes services.php. Never call env() outside config files, and remember runtime config([...]) overrides for multi-account sending don't survive a config cache in the way you might expect within a single request lifecycle.
  • Route returns a user ID, not a handle. routeNotificationForTwitter() must return the numeric ID. Resolving a handle to an ID is your job, and it's an extra API call you'll want to cache.
  • Watch the OAuth major, not just the package major. abraham/twitteroauth 7.x is only available on the package's v9 line; v8.3.0 explicitly dropped it. If a composer update bumps twitteroauth and you're on ^8.3, expect a conflict rather than a resolve — and if you force it, expect method-signature breakage in the transport layer. Run composer show laravel-notification-channels/twitter abraham/twitteroauth and pin both. Snippets from blog posts targeting older majors will silently mislead you; read the README for that tag.
  • Abandonment risk. Low star count, a single maintainer, and near-zero dependents means the bus factor is one. Pin exactly ("^8.3" or "^9.0", never *), keep all TwitterMessage construction inside one class or two, and keep the swap to a hand-rolled TwitterOAuth call within reach — it's about 20 lines for a plain tweet.
  • Rate limits belong to the job, not the channel. Use Laravel's RateLimited job middleware on queued notifications rather than sprinkling sleeps; retries with exponential backoff will otherwise burn your quota on the same failing message.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource