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

hilmi's avatar
Level 1

How to Integrate Pusher private channel in Laravel 10?

I'm creating a chat feature using pusher private channel. When someone from the same thread sends a message, other people in that thread receive the message.

I have created the code as below, but I get error messages:

  • Uncaught Options object must provide a cluster
  • Uncaught ReferenceError: pusher is not defined

Following are the codes that I have created:

ChatController.php

public function store(Request $request)
{
    $thread = Thread::findOrFail($request->thread_id);

    Message::create([
        'thread_id' => $thread->id,
        'user_id' => Auth::id(),
        'body' => $request->body,
    ]);

    event(new NewMessage($thread->id, $request->body));

    return response()->json([
        'status' => 'success',
        'message' => 'Your message has been sent successfully.',
    ]);
}

NewMessage.php

<?php

namespace App\Events;

use App\Models\User;
use Cmgmyr\Messenger\Models\Thread;
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 NewMessage implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $thread_id;
    public $message;

    public function __construct($thread_id, $message)
    {
        $this->thread_id = $thread_id;
        $this->message = $message;
    }

    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('chat.' . $this->thread_id)
        ];
    }
}

routes/channels.php

Broadcast::channel('private-chat.{threadId}', function (User $user, Thread $threadId) {
    return $threadId->hasParticipant($user->id);
});

resources/js/bootstrap.js

import axios from 'axios';
window.axios = axios;

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

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,
    wsHost: 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'],
    authorizer: (channel) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(false, response.data);
                })
                .catch(error => {
                    callback(true, error);
                });
            }
        };
    },
});

window.Pusher.logToConsole = false;
window.pusher = new window.Pusher(import.meta.env.VITE_PUSHER_APP_KEY, {
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    authEndpoint: `/broadcasting/auth`,
    auth: {
        headers: {
        "Access-Control-Allow-Origin": "*",
        
        }
    }
});

resources/js/app.js

import './bootstrap';

vite.config.js

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});

view

@vite('resources/js/app.js')
<script src="https://js.pusher.com/8.2.0/pusher.min.js"></script>
<script type="module">
    Pusher.logToConsole = true;

    var thread_id = new URL(window.location.href).searchParams.get('id');
    var user_id = "{{ auth()->user()->id }}";

    var thread = pusher.subscribe('private-chat.' + thread_id);

    thread.bind('NewMessage', function(data) {
        alert('New message');
    });
</script>

How to fix it?

Note: i also use laravel messenger package: https://github.com/cmgmyr/laravel-messenger

0 likes
5 replies
gych's avatar

Change this part of code in your view, this should get rid off pusher undefined error

var thread = window.pusher.subscribe('private-chat.' + thread_id);

On the backend you're broadcasting on chat but on the frontend you subcribe to private-chat

  new PrivateChannel('private-chat.' . $this->thread_id)

Does VITE_PUSHER_APP_CLUSTER contain the correct value?

hilmi's avatar
Level 1

@gych now I get this error message: Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')

PUSHER_APP_CLUSTER=mt1

VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

gych's avatar

@hilmi Can you try to change this in your bootstrap js file, Pusher is already available so no need to use window.Pusher there.

Pusher.logToConsole = false;
window.pusher = new Pusher(import.meta.env.VITE_PUSHER_APP_KEY, {
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    authEndpoint: `/broadcasting/auth`,
    auth: {
        headers: {
        "Access-Control-Allow-Origin": "*",
        
        }
    }
});

Have you tried subscribing to the channel with Echo instead of pusher?

hilmi's avatar
Level 1

@gych

import axios from 'axios';
window.axios = axios;

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

import Echo from 'laravel-echo';

import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: '21fa0caff88313',
    cluster: 'mt1',
    forceTLS: true,
    encrypted: true,
    authorizer: (channel) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(false, response.data);
                })
                .catch(error => {
                    callback(true, 'error');
                });
            }
        };
    },
});

Pusher.logToConsole = false;
window.pusher = new Pusher('21fa0caff8831', {
    cluster: 'mt1',
    authEndpoint: `/broadcasting/auth`,
    auth: {
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Content-Type": "application/json"
        },
    }
});

console.log('pusher.js loaded');

I don't get that error when I enter the pusher credentials directly without calling it from .env. But now I get an error message like this:

enter image description here

gych's avatar

@hilmi This error means that the auth endpoint you use /broadcasting/auth does not return a valid response. So double check the auth and see if everything is set up correctly.

It might also be easier to set everything up without auth first and if that works well you can then implement the auth.

To check for why its not working when you import the env variables try to console log the variables in your bootstrap file to check if the log has the expected values.

Please or to participate in this conversation.