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

Slack Notification Channel Laravel Package

laravel/slack-notification-channel

Official Laravel package for sending notifications to Slack, supporting webhooks and bot tokens, interactive messages, attachments, and rich block formatting through Laravel's built-in notification system.

View on GitHub
Deep Wiki
Context7

Getting Started

The channel is usually already present in a Laravel app (composer show laravel/slack-notification-channel); otherwise composer require laravel/slack-notification-channel. There is nothing to publish — the package registers itself via its service provider and hooks into Laravel's Notification system.

Two transports, two config paths:

// config/services.php
'slack' => [
    'notifications' => [
        'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), // SlackChannel (Web API)
        'channel'              => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
    ],
],
'slack-webhook' => [
    'webhook_url' => env('SLACK_WEBHOOK_URL'), // SlackWebhookChannel
],

Use the bot token (chat:write, plus chat:write.public or an /invite to the channel) when you need per-message channels, threads, or replies. Use a webhook URL when you just need "post into one channel" with zero OAuth setup.

Where to look first: the Illuminate\Notifications\Messages\SlackMessage class — that is the entire DSL (content, attachments, blocks, routing, HTTP hooks). Transport behavior lives in SlackChannel (Web API) and SlackWebhookChannel. The canonical docs are on laravel.com/docs/notifications#slack-notifications, not the repo README.

First use case — an on-demand alert without a Notifiable model:

Notification::route('slack', '#ops-alerts')
    ->notify(new DeployFailed($release));
class DeployFailed extends Notification
{
    public function via($notifiable) { return ['slack']; }

    public function toSlack($notifiable)
    {
        return (new SlackMessage)
            ->error()
            ->from('Deploy Bot', ':robot_face:')
            ->content("Deploy *{$this->release}* failed on `{$this->env}`");
    }
}

Implementation Patterns

Per-notifiable routing. Add routeNotificationForSlack() to your model (or User) returning a channel ID (C0123ABCD), a DM user ID (U0123ABCD), or #channel-name. Always prefer channel IDs — renaming a channel silently breaks name-based routing.

public function routeNotificationForSlack($notification)
{
    return $this->slack_channel_id ?? config('services.slack.notifications.channel');
}

Blocks over attachments. The v3 line is built around Block Kit. Compose with the fluent block helpers and let the package assemble the payload:

return (new SlackMessage)
    ->from('Monitoring', ':satellite:')
    ->headerBlock('Nightly job summary')
    ->sectionBlock(fn ($block) => $block->fields([
        "*Passed:* {$stats['passed']}",
        "*Failed:* {$stats['failed']}",
    ]))
    ->dividerBlock()
    ->sectionBlock(fn ($block) => $block->text('Failures need triage.')->accessory(
        SlackButtonElement::create('View logs')->url($url)->style('primary')
    ))
    ->contextBlock(fn ($block) => $block->text("Run at {$now}"));

Block types available include header, section (with fields and accessory), divider, context, image, actions (buttons, selects, users-select — added in v3.5–v3.7), so most Block Kit Builder layouts are reproducible fluently. If you'd rather design visually, v3.4.0 added support for hydrating a message from JSON copied out of the Block Kit Builder, and later versions expose a Block Kit Builder URL from a SlackMessage — check the exact static method signature in your installed version before relying on it.

Plain content() still works and is the right tool for one-liners; reach for blocks when you need structure, and legacy attachments() only for old workflows (Slack still renders them, but they appear below blocks).

Conditional messages. Since v3.0.1 you can branch inside the fluent chain, which keeps toSlack() free of if blocks:

return (new SlackMessage)
    ->content('Backup finished')
    ->when($stats['failed'] > 0, fn ($m) => $m->error()->content('Backup finished with failures'))
    ->unless($notifiable->is_quiet_hours, fn ($m) => $m->channel('#ops'));

Threading. Capture the parent ts from Slack (an incoming event or the API response) and reply with ->threadTimestamp($ts), so follow-ups stay out of the main channel.

Queue it. Slack timeouts and rate limits should never fail a business transaction. Implement ShouldQueue on the notification, and for high-volume alerts add job middleware or backoff() — the package does not implement retry/backoff for Slack's 429s.

Testing. Notification::fake() plus assertSentTo($user, DeployFailed::class, fn ($n, $channels, $notification) => ...) verifies routing and channel selection without HTTP. To assert payload shape, call the message's toArray()/buildJsonPayload() (public since v3.0.0) directly and snapshot it — that catches malformed block JSON before it hits Slack. For end-to-end behavior use Http::fake() and assert the request body.

Extending. Subclass SlackMessage and override buildJsonPayload() (public API since v3.0.0) for org-wide defaults like icon_emoji, unfurl_links, or a standard footer context block. Bind a configured Guzzle client in the container if you need proxies, timeouts, or a mock handler in tests.

Gotchas and Tips

  • Silent failures from the Web API. chat.postMessage returns HTTP 200 with {"ok": false, "error": "channel_not_found"}. Nothing throws. Log the response or assert ok in your own wrapper, otherwise "my notification isn't arriving" becomes an hour of debugging. Webhooks behave differently — a bad payload returns 400 and a Guzzle exception does surface.
  • Empty route. If routeNotificationForSlack() returns null and the message has no channel(), you're relying on services.slack.notifications.channel; a misconfigured fallback produces failed sends rather than a skipped notification. Guard with ->when() or return a sane default.
  • Slack mrkdwn is not Markdown. *bold*, not **bold**; _italic_; no headings or tables. Escape user-supplied content (& → &amp;, < → &lt;, > → &gt;) or mentions and links will render weirdly.
  • Hard limits. 50 blocks per message, ~3000 characters per text object, ~150 for header text. The package truncates multibyte-safe since v3.9.0, but truncation is silent — trim long exception messages yourself if the tail is the useful part.
  • Rate limits. Roughly one message per second per channel; bursts get 429 with Retry-After. Batch digests and queue instead of looping notify() inside a foreach.
  • Mutability. Every fluent call returns $this. A SlackMessage stored on the notification instance accumulates state across sends — build it fresh inside toSlack() or clone before appending.
  • unfurlLinks/unfurlMedia were broken for a while and fixed in v3.1.0; if you're pinned below that, unfurling may be ignored. Also note unfurls apply to text, not to arbitrary block content.
  • Config caching. env() calls only work inside config/*.php; after changing SLACK_* variables run php artisan config:cache (and config:clear locally) or you'll chase a stale token.
  • Channel registration ordering. The provider defers registering the slack channel until after the Notification facade resolves, so a custom channel registered in your own provider can be overwritten depending on boot order. Register after resolution (or via Notification::resolved(...)) if you're aliasing slack.
  • Blocks + attachments together: both are sent, blocks on top. Useful for a rich body with a legacy color bar from error()/success()/warning().
  • Debugging checklist: run the notification synchronously (Notification::sendNow()), dump $message->toArray(), then replay the same JSON with curl against the webhook or chat.postMessage to isolate app vs. Slack config.
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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections