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

Gitter Laravel Package

laravel-notification-channels/gitter

Laravel Gitter Notification Channel lets you send notifications from your Laravel app to Gitter chat rooms using Laravel's built-in notification system. Add the channel to a notification, configure your Gitter webhook or token, and deliver updates to your team without custom integration code.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're adopting first. This package is a thin, single-purpose notification channel: it wraps the Gitter REST API (POST /v1/rooms/{roomId}/chatMessages) behind Laravel's Notification system. It has ~10 stars and no dependents. The latest release, v2.2.0, is a "Laravel 8" compatibility bump — i.e. the package's illuminate/support constraint tops out at Laravel 8. That release line predates Laravel 9/10/11/12 entirely, so treat it as "vendored code you happen to install," not a maintained dependency. The code is only a few dozen lines and will run on modern Laravel if you get it installed, but Composer will refuse to resolve it on Laravel 9+. Also confirm Gitter itself is still acceptable in your org: Gitter has been in maintenance mode since the Element acquisition and has a long-running plan to migrate users to Matrix.

Install

composer require laravel-notification-channels/gitter

On Laravel 9+ expect this to fail against the illuminate/support constraint. Run composer why-not laravel-notification-channels/gitter to confirm. Your options, in order of preference:

  1. Don't install it — write the ~40-line channel yourself (see Gotchas). This is now the default recommendation, because the constraint problem isn't going away.
  2. Fork it, widen the constraint in the fork's composer.json, and pull it in via repositories (vcs or path).
  3. --ignore-platform-reqs as a last resort — it silences the resolver, not the incompatibility, and will bite you at the next composer update.

Get credentials

  1. Create a personal access token at https://developer.gitter.im/apps (scope: flow/chat write is enough).
  2. Find the target room ID via the API, e.g. curl -H "Authorization: Bearer $TOKEN" https://api.gitter.im/v1/rooms — the id field is the opaque hex string the channel needs, not the uri/name.

Configure in config/services.php:

'gitter' => [
    'token' => env('GITTER_TOKEN'),
],

Add the room ID here too ('room_id' => env('GITTER_ROOM_ID')) if you'll use on-demand routes — you'll want it in one place.

First use case — a deploy/alert notification, sent on-demand (no Notifiable model required):

use Illuminate\Notifications\Notification;
use NotificationChannels\Gitter\GitterChannel;
use NotificationChannels\Gitter\GitterMessage;

class DeployFailed extends Notification
{
    public function __construct(public string $reason) {}

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

    public function toGitter(object $notifiable): GitterMessage
    {
        return GitterMessage::create()
            ->text("**Deploy failed**\n> {$this->reason}");
    }
}
Notification::route('gitter', config('services.gitter.room_id'))
    ->notify(new DeployFailed('migration timed out'));

Where to look first: the package's src/GitterChannel.php and src/GitterMessage.php. They are the entire API surface. Reading them (5 minutes) beats relying on the README, which hasn't changed since 2020 — and it's also the fastest way to decide whether to just copy them into app/Notifications/Channels/.

Implementation Patterns

Attach the channel to a Notifiable model when the destination is stable:

class Team extends Model
{
    use Notifiable;

    public function routeNotificationForGitter(): string
    {
        return $this->gitter_room_id;
    }
}

Then $team->notify(new DeployFailed(...)) resolves the room automatically. The channel reads this via routeNotificationFor('gitter'); if it returns null/empty, the channel returns silently (see Gotchas).

Fan out to multiple rooms by looping and using on-demand routes — cleanest when rooms are per-environment:

foreach (['staging' => $stagingRoom, 'production' => $prodRoom] as $env => $room) {
    Notification::route('gitter', $room)
        ->notify(new DeployFailed($reason, $env));
}

Use it as one leg of a multi-channel alert. The channel composes naturally with mail/Slack:

public function via($notifiable): array
{
    return $this->severity === 'critical'
        ? [GitterChannel::class, 'mail', 'slack']
        : ['mail'];
}

Keep messages terse and Markdown-safe. Gitter renders Markdown, so **bold**, backticks, and > quotes work; but any user-supplied text (exception messages, branch names) must be escaped or wrapped in code fences to avoid broken formatting and accidental mentions:

