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

Filament Chat Laravel Package

asignua/filament-chat

Filament Chat adds real-time messaging to Filament admin panels. Drop-in chat components let you build conversations, direct messages, and threaded chats with a clean, native Filament UI, ideal for support inboxes, team communication, or customer chat inside your app.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Require the package and run migrations. v1.5.0 ships a third migration, add_last_read_at_to_filament_chat_participants. Run php artisan migrate (or re-publish and migrate if you vendor the migrations) before touching any read-state feature.
  2. Publish the config and skim ChatConfig first — it is the single switchboard for behaviour flags (e.g. ChatConfig::readTimeAvailable()), and most "why is this off?" questions end there.
  3. Register ChatDock on the panel/layout where the chat should live, and make sure your User (or participant model) satisfies whatever contract the package expects.
  4. First use case to build: two users, one conversation. Create the conversation through ChatService, add participants, send a message, and confirm the dock updates. Then wire the smallest possible browser listener for filament-chat-incoming (a console.log) so you can see the event shape {conversation, message, open} before building sound or desktop notifications on it.

Look at, in this order: ChatService (all mutations and signals), ChatConfig (feature gates), ChatDock (front-end constants such as ChatDock::EVENT_INCOMING), then your extension/hook class.

Implementation Patterns

Extensions and hooks. Hook into the message lifecycle by registering an extension that receives the message. As of v1.5.0, messages returned by list/find queries carry their conversation via setRelation, so $message->conversation inside a hook is free — no N+1, and no crash under Model::preventLazyLoading(). Treat that relation as guaranteed and read from it directly rather than re-querying.

Silent UI refresh with ChatService::changed($conversation). Use this when something about the conversation changed but there is no new message: a participant marked something, a read receipt moved, a status badge flipped. It tells members to re-render the conversation — no message row, no bell, no toast, no filament-chat-incoming event. The distinction is deliberate: changed() is a render hint, not a notification channel. If you find yourself calling changed() to make a bell appear, you want a message instead.

Sound / desktop notification via filament-chat-incoming. Listen on the browser for ChatDock::EVENT_INCOMING (string: filament-chat-incoming). Payload is {conversation, message, open}. Typical Alpine or vanilla setup: keep a Set of seen message IDs, and on each event skip if the ID is already present, skip if open is true (the user is looking at the conversation), then fire the sound or new Notification(...). This works with or without a socket — under polling, the event is emitted when the polled counter grows — so the same listener covers both transports.

Read state. conversation_participants.last_read_at is the source of truth for "when did this person last read this conversation". Build unread badges, read receipts, or "last seen" indicators off it, and guard the whole feature behind ChatConfig::readTimeAvailable() so instances that have not run the third migration degrade cleanly to the old behaviour.

Compose the signals. A well-behaved chat screen usually needs all three: messages for content and bells, changed() for out-of-band state, and filament-chat-incoming for cross-tab/desktop attention. Keep them in separate code paths so you can reason about each.

Gotchas and Tips

  • The migration is optional but silent. Without the third migration the chat works exactly as before — which means "read receipts do nothing" looks like a bug rather than a missing migration. Always check ChatConfig::readTimeAvailable() before assuming your read-state code ran.
  • changed() is not a notification. No bell, no toast, no browser event. If a user is expected to notice, send a message.
  • The browser event is independent of notifications.toasts. Turning toasts off does not turn filament-chat-incoming off; turning the event off is not a config toggle. Budget for both firing.
  • It only fires for messages from someone else. Do not add defensive "was this mine?" checks and then wonder why your own-message test never triggers the event — it never will.
  • Polling can duplicate attention. With polling, the counter-growth trigger can fire around reconnects or rapid polls. Dedupe on message.id rather than on timestamps.
  • Respect open. Firing a desktop notification for the conversation currently on screen is the fastest way to get the feature disabled by your users; gate on open first.
  • Don't reintroduce lazy loading. The v1.5.0 setRelation fix protects hook code that reads $message->conversation. If you copy messages out, serialise them, or re-fetch by ID in your own code, hold the conversation relation yourself — otherwise preventLazyLoading() will bite you again in a place the package no longer covers.
  • Debugging event delivery: confirm the Livewire component is actually receiving dispatches, then confirm the browser listener is registered after the asset loads. Log the raw payload from ChatDock::EVENT_INCOMING before adding sound logic — most "no sound" reports are a listener registered too early or an open flag that was true.
  • Feature flags live in ChatConfig. When behaviour differs between environments, diff the published config before diffing the code.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core