Drupal is a registered trademark of Dries Buytaert
cms 2.1.2 Update released for Drupal core (2.1.2)! drupal 11.1.10 Update released for Drupal core (11.1.10)! drupal 10.5.10 Update released for Drupal core (10.5.10)! drupal 10.4.10 Update released for Drupal core (10.4.10)! drupal 11.2.12 Update released for Drupal core (11.2.12)! drupal 11.3.10 Update released for Drupal core (11.3.10)! drupal 10.6.9 Update released for Drupal core (10.6.9)! drupal 10.6.8 Update released for Drupal core (10.6.8)! drupal 11.3.9 Update released for Drupal core (11.3.9)! drupal 11.3.8 Update released for Drupal core (11.3.8)! drupal 11.3.7 Update released for Drupal core (11.3.7)! drupal 11.2.11 Update released for Drupal core (11.2.11)! drupal 10.6.7 Update released for Drupal core (10.6.7)! drupal 10.5.9 Update released for Drupal core (10.5.9)! cms 2.1.1 Update released for Drupal core (2.1.1)! drupal 11.3.6 Update released for Drupal core (11.3.6)! drupal 10.6.6 Update released for Drupal core (10.6.6)! cms 2.1.0 Update released for Drupal core (2.1.0)! linkit 7.0.15 Minor update available for module linkit (7.0.15). views_data_export 8.x-1.10 Minor update available for module views_data_export (8.x-1.10).

What it does

Message Pusher delivers Message Stack entities to subscribed clients in real time, using Pusher or any Pusher-protocol compatible server such as Soketi or pws.

It hooks into Message Notify as a Notifier plugin (id: pusher), so it slots in next to the email notifier and inherits all the standard message_notify behavior — save on success, save on fail, rendered view-modes, MessageNotifierBase::postSend().

Use cases

The transport is generic; anything that can be modeled as a Message entity can ride it:

  • Notifications — mentions, replies, system alerts on private-user.{uid}, rendered as bell popups.
  • Activity streams / timelines — "Alice posted on group X" on group-{linked_entity_id}.
  • Chat / threads — chat lines on thread-{linked_entity_id}.
  • Live dashboards — metric events on dashboard-{uid}.
  • Broadcast announcements — owner-less Messages on a static channel like announcements. Access checks adapt: {uid} is only required when the channel pattern actually uses it.

How it works

Channel resolution is token-driven. Default pattern is private-user.{uid} (matches the Pusher User convention). Available tokens:

  • {uid} — recipient user id
  • {template} — message template machine name
  • {linked_entity_type} / {linked_entity_id} — when those base fields exist on the Message entity

You can fan out one Message to multiple channels in a single trigger via additional_channels. The Pusher event name defaults to the message template machine name, but can be overridden per send. Optionally include the rendered pusher view-mode HTML in the payload (off by default — Pusher caps payloads at ~10kB and rendered HTML may leak privileged content into a channel).

Server side:

$message = Message::create([
  'template' => 'mention_news',
  'uid' => $recipientUid,
  'linked_entity_type' => 'node',
  'linked_entity_id' => $node->id(),
]);
$message->save();

\Drupal::service('message_notify.sender')->send($message, [], 'pusher');

Client side (with pusher_user installed, every authenticated page subscribes the current user to their own private-user.{uid} channel and re-broadcasts each event):

$(document).on('pusherUser:event', (e, eventName, data) => {
  if (eventName.startsWith('mention_')) {
    // Update bell counter, prepend to feed, refetch endpoint, etc.
  }
});

For native clients (React Native, iOS, Android) subscribe to the same channel through your Pusher SDK after authenticating against pusher_api's /admin/pusher-api/authentication endpoint.

Requirements

Recommended companion modules

  • Pusher User — auto-subscribes logged-in Drupal users to their private-user.{uid} channel on the web, so no extra JS is needed to receive notifications.

Installation

composer require drupal/message_pusher
drush en message_pusher

See the bundled README.md for the full configuration reference, payload shape, and test instructions.

Self-hosting tip

Pusher.com works out of the box, but for in-house / EU-hosted real-time you can swap in Soketi — it speaks the Pusher protocol, runs in Docker, and requires no code changes on either the Drupal side or the client side. Just point $settings['pusher_api']['default']['options'] at your Soketi host.

Status

1.0.0-alpha1 — first release. Production-shaped but the API may still shift before 1.0.0 stable. Issue reports, MRs and feedback very welcome.

Related issues upstream

A couple of pusher_api issues are open that affect this module's robustness:

  • pusher_api #3591837: PusherService::trigger() should return bool so callers can detect delivery failure. Once merged, this module's deliver() will pass real success/failure back to MessageNotifierBase::postSend() and save on fail will behave correctly.
  • pusher_api #3591832: self-hosted servers via js_options — needed if you're running Soketi instead of pusher.com and want the browser to connect to your own host.

Activity

Total releases
1
First release
May 2026
Latest release
23 hours ago
Release cadence
Stability
0% stable

Releases

Version Type Release date
1.0.0-alpha1 Pre-release May 24, 2026