Getting started: Pub/Sub in Laravel
This guide will get you started with Ably Pub/Sub in Laravel 12.
You'll learn how to create a client and establish a connection to Ably using the Laravel Broadcaster service provider and Echo (a Laravel Echo fork with native Ably integration). You'll also cover creating an event to broadcast messages from the backend and setting up a frontend client to receive and publish messages to a channel.
Prerequisites
- Sign up for an Ably account.
- Create a new app, and create your first API key in the API Keys tab of the dashboard.
- Your API key will need the
publish
,presence
, andhistory
capabilities. - 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
(Optional) Install Ably CLI
The Ably CLI provides a command-line interface for managing your Ably Pub/Sub and Chat applications directly from your terminal.
- 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
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 PHP as the selected framework:
- Read more about Ably Laravel Echo.
- 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.