Laravel + Pusher without Echojs

If you want to get real time notification using Laravel backend api and any frontend of your choice without Laravel Echo, this article will provide a step by step guide;

  1. Register with Pusher
  2. Create an event using Laravel event command
  3. Setup queue backend
  4. Setup a public channel
  5. Setup a private channel

Step 1: Register with Pusher

Register with Pusher or if you already have an account, go to Pusher dashboard, click on App Key and obtain the following:

app_id = "******"
key = "***********"
secret = "************"
cluster = "***"

At this point, I assume you have a laravel project already setup. If not, visit Laravel documentation for a quick setup. Go to your Laravel and replace Pusher env credentials with what you got from your Pusher dashboard.

BROADCAST_DRIVER=pusherPUSHER_APP_ID=*******
PUSHER_APP_KEY=**************
PUSHER_APP_SECRET=**************
PUSHER_APP_CLUSTER=***

Step 2: Create an event using Laravel event command

php artisan make:event PaymentNotification

Navigate to PaymentNotification.php and you will see something like this;

//app/Events/PaymentNotification.php<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PaymentNotification
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*
*
@return void
*/
public function __construct()
{
//
}

/**
* Get the channels the event should broadcast on.
*
*
@return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

We will update this file shortly.

Create an endpoint that will trigger the notification. Whenever you visit the event will be triggered. This is for testing purposes.

//routes/web.phpRoute::get('/event', function () {
$array = ['name' => 'Ekpono Ambrose']; //data we want to pass
event(new PaymentNotification($array));

return 'done';
});

Step 3: Setup queue backend process,

Use one of these links:

My personal favourite is Laravel Horizon. Once you have your queuing system running in the background, let’s move to the next step.

Step 4: Setup a public channel

Frontend

Use any frontend you want e.g React, Vue or just plain html with script tags or blade. You can use NPM, for the sake of clarity we will use Pusher via CDN

<!DOCTYPE html>
<head>
<title>Pusher Test</title>
</head>
<body>
<h1>Pusher Test</h1>
<p>
Publish an event to channel <code>my-channel</code>
with event name <code>my-event</code>; it will appear below:
</p>
<div>
<h1>Welcome to pusher frontend</h1>
</div>

<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script>
// Enable pusher logging - don't include this in production
Pusher.logToConsole = true;

var pusher = new Pusher('PUSHER_APP_KEY', {
cluster: 'eu',
});

var channel = pusher.subscribe('payment-request');
channel.bind('new-payment-request', function(data) {
console.log(data)
alert(JSON.stringify(data))
app.messages.push(JSON.stringify(data)); //Data assignment
});
</script>
</body>

Backend

//app/Events/PaymentNotification.php<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PaymentNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public array $paymentRequest;

public function __construct(array $paymentRequest)
{
$this->paymentRequest = $paymentRequest;
}

public function broadcastOn()
{
return new Channel('payment-request');
}

public function broadcastAs()
{
return 'new-payment-request';
}
}

Next is to trigger the event by visiting our backend route which was created earlier.

//routes/web.phpRoute::get('/event', function () {
$array = ['name' => 'Ekpono Ambrose']; //data we want to pass
event(new PaymentNotification($array));

return 'done';
});

When you visit the frontend, there should be an alert and a console message that was logged earlier.

Step 5: Setup a Private Channel

If you want to push the notification to only authenticated (api auth) users, admins or specific users, you’d need to use private channels to avoid unauthorized users listening to private conversations.

Frontend

<!DOCTYPE html>
<head>
<title>Pusher Test</title>
</head>
<body>
<h1>Pusher Test</h1>
<p>
Publish an event to channel <code>my-channel</code>
with event name <code>my-event</code>; it will appear below:
</p>
<div>
<h1>Welcome to pusher frontend</h1>
</div>

<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script>
// Enable pusher logging - don't include this in production
Pusher.logToConsole = true;
let backendBaseUrl = "https://127.0.0.1";

var pusher = new Pusher('PUSH_APP_KEY', {
cluster: 'eu',
authEndpoint: `${backendBaseUrl}/broadcasting/auth`,
auth: {
headers: {
"Authorization": "Bearer TOKEN",
}
}
});

var channel = pusher.subscribe('private-payment-request');
channel.bind('new-payment-request', function(data) {
//add sound
// fetch notification details ( both read and unread )
console.log(data)
alert(JSON.stringify(data))
app.messages.push(JSON.stringify(data));
});
</script>
</body>

We have modified the Pusher object to accept and . The is your api authentication token that you are using to authenticated users. It could be Passport, Santum or any api authentication that your system is using.

authEndpoint: `${backendBaseUrl}/broadcasting/auth`,
auth: {
headers: {
"Authorization": "Bearer TOKEN",
}
}

Also, you have to append to your channel name.

var channel = pusher.subscribe('private-payment-request’)

That’s what makes it private and tells Pusher to send a request to to authenticate the user.

If your frontend is in a different domain you might run into a CORS error. Please visit Pusher or Browser same origin policy page for a work around

Backend

Change the following files

//app/Events/PaymentNotification.php<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class PaymentNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public array $paymentRequest;

public function __construct(array $paymentRequest)
{
$this->paymentRequest = $paymentRequest;
}

public function broadcastOn()
{
return new PrivateChannel('payment-request');
}

public function broadcastAs()
{
return 'new-payment-request';
}
}

Then in your is where the authentication of users happen.

//routes/channels.phpBroadcast::channel('payment-request', function ($user) {
$user= \App\User::find($user->id)->load('roles');
$role = $user->roles()->first();
return in_array($role->name, ['admin', 'superadmin']);
});
orBroadcast::channel('payment-request', function ($user) {
$user= \App\User::find($user->id)->load('roles');
return $user->is_admin;
});
//However you want to authorise the user for the channel

The broadcast channel returns a truthy, falsy or data object.

Lastly needs to be updated to accept authentication guard you are using, mine is

//app/Providers/BroadcastServiceProvider.php<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;

class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
*
@return void
*/
public function boot()
{
Broadcast::routes(['middleware' => ['auth:api']]); add auth guard you are using here

require base_path('routes/channels.php');
}
}

When you trigger the event by visiting this route you should get realtime response on your frontend. Then you can use the data to display on the page. Also, you can visit Pusher Console (https://dashboard.pusher.com/apps/APP_ID/console) on your dashboard to see the debug log.

private channel notification

NOTE: YOU MUST KEEP YOUR QUEUE PROCESS RUNNING

That is all needed to setup a private channel. You can stop reading at this point.

A LITTLE DEEPER

  1. Broadcasting endpoint

If you are curious and want to know how laravel endpoint works, do the following.

Open your postman, make a request to your Laravel backend also remember to pass in your authorization header api token and the socket_id and channel name in a POST request.

To get socket_id, on your frontend, you can console log and copy the id to use for testing purposes.

manually making api request to broadcasting endpoint to authorize user channel

This request is automatically done for us by Pusher. You can open your frontend and see XHR request to the endpoint with long hash. To learn more visit Pusher authorizing user or Laravel authorization channel.

Read more

https://laravel.com/docs/master/broadcasting

Conclusion

We have explored using Pusher as a third party service to push realtime notification to our users, this is relevant when you want to build a chat service, or push realtime notification to certain users about an activity that has happened in the system. There are other services like Ably and Laravel Websocket.

There are other obvious things that might be missing in this article, please drop them in the comment section and also, if you face any issue, let me know.

You can shoot me an email via

Thank you for reading this far.

I am a Web Developer, tech enthusiast. Passionate about using cutting edge technologies to build solutions