return GitterMessage::create()
    ->text("Deploy failed on `".e($this->branch)."`\n```\n".$this->reason."\n```");

Trigger from events, not controllers. A listener is the natural integration point:

class NotifyGitterOfFailedJob
{
    public function handle(JobFailed $event): void
    {
        Notification::route('gitter', config('services.gitter.room_id'))
            ->notify(new DeployFailed($event->exception->getMessage()));
    }
}

Queue the notification, not the HTTP call, so alerts don't block the request/job that failed:

class DeployFailed extends Notification implements ShouldQueue
{
    use Queueable;
}

Note the package's GitterChannel does a synchronous HTTP call inside send(); ShouldQueue on the notification is what moves it off the request path.

Testing. Notification::fake() asserts the notification was dispatched, which is usually all you need:

Notification::fake();

$team->notify(new DeployFailed('boom'));

Notification::assertSentTo($team, DeployFailed::class);

To assert the payload, call toGitter() directly and inspect the message object — faster and more stable than mocking HTTP:

$message = (new DeployFailed('boom'))->toGitter($team);
$this->assertStringContainsString('boom', $message->text);

For an end-to-end check: the channel predates Laravel's HTTP client, so it likely talks to Guzzle directly (Http::fake() won't intercept it). If you write or fork the channel, switching it to Http::withToken(...) means your existing Http::fake() tests cover it for free — a good reason to prefer the DIY version.

Gotchas and Tips

  • The install is the gotcha now. v2.2.0's "Laravel 8" release means the constraint is ^8.0-era. On Laravel 9+ Composer simply won't install it. Decide up front: fork, vendor-copy the two classes, or reimplement. Don't ship a --ignore-platform-reqs install to production and call it done.
  • Silent no-op without a route. If routeNotificationForGitter() returns null or the on-demand route key is wrong (e.g. 'gitter ' with a space, or 'Gitter'), the channel simply returns. Nothing throws, nothing logs. This is the #1 "why isn't it sending?" cause — verify the route key matches exactly gitter.
  • Room ID vs. room URI. Passing org/channel or the display name will 404. Use the hex id from GET /v1/rooms.
  • Config cache. php artisan config:cache in production will bake in a stale GITTER_TOKEN if you changed .env without recaching. Also never commit the token; it's a full-account credential.
  • Abandonment risk is the real gotcha. With a 2020-era last release, a Laravel-8-only constraint, and zero dependents, there is no one upstream fixing Laravel 12 compatibility, PSR-18 changes, or Gitter API quirks. Budget for one of:
    1. Forking into your monorepo (repositories + vcs in composer.json) with a widened illuminate/support constraint.

    2. Writing the channel yourself — it is genuinely small, and this is the recommended path:

      class GitterChannel
      {
          public function send($notifiable, Notification $notification): void
          {
              if (! $room = $notifiable->routeNotificationFor('gitter')) {
                  return;
              }
              Http::withToken(config('services.gitter.token'))
                  ->post("https://api.gitter.im/v1/rooms/{$room}/chatMessages", [
                      'text' => $notification->toGitter($notifiable)->text,
                  ])->throw();
          }
      }
      

      This version uses Http::fake() in tests and ->throw() for observable failures — both improvements over the package, on top of having no version constraint to fight.

  • Platform risk. Confirm Gitter is a supported tool before building alerting on it; migrations to Matrix have been announced and repeatedly slipped. Don't make it the only alert path for production incidents.
  • Rate limits. Gitter throttles per-token. Bursty loops (e.g., one notification per failed job in a batch) will get 429s. Deduplicate/batch in the listener, or catch and back off.
  • Message length. Gitter truncates long messages server-side; truncate exception traces at the source (Str::limit($e->getMessage(), 1500)) so the important first lines survive.
  • Debugging checklist: (1) curl the send endpoint with the token — if that fails, it's credentials/room, not Laravel; (2) confirm the config key is services.gitter.token as the provider expects; (3) Log::info() inside your toGitter() to prove it's reached; (4) check queue workers are running if ShouldQueue.
  • Extension point: since there's no maintained upstream, prefer wrapping the channel in your own toGitter()-returning notification base class so you can swap the transport (Gitter → Slack → Matrix) later without touching call sites. Keep the room IDs in config, not in code, for the same reason.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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