Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

andfelzapata's avatar

Laravel echo listening is not receiving data

Hey everyone !

I'm building a real time notification feature for an app I'm working on. I' using Laravel 5.3, Node, Laravel Echo, Redis, and socket.io.

I have my events setup, node server listening on port 8888, redis pubsub is connection with node working. Everything on the backend is working.

One of my events:

class BecaCargada implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public $usuario;

    public $mensaje;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(Usuario $usuario, $mensaje)
    {
        $this->usuario = $usuario;
        $this->mensaje = $mensaje;
    }

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

When I generate this event it gets fired and publishes on the change successfully, I can see that on redis-cli and also on the nodeJS code thats subscribed and listening to the same channel.

The is the nodeJS code that listens on the same channel:

require ('dotenv').config();

const server = require('http').Server();

const io = require('socket.io')(server);

const Redis = require('ioredis');

const redis = new Redis();

redis.subscribe('channel-notificaciones');

redis.on('message', function (channel, message) {
    const notificacion = JSON.parse(message);
    const emmitChannel = `${channel}:${notificacion.event}`;
    console.log(`Canal: ${emmitChannel}`);
    io.emit(emmitChannel, notificacion.data);
});

server.listen({
    host: process.env.NOTIFICACIONES_SOCKET_HOST,
    port: process.env.NOTIFICACIONES_SOCKET_PORT
});

And for my js code I only have this right now:

import Echo from "laravel-echo";

window._ = require('lodash');

window.io = require("socket.io-client");

/**
 * 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.
 */
const echo = window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: `${process.env.APP_URL}:${process.env.NOTIFICACIONES_SOCKET_PORT}`
});


echo.channel('channel-notificaciones')
    .listen('BecaCargada', (e) => {
        console.log(e);
});

After running gulp and refreshing, I open another tab and trigger the event. If I open dev tools and look at the frames tab in the socket connection I can see the incoming events clearly, channel:EventName, payload.

But nothing shows on the console from the console.log(e) code. I've inspected the echo variable and everything seems ok, the namespace, the channel.

Any thoughts on what could be wrong ?

Thanks and happy coding =)

0 likes
28 replies
khaledSMQ's avatar

yesterday i face the same problem and i could figure out where is the problem, i end up to call listen method after all the dom is loaded.

also make sure in your blade file to load socket.io before app.js

khaledSMQ's avatar

Your welcome , sorry for late update. i think the problem is you have to listen for the jobs by running

php artisan queue:listen

andfelzapata's avatar

The events from the server are getting to the browser with no problem. I think the problem is with:

echo.channel('channel-notificaciones')
    .listen('BecaCargada', (e) => {
        console.log(e);
});

That piece of code is not doing anything, however, messages from the server to the browser are working, the browser is receiving data.

If I open dev tools and inspect the socket's frames, is see the incoming data.

khaledSMQ's avatar

What about

echo.channel('channel-notificaciones')
    .listen('BecaCargada', function(e) {
        console.log(e);
});

khaledSMQ's avatar

also in the frame you can see the entire event namespace or just a number ?

khaledSMQ's avatar

Hi @andfelzapata i think the missing part in your node server

// need to add 'channel' like bellow 
io.emit(emmitChannel, channel, notificacion.data);


// update

    const notificacion = JSON.parse(message);
    const emmitChannel = notificacion.event;
    io.emit(emmitChannel, channel, notificacion.data);

andfelzapata's avatar

I think a good idea would be to read Echo's source code. I'm planning on doing that soon. I'll update anything I find.

geraldarcega's avatar

I agree @andfelzapata, will do the same and also post an update if I got something.

@khaledSMQ I have exactly the same issue as the op. I'm just asking if there are any other options or set up that we have forgotten (based on the code that op posted) to include on either node server or in Echo.

andfelzapata's avatar

Testing plain io code works:

var socket = io(`${process.env.APP_URL}:${process.env.NOTIFICACIONES_SOCKET_PORT}`);

socket.on(`channel-notificaciones:App\\Events\\Notificaciones\\BecaCargada`, function (data) {
    console.log(data);
});
geraldarcega's avatar

I think I got something, this is only my initial findings, take a look at the generated Echo js, in my case line 271 to 284; { key: 'on', value: function on(event, callback) { var _this2 = this; var listener = function listener(channel, data) { if (_this2.name == channel) { callback(data); } }; this.socket.on(event, listener); this.bind(event, listener); } } Try to check the value of the listener parameter (channel, data), based on the condition in the IF statement, the channel must be a string, but what I get is Object, and the data is undefined, which is I think that the channel is not being past in the listener but only the data is being past, that's why the callback never fires.

andfelzapata's avatar

I think I'm going to give up one Echo for now. I've read the source and found something that doesn't add up when attaching the channel and event to the socket.io instance. With more reading about Echo and socket.io itself things might get clearer but I think we might be weak in websocket concepts.

This is the test code I have with Echo and regular 'on' event:

const echo = new Echo({
    broadcaster: 'socket.io',
    connector: 'socket.io',
    host: `${process.env.APP_URL}:${process.env.NOTIFICACIONES_SOCKET_PORT}`,
});

echo.channel('channel-notificaciones')
    .listen('.App.Events.Notificaciones.BecaCargada', function(data) {
        console.log(data);
    });

console.log({echo});

var socket = io(`${process.env.APP_URL}:${process.env.NOTIFICACIONES_SOCKET_PORT}`);

