spatie/laravel-bluesky-notification-channel
Laravel notification channel for Bluesky (spatie/laravel-bluesky-notification-channel). Send posts via Laravel’s notification system using a simple BlueskyPost builder; automatically detects links, mentions, and hashtags and renders rich text.
Installation:
composer require spatie/laravel-bluesky-notification-channel
Publish the config (if needed):
php artisan vendor:publish --provider="Spatie\BlueskyNotificationChannel\BlueskyNotificationServiceProvider"
Configure .env:
Add your Bluesky API credentials:
BLUESKY_API_KEY=your_api_key_here
BLUESKY_API_SECRET=your_api_secret_here
BLUESKY_ACCESS_TOKEN=your_access_token_here
First Use Case:
Send a notification via a Notification class:
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Spatie\BlueskyNotificationChannel\BlueskyChannel;
use Spatie\BlueskyNotificationChannel\BlueskyPost;
class BlueskyNotification extends Notification
{
use Queueable;
public function via($notifiable)
{
return [BlueskyChannel::class];
}
public function toBluesky($notifiable)
{
return BlueskyPost::make()
->text('Hello from Laravel! Check out ' . url('/'))
->language('en');
}
}
Basic Notification:
// In a controller or job
$user->notify(new BlueskyNotification());
Dynamic Content:
Use variables in text() and leverage Laravel’s string interpolation:
public function toBluesky($notifiable)
{
return BlueskyPost::make()
->text("Hi {$notifiable->name}, your order #{$notifiable->order_id} is ready!")
->language('en');
}
Rich Text Features:
Automatically formats URLs, mentions (@user), and hashtags (#tag):
->text('Visit @spatie for more: https://spatie.be #laravel');
Queueing: Use Laravel’s queue system for async delivery:
$user->notify((new BlueskyNotification())->delay(now()->addMinutes(5)));
Customizing the Post: Add metadata or embeds (if supported by Bluesky’s API):
->text('Check this out!')
->embed('https://example.com/post') // Hypothetical; verify API support
->language('en');
Notifiable Models:
Ensure your model uses Notifiable trait and implements route():
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
public function routeNotificationForBluesky()
{
return $this->bluesky_handle; // Custom accessor for Bluesky handle
}
}
Testing: Use mocks for API calls in tests:
$this->mock(Spatie\BlueskyNotificationChannel\BlueskyClient::class, function ($mock) {
$mock->shouldReceive('post')
->once()
->andReturn(['success' => true]);
});
Error Handling:
Extend the BlueskyChannel to handle failures gracefully:
public function send($notifiable, $notification)
{
try {
parent::send($notifiable, $notification);
} catch (\Exception $e) {
Log::error("Bluesky notification failed: " . $e->getMessage());
// Fallback to email/SMS
}
}
API Rate Limits: Bluesky’s API may throttle requests. Implement retries with exponential backoff:
use Illuminate\Support\Facades\Http;
Http::timeout(30)->retry(3, 100);
Handle Validation:
Ensure text() isn’t empty or exceeds Bluesky’s character limits (~300 chars for posts, ~1000 for replies). Validate in toBluesky():
if (strlen($text) > 300) {
throw new \Exception('Bluesky post exceeds character limit.');
}
Authentication: If using OAuth, ensure tokens are refreshed before expiry. Store tokens securely (e.g., Laravel Sanctum or database).
Rich Text Parsing: Bluesky’s rich text parsing may not support all HTML tags. Test edge cases like nested links or special characters.
Log API Responses: Enable debug mode in the config:
BLUESKY_DEBUG=true
Logs will appear in storage/logs/laravel.log.
Check HTTP Status Codes:
Bluesky may return 429 (rate-limited) or 401 (invalid token). Handle these in a custom channel class.
Verify Handles:
Ensure routeNotificationForBluesky() returns a valid Bluesky handle (e.g., user.bsky.social).
Custom Post Types:
Extend BlueskyPost to support replies or likes:
class BlueskyReply extends BlueskyPost
{
public function replyTo(string $parentPostUri): self
{
$this->replyTo = $parentPostUri;
return $this;
}
}
Webhook Integration:
Use Laravel’s HandleIncomingWebhook to process Bluesky events (e.g., replies to your posts).
Multi-Language Support: Add language detection logic:
public function toBluesky($notifiable)
{
$language = app()->getLocale();
return BlueskyPost::make()
->text('Hello!')
->language($language);
}
Fallback Channels: Combine with other channels (e.g., email) for reliability:
public function via($notifiable)
{
return [BlueskyChannel::class, MailChannel::class];
}
How can I help you explore Laravel packages today?