This project is not covered by Drupal’s security advisory policy.

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.
Supporting organizations: 
sponsored development

Project information

Releases