socket.on(`channel-notificaciones:App\\Events\\Notificaciones\\BecaCargada`, function (data) {
    console.log(data);
}).on('channel-notificaciones:App\\Events\\Notificaciones\\AccionCambioEstado', function (data) {
    console.log(data);
});

console.log({socket});

When echo instance receives the channel and the event name, either by passing the full class name with namespaces '.App.Events.Notificaciones.BecaCargada' or by passing a namespace to the echo constructor and passing just the class name to the liste event.

In the code above I'm printing to console both the echo instance and the socket.io. After inspecting those objects a little I found out something that might be the issue, but I'm not sure.

The listeners attached to the 'io' socket events work. Thy log the payload from the sever with no problems.

The echo instance holds a reference to a socket.io instance in a property called connector. (Echo's source code is really good by the way, very easy to follow). Every socket.io instance has a list of callbacks, which are the vents attached to the channels.

Any event attached to a socket.io instance by doing:

socket.on(`channel-notificaciones:App\\Events\\Notificaciones\\BecaCargada`, function (data) {
    console.log(data);
}).on('channel-notificaciones:App\\Events\\Notificaciones\\AccionCambioEstado', function (data) {
    console.log(data);
});

Will result in an array of callbacks to responde to data coming from the server. In this case, with the socket.io plain instance, contains two callbacks:

$channel-notificaciones:App\Events\Notificaciones\AccionCambioEstado

and

$channel-notificaciones:App\Events\Notificaciones\BecaCargada

And that matches the channel and event I get from the server for each type of event.

Now, inspecting the callbacks property on the socket.io instance inside the connector property of echo, it's very different. It only has the event name and not the channel:event signature, just 'App\Events\Notificaciones\BecaCargada' for this example.

Again, there might be something missing that we're not seeing at the moment, but I tried passing arguments and different orders and also passing the full channel:event string as argument to echo's listen method but no luck niether. I'm going to try again tomorrow see If I can get it to work, if not I'm going to try out the larave-echo-server I mentioned earlier. If that doesn't work, then I'l just listen for events using plain socket.io 'on' events.

Hopes this helps.

1 like
khaledSMQ's avatar
Level 6

@andfelzapata , @andfelzapata here is my full code and it's working i have tested

// /etc/supervisor/conf.d/laravel-worker.conf

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/vagrant/Code/Laravel/artisan queue:work redis --tries=3
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/home/vagrant/Code/Laravel/storage/logs/worker.log

// from https://laravel.com/docs/5.3/queues#supervisor-configuration


// .env

APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://homestead.app
SOCKET_PORT=6001

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_DRIVER=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

PUSHER_APP_ID=
PUSHER_KEY=
PUSHER_SECRET=


// server.js
require('dotenv').config();

const server = require('http').Server();

const io = require('socket.io')(server);

const Redis = require('ioredis');

const redis = new Redis();

redis.subscribe('all-channel');

console.log(process.env.SOCKET_PORT);

redis.on('message', function (channel, message) {
    const event = JSON.parse(message);
    io.emit(event.event, channel, event.data);
});

server.listen({
    port: process.env.SOCKET_PORT
});



// bootstrap.js
import Echo from "laravel-echo"

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: 'http://homestead.app:6001'
});


// home.blade.php
 
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="{{ elixir('js/app.js') }}"></script>

<script>

    document.onreadystatechange = () => {
        if (document.readyState === 'complete') {
            console.log("doc is ready");
            Echo.channel('all-channel').listen('ServerCreated', function(e) {
                console.log(e);
            });
        }
    };

</script>



/// route/web.php


Route::get('publish', function () {
    $data = [
        'type'    => 'erhelloror',
        'title'   => 'new article has been published',
        'message' => 'check it out',
        'url'     => 'url',
    ];
    event(new \App\Events\ServerCreated($data));
    return 'done';
});



/// App\Events\ServerCreated
// event

class ServerCreated implements ShouldBroadcast
{

    use InteractsWithSockets, SerializesModels;

    public $data;


    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(array $data = [])
    {
        $this->data = $data;
    }


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

}


don't forget to run

npm run dev
5 likes
andfelzapata's avatar

@khaledSMQ that worked with a slight change.

There's no need for the document.onreadystatechange. I updated part to my node server code, and added the channel as second argument. On the front end I had to specify the event namespace in the Echo constructor.

Thank you very much =)

1 like
geraldarcega's avatar

@khaledSMQ it works! So by adding the additional parameter in emit on the nodejs server it works like a charm.

io.emit(event.event, **channel**, event.data);

Thank you very much!

1 like
ignasbernotas's avatar

Did anyone manage to solve this? I'd like to stick to echo since I need private channel support, but this is a major issue.

Actually, in my case, I didn't realize that the Echo client has a default namespace set to App\Events. When using broadcastAs() in your events, you may want to set your Echo client namespace to an empty string.

let socket = new Echo({
  broadcaster: 'socket.io',
  namespace: '',
  host: 'localhost' + ':6001'
});
1 like
Heyaj05's avatar

@khaledSMQ when you access your env file in javascript like that isn't it a bad security practice?

Asking because I want to do something like that for the javascript to access my google api key but also dont want people to get access to my database password

Thank you

khaledSMQ's avatar

@Heyaj05 Thanks for asking,

Since you are working in back-end to back-end calls there will be no problems or any security problems just make sure if you are in production exceptions are not exposed to public in case there is any error UnhandledException thrown

Please or to participate in this conversation.