Many websites and web applications that you interact with on a daily basis present information in real time. For example, when using a messaging application, messages appear on the screen as soon as they are sent to you without requiring the page to be refreshed in your browser.
Typically, this type of real-time functionality is implemented in web applications by using WebSockets.
In this article, we'll look at what WebSockets are, where you might want to use them, and alternative approaches to using WebSockets. Then, we’ll explain how to implement WebSockets in Laravel applications using Pusher. We'll cover how to set up the backend to send broadcasts via WebSockets, as well as how to set up the frontend to listen for these broadcasts. Finally, we’ll cover how to use private channels, presence channels, channel classes, and client events.
What are WebSockets?
WebSockets are a technology that you can use to send and receive data between a client and a server in real time. They allow you to send data from the server to the client without the client needing to request it. Therefore, you can send data to your users as soon as it is available, without needing users to refresh the page in their browser.
WebSockets are useful for implementing features that require instant feedback without any interval, such as real-time notifications and chat applications.
Before we delve further into the topic, it's important that we understand two key concepts used when working with WebSockets: "events" and "channels".
Channels can be thought of as a way of grouping events. For example, in a chat application, you might have a channel for each chat room, such as chat.1
and chat.2
(where 1
and 2
are the IDs of the chats). These channels would be subscribed to (or joined) by the users of the chat rooms, and only events related to these specific chat rooms (such as a message being sent, or a user joining or leaving) would be broadcast to the users.
Events are the actual data broadcast to the users on a channel. For example, in the chat application, you could have events for when a message is sent (that contains the message itself), when a user joins the chat, and when a user leaves the chat.
Typically, a user subscribes to a channel and listens for events.
To give an example of how WebSockets might be used in your application, let's imagine that you have a button that builds a report and then provides a link to download it. We'll assume that the report can sometimes take a few minutes to build, so you don't want to have to wait for the report to be built before the application allows the user to do something else. Instead, pressing the button could trigger the report to be built using the queue. Once the report has been built, the application could broadcast an event via WebSockets to the user so that a notification window pops up letting the user know the report is ready to be downloaded.
Choosing a WebSockets server
Typically, to send data to the client using WebSockets, you need to use a WebSockets server capable of handling connections between the client and server. Depending on your application, you can set up these servers yourself using something like "laravel-websockets" or "Soketi". However, this can sometimes lead to additional complexity in your system's infrastructure because you need to maintain and manage the server yourself.
Instead, you can use managed services, such as Pusher or Ably. You can rely on these services to handle the broadcasting of your data to your users so that you can focus on building your application.
The benefit of using a managed service, such as Pusher, is that you don't need to worry about the complexity of maintaining your own WebSockets server. However, this means that you need to send data to a third party which can sometimes be a security concern depending on the types of data you're sending. Thankfully, Pusher allows you to enable end-to-end encryption for WebSockets, so only the intended recipient can read the data.
As you'd imagine, you'll need to decide on a project-by-project basis whether it’s best to use a managed service or set up your own WebSockets server. For the purpose of this tutorial, we'll be using Pusher. However, the general principles we'll cover can still be implemented with other WebSocket services.
WebSockets vs. polling
As we've already covered, WebSockets allow for data to be sent in real time to the user when an event occurs. Therefore, this approach only sends data to the user when it's available.
However, similar approaches can be implemented without requiring WebSockets, such as "polling". Polling refers to the process of regularly sending a request from the client's browser to the server at a set interval to fetch a new copy of the data. For example, you might send a request to the server every five seconds to check if there are any new notifications to display for the user. Therefore, it can be used to provide a close to real-time experience.
To compare the two approaches, let's take a look at some examples.
First, let's imagine that we have a chat application. In this application, as soon as a message is sent, we want to display it in the recipient's browser. If WebSockets are used, a single broadcast is made from the server to the recipient's browser, and the message is displayed instantly. However, if polling is used, and the browser is set to poll every five seconds, there could be a potential delay of up to five seconds before the message is displayed to the user. Of course, in this scenario, polling wouldn't be very suitable because it could become frustrating for the user to have to wait five seconds before receiving the message.
Second, let's imagine that we have a dashboard displaying some sales figures and charts for your business. Again, if WebSockets are used, as soon as a sale is made, the dashboard updates instantly. However, if polling is used, the dashboard updates after five seconds. In this type of scenario, the dashboard's sales figures aren't as time-sensitive as a chat application, so it's not as important that the dashboard updates instantly. Therefore, in this case, although WebSockets would be nice to have, polling would also be a suitable approach. In fact, you may even want to increase the polling interval to something like thirty seconds or one minute to reduce the strain on the server.
It's important to remember that WebSockets only send data when it's available, so if there's no new data to send, then there's no need to process anything on the server and send the data to the browser. However, polling can potentially put extra strain on the server when constantly sending requests to check if there's any new data available.
Therefore, you'll need to decide on a feature-by-feature basis whether to use WebSockets or an alternative approach, such as polling.
Now that we've covered what WebSockets are, let's take a look at how we can use them in our Laravel applications using Pusher.
Setting up Pusher
To get set up with Pusher, you'll first need to create an account. You can do this by visiting the Pusher website.
After registering, you'll want to create a new "Channels" app. For the sake of this article, we'll be using the following details for the app we create:
- Name your app: "laravel-websockets-test"
- Select a cluster: "eu (EU (Ireland))"
- Choose your tech stack (optional) - Frontend: "Vanilla JS"
- Choose your tech stack (optional) - Backend: "Laravel"
You may also wish to check the "Create apps for multiple environments?" checkbox, which creates separate apps for your local, staging, and production environments. This can be useful if you want to use separate Pusher apps so that your data are completely separate for each environment. However, for the purposes of this tutorial, we'll just be using a single app.
After creating the app, you can then click the "App Keys" navigation option to view the keys that you'll need to add to your Laravel application.
Setting up the backend
Now that we've created an app in Pusher, let's take a look at how we can use it in our Laravel application.
To register the broadcasting authorization features in your application, Laravel ships with a App\Providers\BroadcastServiceProvider
provider out of the box. By default, this provider isn't automatically registered in new Laravel applications. Therefore, you'll need to go to your config/app.php
file and uncomment the line containing the App\Providers\BroadcastServiceProvider::class
provider.
You'll also need to ensure that you have a queue worker running to process the broadcast events. By default, Laravel processes all event broadcasts on the queue to prevent responses from being returned to the users' requests.
Because we're using Pusher Channels in this article, we'll also need to install the Pusher Channels PHP SDK. You can install it using Composer by running the following command in your terminal:
composer require pusher/pusher-php-server
Depending on which WebSocket service you're using, you may need to install a different package or no package at all. For example, if you're using Ably, you'll need to install the Ably PHP SDK.
You can then add the keys that you received from Pusher to your project's .env
file:
PUSHER_APP_ID=pusher-app-id-goes-herePUSHER_APP_KEY=pusher-key-goes-herePUSHER_APP_SECRET=pusher-secret-goes-herePUSHER_APP_CLUSTER=pusher-cluster-goes-here
If you're using the default Laravel .env
file, you may have noticed the following values:
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"VITE_PUSHER_HOST="${PUSHER_HOST}"VITE_PUSHER_PORT="${PUSHER_PORT}"VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
The environment variables starting with VITE_
are used by Vite so that we can access their values in our JavaScript code. For example, VITE_PUSHER_APP_KEY
can be accessed in our JavaScript code using import.meta.env.VITE_PUSHER_APP_KEY
. If these environment variables aren't already in your .env
file (and you're using Vite for compiling your JavaScript), you can add them. Using this approach allows us to keep our keys in a single place (the .env
file) and prevents us from adding hardcoded values to our application code. This makes maintenance easier if we need to change the values in the future when rotating keys, such as in the event of a breach.
It's important to remember that you shouldn't make the PUSHER_APP_SECRET
variable accessible to the frontend using one of the VITE_
variables. This is purely used on the backend and should never be exposed to the frontend.
You'll also need to update your .env
file to set the BROADCAST_DRIVER
to pusher
:
BROADCAST_DRIVER=pusher
These environment variables are all used inside the config/broadcasting.php
config file. Therefore, if you wish to make any changes to your broadcasting-related config, you can change them within this file.
The backend should now be configured and ready to send broadcasts on WebSockets. Let's take a look at how to configure the frontend.
Setting up the frontend
Laravel provides a handy JavaScript library that you can use to subscribe to WebSocket channels and listen for events called Laravel Echo. Laravel Echo is quite handy because it provides a simple API that you can use to subscribe to your channels without needing to understand the underlying WebSocket protocol.
You can install it in your project using NPM by running the following command in your terminal:
npm install --save-dev laravel-echo pusher-js
You might notice that we're also installing the pusher-js
library. We are required to install this because we're using Pusher for broadcasting our events.
After installing Laravel Echo, we can then create a new instance of it in our JavaScript code.
For the purposes of this example, we'll assume that we're using Vite to build our application's assets, so we can access the environment variables that we added to our .env
file earlier on. If you're using a different tool, such as Webpack (whether directly or through Laravel Mix), you may need to use a different approach to access your environment variables.
If you're working on a fresh Laravel application, the resources/js/bootstrap.js
file that ships with the default installation already has the code included to work with Laravel Echo. However, you need to remember to uncomment it so that it can be used. If you're not working with a fresh Laravel application, the contents of the resources/js/bootstrap.js
file are as follows:
/** * We'll load the axios HTTP library which allows us to easily issue requests * to our Laravel back-end. This library automatically handles sending the * CSRF token as a header based on the value of the "XSRF" token cookie. */import axios from 'axios';window.axios = axios;window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';/** * Echo exposes an expressive API for subscribing to channels and listening * for events that are broadcast by Laravel. Echo and event broadcasting * allows your team to easily build robust real-time web applications. */import Echo from 'laravel-echo';import Pusher from 'pusher-js';window.Pusher = Pusher;window.Echo = new Echo({ broadcaster: 'pusher', key: import.meta.env.VITE_PUSHER_APP_KEY, cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', enabledTransports: ['ws', 'wss'],});
As you might have noticed, we're working with the VITE_PUSHER_*
environment variables (such as VITE_PUSHER_APP_KEY
and VITE_PUSHER_APP_CLUSTER
) and passing them to the Echo instance. These are the same environment variables that we previously added to our .env
file.
After creating the Echo instance, you can then compile assets by running the following command in your terminal
npm run dev
Although nothing will happen yet in your browser, we're now ready to write the code to listen for events. If everything is configured correctly, Vite should be able to compile your assets without any errors.
Listening to public channels
Now that we have Pusher set up and our application configured, let's take a look at how we can use it to listen to public channels.
In this example, we'll create a simple Blade view that contains a button. When the button is clicked, it will trigger an event to be broadcast on a public channel. We'll listen for that event in our JavaScript code and use the alert
function when it's received to display the message passed in the event.
The Blade view may look something like this:
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>WebSockets Test</title> @vite('resources/js/app.js') </head> <body> <button id="submit-button" type="button"> Press Me! </button> </body></html>
We'll now want to create a new route in our routes/web.php
file. When we click the button, we'll send a POST
request to this route, which will trigger the broadcast:
use App\Http\Controllers\ButtonClickedController;use Illuminate\Support\Facades\Route;Route::post('button/clicked', ButtonClickedController::class);
We can then create the ButtonClickedController
by running the following command in our terminal:
php artisan make:controller ButtonClickedController -i
You may have noticed that we are passing -i
to the command. This is done so that we can create a single-use controller that only has an __invoke
method since we don't need any other methods in our controller. However, you can remove the -i
flag if you want to create a full controller.
We can then update our controller so that it dispatches an event when called and returns a JSON response:
declare(strict_types=1);namespace App\Http\Controllers;use App\Events\ButtonClicked;use Illuminate\Http\JsonResponse;use Illuminate\Http\Request;final class ButtonClickedController extends Controller{ public function __invoke(Request $request): JsonResponse { ButtonClicked::dispatch(message: 'Hello world!'); return response()->json(['success' => true]); }}
As you can see inside our controller, we've referenced an event called ButtonClicked
and passed a message
parameter to it. This is the event that we'll broadcast via WebSockets. We can create the event by running the following command in our terminal:
php artisan make:event ButtonClicked
Running the above command will create a new app/Events/ButtonClicked.php
file.
I've made some changes to the class generated. Let's take a look at the class and then break down what's happening:
declare(strict_types=1);namespace App\Events;use Illuminate\Broadcasting\Channel;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Queue\SerializesModels;final class ButtonClicked implements ShouldBroadcast{ use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct( private readonly string $message ) { // } public function broadcastAs(): string { return 'button.clicked'; } public function broadcastWith(): array { return [ 'message' => $this->message, ]; } public function broadcastOn(): array { return [ new Channel('public-channel'), ]; }}
First, we have ensured the class is implementing the Illuminate\Contracts\Broadcasting\ShouldBroadcast
interface. This is needed so that Laravel knows to broadcast the event over a WebSocket connection. By default, this interface will cause the event to be processed and broadcast on the queue. However, if you'd prefer to broadcast the event synchronously (before returning the response for the request), you can use the Illuminate\Contracts\Broadcasting\ShouldBroadcastNow
interface instead.
This will force us to add a broadcastOn
method to our event. This method should return an array containing the channel(s) on which we want to broadcast the event. In this case, we'll broadcast the event on a channel called public-channel
.
We will also add an optional broadcastAs
method to our event. This will return the name of the event that we can to broadcast. We'll call it button.clicked
. If we don’t specify the method, Laravel will fall back to the name of the event class. In this case, it would be App\Events\ButtonClicked
. It's important to remember that if you specify the broadcastAs
method, you'll need to add a .
to the beginning of the event name in Laravel Echo. Otherwise, it will append the expected namespace (App\Events
) to the event name. In this case, in our JavaScript, want to listen for .button.clicked
instead of button.clicked
.
We can also specify a broadcastWith
method. This will return an array of data that we want to broadcast with the event. In this case, we'll broadcast the message
property that we passed to the event's constructor and will be displayed in the JavaScript alert box. However, you can pass whatever data best suits your feature here. For example, if you were building a chat application, you might want to broadcast the message that was sent and some other meta information about the chat.
This is all that's needed on the backend to send the broadcasts. We can now update the frontend to listen for the broadcasts and display the alert box.
We'll need to add an event listener that sends a POST
request to the /button/clicked
route whenever the button is clicked. We know that our event is called button-clicked
and that it's being broadcast on the public-channel
channel. We can update our reousrces/js/app.js
file using the following code:
import './bootstrap';// Create an event listener that will send a POST request to the// server when the user clicks the button.document.querySelector('#submit-button').addEventListener( 'click', () => window.axios.post('/button/clicked'));// Subscribe to the public channel called "public-channel"Echo.channel('public-channel') // Listen for the event called "button.clicked" .listen('.button.clicked', (e) => { // Display the "message" in an alert box alert(e.message); });
We can now test that this works. If you click the button on the page, you should see an alert box appear in your browser. To prove that this alert box is being displayed using WebSockets, you can open two different browsers and go to the same page in each browser. Then, click the button in one browser. The alert box should appear in both browsers.
Listening to private channels
So far, we've covered how to send broadcasts over public WebSocket channels. However, there are times when you might want to send broadcasts over private channels so that only authorized users can listen to them. For example, if you were building a chat application, you wouldn't want your messages to be broadcast on a public channel when you sent them; this would allow anyone that knows the name of the channel to listen to your messages. Instead, you'd want to send your messages over a private channel so that only the intended recipients can listen to them.
Let's take a look at how we can use private channels in our application.
By default, Laravel Echo will make an HTTP request to a /broadcasting/auth
endpoint in your application when a user attempts to subscribe to a private channel. This endpoint is defined in the app/Providers/BroadcastServiceProvider
class. We can customize this endpoint by overriding the broadcastingAuthEndpoint
method on the BroadcastServiceProvider
class and updating our Laravel Echo configuration. However, for the purposes of this guide, we'll use the default route.
Let's imagine that we have a chat application, and we want to use private channels. To define the authorization logic for our private channel, we'll need to use the Broadcast::channel
method in our routes/channels.php
.
This method accepts two arguments: the name of the channel and a callback that will be executed when a user attempts to subscribe to the channel. If the user is authorized to subscribe to the channel, the callback should return true
or an array of data that will be sent to the client (we'll cover this part when discussing presence channels later). If the user is not authorized to subscribe to the channel, the callback should return false
.
We’ll assume that the Chat
model has an isMember
method that will return true
if the user is a member of the chat and false
if they are not.
We can define the private channel authorization for our chat application using the following code in the routes/channels.php
file:
use App\Models\Chat;use App\Models\User;use Illuminate\Support\Facades\Broadcast;Broadcast::channel( 'chats.{chat}', fn (User $user, Chat $chat): bool => $chat->isMember($user));
As we can see in the example above, we've defined a chats.{chat}
private channel. Then, we checked whether the user is a member of the chat to which they're attempting to subscribe. Similar to route model binding for routes in Laravel, by defining {chat}
in the channel name, we can type hint the Chat
model in the callback. This will automatically resolve the Chat
model instance from the parameter for us.
We can now create an event that will broadcast on a private channel. We'll call the event App\Events\MessageSent
. Let's take a look at the event class, and then we'll look at what's been done:
declare(strict_types=1);namespace App\Events;use App\Models\Chat;use App\Models\ChatMessage;use Illuminate\Broadcasting\PrivateChannel;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Queue\SerializesModels;final class MessageSent implements ShouldBroadcast{ use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct( private readonly Chat $chat, private readonly ChatMessage $chatMessage ) { // } public function broadcastAs(): string { return 'message.sent'; } public function broadcastWith(): array { return [ 'message' => $this->chatMessage->message, 'sentBy' => [ 'id' => $this->chatMessage->sentBy->id, 'name' => $this->chatMessage->sentBy->name, ] ]; } public function broadcastOn(): array { return [ new PrivateChannel('chats.'.$this->chat->id), ]; }}
As we can see, the broadcastOn
method is returning an array that contains a PrivateChannel
object rather than a Channel
object. If we were to assume the Chat
model has an id
of 1
, the event would be broadcast on the chats.1
private channel.
You may have also noticed that the constructor includes the Chat
model so that we can access it. To dispatch such an event, our code may look something like this:
use App\Models\Chat;use App\Events\MessageSent;MessageSent::dispatch(chat: $chat, chatMessage: $chatMessage);
Let's now write some example JavaScript code that could be used to subscribe to a private channel. We'll assume that a displayChatMessage
function handles displaying the chat message in the browser. We'll also assume that a getChatId
function returns the id
of the chat that the user is currently viewing.
const chatId = getChatId();Echo.private(`chats.${chatId}`) .listen('.message.sent', (e) => { displayChatMessage(e.message, e.sentBy); });
As you can see, it's very similar to subscribing to a public channel. The only difference is that we're using the private
method instead of the channel
method. Laravel Echo handles the authorization logic for us behind the scenes so that we don't need to worry about how it's done.
Listening to presence channels
Presence channels are private, but they allow you to have some awareness of who is subscribed to a given channel. This type of feature could be used in a chat application to know which users are present in the chat. They give us access to events that provide visibility of when someone is joining or leaving the channel.
Similar to private channels, you must authorize the user when attempting to join the channel. Rather than just returning a simple true
or false
from the method, we can return some data in an array. For example, let's take our previous private channels example for the chat room. When authorizing a user for the chats.{chat}
channel, we could return an array containing the user's id
and name
. This data would then be broadcast to the other users already subscribed to this channel. This could be used for displaying information, such as "John Smith joined the chat", or "John Smith left the chat", or maybe even highlighting the users currently online in a list.
To get started with using a presence channel, we'll first need to define the authorization logic for the channel. We'll do this in the routes/channels.php
file:
use App\Models\Chat;use App\Models\User;use Illuminate\Support\Facades\Broadcast;Broadcast::channel('chats.{chat}', function (User $user, Chat $chat): bool { return $chat->isMember($user) ? ['id' => $user->id, 'name' => $user->name] : false;});
Now if we wanted to broadcast an event to this channel, it would be very similar to broadcasting to a private channel. The only difference is that we need to return a PresenceChannel
object in the array from the broadcastOn
method rather than a PrivateChannel
:
use Illuminate\Broadcasting\PresenceChannel;public function broadcastOn(): array{ return [ new PresenceChannel('chats.'.$this->chat->id), ];}
Now we can write the JavaScript that handles the presence channel logic.
We'll assume that a getChatId
function returns the id
of the chat the user is currently viewing. We'll also assume that we have four other functions:
highlightActiveUsers
- This function will highlight the users currently online in the chat.displayUserJoinedMessage
- This function will display a message to the user that another user has joined the chat. It will also highlight the user in the list of active users.displayUserLeftMessage
- This function will display a message to the user that another user has left the chat. It will also remove the user from the list of active users.displayChatMessage
- This function will display the chat message that has just been sent in the browser.
To join a presence channel, we can use the join
method in Laravel Echo:
const chatId = getChatId();Echo.join(`chat.${chatId}`) .here((users) => { // This is run when you first join the channel. highlightActiveUsers(users); }) .joining((user) => { // This is run when other users join the channel. displayUserJoinedMessage(user); }) .leaving((user) => { // This is run when users are leaving the channel. displayUserLeftMessage(user); }) .listen('.message.sent', (e) => { // This is run when a message is sent to the channel. displayChatMessage(e.message, e.sentBy); }) .error((error) => { // This is run if there's a problem joining the channel. console.error(error); });
You might have noticed that five methods are being used here. Let's take a look at what each one does:
join
- This function allows us to join a presence channel. It also handles the authorization logic for us.here
- This function is called when you first join the channel. It receives an array of all the users currently subscribed to the channel. In a chat application, this could be used to display a list of users currently online when you first join the channel.joining
- This function is called whenever other users join the channel and receives the data (in the format we defined in theroutes/channels.php
file). In a chat application, this could be used to display a message to the user that another user joined the chat or highlight the users in a list of active users.leaving
- This function is called whenever other users leave the channel and receives the data (in the format we defined in theroutes/channels.php
file). In a chat application, this could be used to display a message to the user that another user has left the chat or remove the user from the list of active users.listen
- This function is the same as thelisten
function that we used in our public and private channel examples earlier. It allows us to listen for events broadcast to the channel, such as when new messages are sent.error
- This function is called if there are any issues with authorizing the user when trying to join the channel or if the JSON response returned from the authorization endpoint is invalid.
As you can see, presence channels can help to provide a more interactive experience for the user without adding too much extra complexity to your code.
Taking it further
Now that we've covered the three main types of channels and how we can use them to broadcast data to the client, let's take a look at some other handy WebSockets-related features that we can use in our Laravel applications.
Using broadcast channel classes
As your project grows, you may find that your routes/channels.php
file becomes quite large, especially with the authorization logic for private channels. This can sometimes make it difficult to read and maintain. To keep this file clean and improve its maintainability, we can make use of a feature that Laravel provides called "channel classes".
Channel classes are PHP classes that allow us to encapsulate the authorization logic for our private channels within a class. This class can then be used in our routes/channels.php
file to define the authorization logic for the channel.
For example, let's take the following private channel definition from the routes/channels.php
file:
use App\Models\Chat;use App\Models\User;use Illuminate\Support\Facades\Broadcast;Broadcast::channel( 'chats.{chat}', fn (User $user, Chat $chat): bool => $chat->isMember($user));
We could create a new channel class by running the following command:
php artisan make:channel ChatChannel
This would create an app\Broadcasting\ChatChannel
class with a join
method. We can add our authorization logic to this method:
declare(strict_types=1);namespace App\Broadcasting;use App\Models\Chat;use App\Models\User;final class OrderChannel{ public function join(User $user, Chat $chat): bool { return $chat->isMember($user); }}
Alternatively, if we wanted to return an array of data (like for using in a presence channel), the join
method may look like this instead:
public function join(User $user, Chat $chat): bool{ return $chat->isMember($user) ? ['id' => $user->id, 'name' => $user->name] : false;}
We can then update our channel route in the routes/channel.php
file to use this new channel class:
use App\Broadcasting\ChatChannel;use Illuminate\Support\Facades\Broadcast;Broadcast::channel('chats.{chat}', ChatChannel::class);
Broadcasting to others
There may be times when you only want to send a broadcast to other users but not yourself.
For example, let's imagine that you are using a chat application and send a message. In your application's JavaScript, you might instantly display the message on your screen as soon as you send it. You may also have Laravel Echo set up to listen for any new messages sent. When it receives one of these events, Laravel Echo will display the message on the page. This would work perfectly for displaying the messages in the recipient's browser. However, it would result in the message being displayed twice in the sender's browser (once at the time of sending and again at the time of receiving the WebSocket event).
To prevent scenarios like this from happening, we can use the toOthers
method when dispatching the event that will be broadcast. For example, if we wanted to broadcast a MessageSent
event to other users in the chat, we could do the following:
use App\Events\MessageSent;broadcast( new MessageSent(chat: $chat, message: $chatMessage))->toOthers();
Broadcasting on multiple channels per event
So far, in all the examples above, we've only broadcast events to single channels. However, there may be times when you want to broadcast an event on multiple channels simultaneously. For example, let's say that your application has a private channel set up for each user; you may want to send a notification to several of the users at once.
To do this, you can return an array of channels in the broadcastOn
method of your event. For instance, let's say that we have three users with their own private notifications channel enabled (with the channels being called notifications.1
, notifications.2
, and notifications.3
). We could send the broadcast to each of the users by returning an array of PrivateChannel
classes from the broadcastOn
method:
declare(strict_types=1);namespace App\Events;use App\Models\User;use Illuminate\Support\Collection;use Illuminate\Broadcasting\PrivateChannel;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Queue\SerializesModels;final class NewNotification implements ShouldBroadcast{ use Dispatchable; use InteractsWithSockets; use SerializesModels; /** * @param Collection<User> $users */ public function __construct( private readonly Collection $users, ) { // } // ... public function broadcastOn(): array { return $this->users->map(function (User $user): PrivateChannel { return new PrivateChannel('notifications.'.$user->id); })->all(); }}
In the example above, we're passing a Collection
of User
models to the event's constructor. In the broadcastOn
method, we're then mapping through the Collection and returning an array of PrivateChannel
instances (one PrivateChannel
instance per user).
Whispering
Laravel Echo allows you to use "client events". These events don't hit your application's server and can be really useful for providing functionality, such as typing indicators in a chat application.
Let's imagine that we have a chat application, and we want to send a client event to other members of the chat when someone is typing. We'll assume that there is a getUserName
method that returns the name of the logged-in user. We'll also use a very naive and basic approach for detecting whether a user is typing. In a real-life application, you may want to also add debouncing, listen for users pasting text into the text box, etc. However, for the purposes of this guide, we'll just send a client event whenever a user types into the message box.
To enable client events, you can use the whisper
and listenForWhisper
methods in your JavaScript:
// Resolve the channel instance.let channel = Echo.private('chat');// Add handling when a client event is detected. This will// output "John Smith is typing..." to the console.channel.listenForWhisper('typing', (e) => { console.log(e.name + ' is typing...');})// Add an event listener that will trigger a "typing" client// event whenever the user types into the message box.document.querySelector('#message-box') .addEventListener('keydown', function (e) { channel.whisper('typing', { name: getUserName(), }); });
The whisper
method will be called whenever the user types and will send the data to the other users listening on the channel.
The listenForWhisper
method will be called on the receiving users' browsers and be passed the data sent by the whisper
method.
It's important to note that if you're using Pusher (as shown in this guide), you'll need to enable the "Client Events" option in the "App Settings" of your Pusher Channels app.
Conclusion
This article should have given you some insight into what WebSockets are, where you might want to use them, and how to set them up in Laravel using Pusher. You should now be able to use WebSockets in your own Laravel applications to add real-time functionality using public channels, private channels, and presence channels. You should also be able to use concepts such as channel classes and client events to build robust WebSockets integrations.
FAQs
How do WebSockets work in laravel? ›
Laravel WebSockets uses the concept of apps to support multitenancy out of the box. This allows you to host the package separately from your current Laravel application and serve multiple WebSocket applications with one server. The default app uses your existing Pusher configuration. This should do for most use cases.
How to use WebSocket in Laravel 9? ›- Install Laravel 9 Application.
- Make Database Connection.
- Create Model Class.
- Download & Install Ratchet WebSocket Library.
- Create Controller.
- Create View Blades Files.
- Set Route of Controller Method.
- Run Laravel 9 Application.
WebSockets are a low-level protocol that enables two-way realtime communication between client and server. In contrast, Pusher channels are a service that provides an abstraction layer on top of WebSockets, with many features provided by default to make it easier to create realtime applications.
Is laravel WebSockets free? ›You could spend weeks binging, and still not get through all the content we have to offer. Push your web development skills to the next level, through expert screencasts on PHP, Laravel, Vue, and much more. Get Started For Free!
What is the limit of WebSockets in Laravel? ›In addition to the OS restrictions, this package makes use of an event loop called "stream_select", which has a hard limit of 1024.
How to send data through WebSocket? ›WebSocket: send() method. The WebSocket. send() method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of bufferedAmount by the number of bytes needed to contain the data.
How to work with WebSockets? ›WebSocket uses a unified TCP connection and needs one party to terminate the connection. Until it happens, the connection remains active. HTTP needs to build a distinct connection for separate requests. Once the request is completed, the connection breaks automatically.
How to implement WebSocket in PHP? ›- Prerequisites. Create file websockets.html with next content: ...
- Engagement. Start in shell WebSocket server: php -q websockets. ...
- Test. Open in browser URL: http://0.0.0.0:8000/ you will see current timestamp which will continuously updating! ...
- Conclusion.
- A fully HTML5-compliant web browser is required.
- AJAX-like success mechanisms are not available in Websockets.
- Websockets, unlike HTTP, do not provide intermediary/edge caching.
- It is impossible to employ friendly HTTP statuses, bodies, and other elements to create even a simple protocol of your own.
- The connection is used only for a very small number of events, or a very small amount of time, and the client does not need to quickly react to the events.
- Your feature requires multiple WebSockets to be open to the same service at once.
What is the practical use of WebSockets? ›
WebSocket is a protocol that provides full-duplex communication between the client and the server. WebSocket, when connecting to the target server, uses a rather unique function – changing the protocol through its upgrade. This way the HTTP protocol is replaced with WebSocket.
Do WebSockets use a lot of data? ›With HTTP requests, the browser sends cookies and other headers using few hundreds of bytes, increasing the overhead for real-time communication. However, with WebSockets, subsequent messages are small and only have 6 bytes of overhead (2 for the header and 4 for the mask value).
Why are WebSockets obsolete? ›Websockets are largely obsolete because nowadays, if you create a HTTP/2 fetch request, any existing keepalive connection to that server is used, so the overhead that pre-HTTP/2 XHR connections needed is lost and with it the advantage of Websockets.
How many WebSockets can a browser handle? ›WebSocket libraries and web browsers enforce different limits on the number of WebSocket connections. For example, at the time of writing (14th of April 2023), Chrome allows up to 256 concurrent connections per client by default, while Firefox can handle 200 connections per client by default.
How much faster are WebSockets than HTTP? ›Browser client
All browser tests do not include the time (~190ms) it takes to establish websocket connection. The times for a single HTTP and equivalent websocket request look like this: On average a single HTTP request took about 107ms and a Socket.io request 83ms.
WebSockets allows you to transfer as much data as you'd like without incurring the overhead associated with traditional HTTP requests. Data that is transferred through a WebSocket is referred to as messages. These messages consist of one or more frames that contain the data you're sending (the payload).
Can a WebSocket handle multiple connections? ›A server can open WebSocket connections with multiple clients—even multiple connections with the same client. It can then message one, some, or all of these clients. Practically, this means multiple people can connect to our chat app, and we can message some of them at a time.
Do WebSockets close automatically? ›However, the connection between a client and your WebSocket app closes when no traffic is sent between them for 60 seconds.
Can WebSocket handle both text and binary data? ›WebSocket enables bidirectional, message-oriented streaming of text and binary data between client and server.
What type of data is used for WebSocket? ›WebSocket communication consists of “frames” – data fragments, that can be sent from either side, and can be of several kinds: “text frames” – contain text data that parties send to each other. “binary data frames” – contain binary data that parties send to each other.
What version of laravel is WebSockets? ›
Laravel WebSockets is a package for Laravel 5.7 and up that will get your application started with WebSockets in no-time!
How to connect WebSocket to API? ›- You can use wscat to connect to your WebSocket API and send messages to it to simulate client behavior. ...
- You can use the @connections API from your backend service to send a callback message to a connected client, get connection information, or disconnect the client.
Installation. To make use of the Laravel WebSockets package in combination with Pusher, you first need to install the official Pusher PHP SDK. You need to un-comment this provider in the providers array of your config/app. php configuration file to broadcast on channel.
What language works best with WebSockets? ›A WebSocket server can be written in any server-side programming language that is capable of Berkeley sockets, such as C(++), Python, PHP, or server-side JavaScript.
How to read data from WebSocket? ›First, you need to copy your web browser's header to here and use json. dumps to convert it into the string format. After that, create the connection to the server by using create_connection . Then, perform the handshake by sending the message, and you will be able to see the data on your side.
What are WebSockets for dummies? ›WebSockets is a technology that allows a web browser and a web server to communicate with each other in real-time over a persistent connection. It is designed to allow two-way communication between the client and the server, so that either side can send data to the other at any time.
Is PHP good for WebSocket? ›The WebSocket is an armistice allowing two-way asynchronous communication between the customer and the host. It can perform well with PHP applications, for which almost all the companies are using it to benefit from Core PHP Development.
How do I start WebSocket? ›All you have to do is call the WebSocket constructor and pass in the URL of your server. // Create a new WebSocket. var socket = new WebSocket('ws://echo.websocket.org'); Once the connection has been established, the open event will be fired on your Web Socket instance.
How to write a WebSocket API? ›- Sign in to the API Gateway console and choose Create API.
- Under WebSocket API, choose Build.
- Under Settings, in the API name field, enter the name of your API, for example, PetStore .
- Enter a Route Selection Expression for your API, for example, $request.
WebSockets have a low overhead per message. They're ideal for use cases that require low-latency, high-frequency communication. REST APIs have a higher message overhead compared to WebSockets. They're best suited for use cases where you want to create, retrieve, delete, or update resources.
Which is better Socket or WebSocket? ›
It seems that WebSockets have an edge in terms of performance over Socket.IO; for example, WebSockets have a much lower memory requirement compared to Socket.IO. However, some differences are to be expected. After all, Socket.IO is a more complex (and demanding) solution than raw WebSockets.
What is faster than WebSockets? ›WebRTC primarily works over UDP, while WebSocket is over TCP. This means that WebRTC offers slightly lower latency than WebSockets, as UDP is faster than TCP. However, the difference is negligible; plus, TCP is more reliable when it comes to packet delivery (in comparison, with UDP some packets may be lost).
How long can a WebSocket last? ›Typically, HTTP/1.1 infrastructure closes idle connections after 30 to 120 seconds. As a consequence, proxies may terminate WebSocket connections prematurely when no message was exchanged in 30 seconds.
Does Facebook use WebSockets? ›We rely on our existing chat servers, and added the ability to handle WebSocket connections. On top of that we use the MQTT protocol, which we already use in the mobile Messenger apps and in Messenger for Windows to communicate with our chat servers while consuming less bandwidth.
Why WebSockets are not scalable? ›Before: Each WebSocket server needs to process every state update, filter messages addressed to connected clients and forward it along. Thus the scalability of the system is limited by the maximum throughput of a single server for processing state updates.
Should I use WebSockets or HTTP? ›Which protocol is better suited to handle real-time communication? Websockets are the best choice to handle real-time communication as they support bi-directional communication. In this model, both the client and server can push or pull data. They do not have to wait of each other and can work simultaneously.
Which websites use WebSockets? ›- WEBSITE. Multiuser Blocks. Patrick Schroen. HM. ...
- WEBSITE. WeAlgo. Stef Kolman. HM. ...
- WEBSITE. NFT of the Dead. Media.Monks. PRO ...
- WEBSITE. Aritelia. astressence.
- WEBSITE. The Festival of the Diaspora. oncillalabs.
- WEBSITE. Google I/O: Adventure. Set Snail. PRO ...
- WEBSITE. La Passation Synerg'hetic 2021. Romain Penchenat. ...
- PROMOTED.
In a WebSocket "scenario", you have a server-side part and multiple clients. A client can connect with the server side part, and if a client wants to communicate with other clients, it can do it by sending messages to the server. The server will forward or will send messages to the client.
How does the WebSocket work? ›WebSocket is a communications protocol for a persistent, bi-directional, full duplex TCP connection from a user's web browser to a server. A WebSocket connection is initiated by sending a WebSocket handshake request from a browser's HTTP connection to a server to upgrade the connection.
How does WebSocket API work? ›The WebSocket API invokes your backend based on the content of the messages it receives from client apps. Unlike a REST API, which receives and responds to requests, a WebSocket API supports two-way communication between client apps and your backend. The backend can send callback messages to connected clients.
What is the point of WebSockets? ›
The WebSocket API is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
How do you implement WebSockets? ›How Websockets are implemented? webSockets are implemented as follows: Client makes HTTP request to server with "upgrade" header on the request. If server agrees to the upgrade, then client and server exchange some security credentials and the protocol on the existing TCP socket is switched from HTTP to webSocket.
How many WebSockets can connect to a browser? ›WebSocket libraries and web browsers enforce different limits on the number of WebSocket connections. For example, at the time of writing (14th of April 2023), Chrome allows up to 256 concurrent connections per client by default, while Firefox can handle 200 connections per client by default. What are WebSockets?
Is WebSocket frontend or backend? ›Using WebSockets to connect a backend with a frontend enables you to form long-lasting, full duplex connections for continuously streaming data. For the backend, the essential steps are: Import the socket.io library, create an node HttpServer instance, and use this instance to create a Socket.IO instance.
Is WebSocket better than rest? ›WebSockets have a low overhead per message. They're ideal for use cases that require low-latency, high-frequency communication. REST APIs have a higher message overhead compared to WebSockets. They're best suited for use cases where you want to create, retrieve, delete, or update resources.