Getting started: Pub/Sub in Laravel
This guide will get you started with Ably Pub/Sub in Laravel 12.
It will take you through the following steps:
- Create a client and establish a connection to Ably with:
- Create an event to broadcast (publish) messages from the backend.
- Set up a frontend client to receive (subscribe) and publish messages to a channel.
Prerequisites
- Sign up for an Ably account.
- Create a new app, and create your first API key.
- Your API key will need the
publish
,presence
, andhistory
capabilities. - Install the Ably CLI:
npm install -g @ably/cli
- Run the following to log in to your Ably account and set the default app and API key:
ably login
ably apps switch
ably auth keys switch
- Install PHP version 8.2 or greater and Laravel version 12.0 or greater.
- Create a new Laravel project and install the Ably Broadcaster for Laravel:
# Create a new Laravel project
composer create-project laravel/laravel ably-laravel-quickstart
cd ably-laravel-quickstart
# Install the Ably Broadcaster for Laravel
composer require ably/laravel-broadcaster
# Setup API route
php artisan install:api
- Now run the two dev servers (PHP and Vite) in separate Terminal windows:
php artisan serve # http://localhost:8000
npm install
npm run dev
Step 1: Configure the Ably Laravel SDK
The Ably Laravel SDK integrates with Laravel's broadcasting system. You need to configure it to establish a connection with Ably.
First, add your Ably credentials to your .env
file:
1
2
BROADCAST_CONNECTION=ably
ABLY_KEY=demokey:*****
In Laravel 12, broadcasting is enabled by default. Verify that BroadcastServiceProvider
is included in bootstrap/providers.php
:
1
2
3
4
5
6
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\BroadcastServiceProvider::class,
];
Publish the broadcasting configuration file if it doesn't exist:
php artisan install:broadcasting --ably
This will create the config/broadcasting.php
file and add the Ably configuration automatically.
Step 2: Create the event that will be broadcast
To send events from Laravel to Ably, create an event file by running the following command in your terminal:
php artisan make:event PublicMessageEvent
This command will create a PublicMessageEvent.php
file in the app/Events
directory. Replace the content of the file with following to handle the broadcasting of messages to a public channel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* Event for broadcasting public messages.
*/
class PublicMessageEvent implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $channelName;
public $message;
/**
* Create a new event instance.
*/
public function __construct($channelName, $message)
{
$this->channelName = $channelName;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* @return array<\Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [new Channel($this->channelName)];
}
}
Step 3: Add an API route to broadcast
To handle API requests from frontend, open the routes/api.php
file and add following route:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Events\PublicMessageEvent;
Route::post('/public-event', function (Request $request) {
$channelName = $request->input('channelName');
$message = $request->input('message');
broadcast(new PublicMessageEvent($channelName, $message));
return response()->json(['success' => true, 'message' => 'Event broadcasted']);
})->middleware('throttle:60,1'); // 60 requests/minute are allowed.
This endpoint public-event
will accept POST requests with channelName
and message
parameters, and broadcast the event to the specified channel.
Step 4: Test the API route
To test the API route, first you need at least one client subscribed to the channel. You can use the Ably CLI to subscribe to a channel:
ably channels subscribe public:my-first-channel
Now you can publish a message to the channel using the API route you created in Step 3. You can use curl
or any HTTP client to send a POST request:
curl --location --request POST 'localhost:8000/api/public-event' \
--header 'Content-Type: application/json' \
--data-raw '{
"channelName":"my-first-channel",
"message":"A message sent from my first client!"
}'
Step 5: Frontend setup
Install Ably's Pub/Sub JavaScript SDK
, Ably's fork of laravel-echo
, and axios
in your Laravel project:
npm install @ably/laravel-echo ably axios
Create or update resources/js/bootstrap.js
to include Echo configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import axios from 'axios';
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// Configure Laravel Echo with Ably
import Echo from '@ably/laravel-echo';
import * as Ably from 'ably';
window.Ably = Ably;
window.Echo = new Echo({
broadcaster: 'ably',
key: import.meta.env.VITE_ABLY_KEY, // Add this to your .env file as VITE_ABLY_KEY
});
Step 6: Create a frontend file to listen for events
Create a new CSS stylesheet resources/css/echo.css
and add the Tailwind imports:
@tailwind base;
@tailwind components;
@tailwind utilities;
Now create a new Blade view file named echo.blade.php
in the resources/views
directory, which will be the page rendered in your browser as your front end client to publish and subscribe to a channel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!DOCTYPE html>
<html>
<head>
<title>Laravel Echo with Ably</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
@vite(['resources/css/app.css','resources/css/echo.css', 'resources/js/app.js'])
</head>
<body class="font-sans max-w-4xl mx-auto p-5 bg-gray-50 leading-relaxed">
<h1 class="text-slate-800 text-4xl mb-8 text-center font-bold tracking-tight">Laravel Echo with Ably Test</h1>
<form id="messageForm" class="my-5 p-5 bg-white rounded-lg shadow-sm">
<h3 class="text-slate-700 text-xl mb-4 font-semibold">Send a Message</h3>
<input type="text" id="channelName" placeholder="Channel name" value="my-first-channel"
class="w-48 px-4 py-3 m-1 border-2 border-gray-200 rounded-md text-sm bg-white transition-colors focus:outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-100">
<input type="text" id="messageInput" placeholder="Enter your message" required
class="w-48 px-4 py-3 m-1 border-2 border-gray-200 rounded-md text-sm bg-white transition-colors focus:outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-100">
<button type="submit" class="px-6 py-3 m-1 bg-blue-600 text-white border-none rounded-md text-sm font-semibold cursor-pointer transition-colors hover:bg-blue-700 active:translate-y-px">Send Message</button>
</form>
<div id="messages" class="border-2 border-gray-200 rounded-lg p-4 h-80 overflow-y-auto my-5 bg-white shadow-sm">
<p class="message py-2 border-b border-gray-100 text-gray-600"><strong>Listening for messages...</strong></p>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log('Echo instance:', window.Echo);
console.log('Attempting to join channel: my-first-channel');
const channel = Echo.channel('my-first-channel')
.subscribed(() => {
console.log('Successfully subscribed to channel');
})
.listenToAll((eventName, data) => {
console.log("Event :: " + eventName + ", data is :: " + JSON.stringify(data));
})
.listen('PublicMessageEvent', (data) => {
document.getElementById('messages').innerHTML +=
`<div class="message py-2 border-b border-gray-100 text-gray-600"><strong>Received:</strong> ${data.message}</div>`;
})
.error((err) => {
if (err?.statusCode === 401){
alert("You don't have the access to join this public room.");
} else {
alert("An error occurred while trying to join a public room, check the console for details.");
}
console.error(err);
});
// Handle form submission
document.getElementById('messageForm').addEventListener('submit', function(e) {
e.preventDefault();
const channelName = document.getElementById('channelName').value;
const message = document.getElementById('messageInput').value;
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
if (!message.trim()) {
alert('Please enter a message');
return;
}
// Send message to Laravel API
fetch('/api/public-event', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken,
'Accept': 'application/json'
},
body: JSON.stringify({
channelName: channelName,
message: message
})
})
.then(response => response.json())
.then(data => {
console.log('Message sent successfully:', data);
document.getElementById('messageInput').value = ''; // Clear the input
document.getElementById('messages').innerHTML +=
`<div class="message py-2 border-b border-gray-100 text-gray-600"><strong>Sent:</strong> ${message} (to ${channelName})</div>`;
})
.catch(error => {
console.error('Error sending message:', error);
alert('Error sending message. Check console for details.');
});
});
});
</script>
</body>
</html>
Add the route to serve the frontend file in routes/web.php
to expose this new file to the browser:
1
2
3
4
5
6
7
8
9
10
11
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/echo', function () {
return view('echo');
});
In your browser, open the url http://localhost:8000/echo
to see the frontend page.
Use curl
or any HTTP client to send a POST request, you should see the message appear in the #messages
div on the page:
curl --location --request POST 'localhost:8000/api/public-event' \
--header 'Content-Type: application/json' \
--data-raw '{
"channelName":"my-first-channel",
"message":"A message sent from my first client!"
}'

Next steps
Continue to explore the documentation with Laravel as the selected language:
Read more about the concepts covered in this guide:
- Read more about Ably Laravel Echo
- Fetch message history in your apps
- Learn more about Laravel Broadcasting
- Explore the Ably Laravel Broadcast app - a comprehensive example that builds upon this guide with features like:
- User authentication (registration + login)
- Public channels for guests
- Private channels with presence for authenticated users
- Typing indicators
- Multi-room support
You can also explore the Ably CLI further, or visit the Pub/Sub API references.