Laravel Integration Guide

Vask is fully compatible with Laravel Broadcasting and Laravel Echo.

Installation

We recommend following Laravel's broadcasting documentation to get setup.

Then you only need to set the environment variables to your vask app details.

Configuration

Environment Variables

Add your Vask credentials to your .env file:

BROADCAST_CONNECTION=pusher

PUSHER_APP_ID=your_app_id
PUSHER_APP_KEY=your_app_id
PUSHER_APP_SECRET=your_app_secret
PUSHER_HOST=wss.vask.dev
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1

Broadcasting Events

Creating a Broadcast Event

Create an event that implements ShouldBroadcast:

<?php

namespace App\Events;

use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Message $message,
        public string $userName
    ) {}

    public function broadcastOn(): Channel
    {
        return new Channel('chat.' . $this->message->room_id);
    }

    public function broadcastAs(): string
    {
        return 'message.sent';
    }

    public function broadcastWith(): array
    {
        return [
            'id' => $this->message->id,
            'content' => $this->message->content,
            'user' => $this->userName,
            'created_at' => $this->message->created_at->toISOString(),
        ];
    }
}

Triggering Events

Broadcast events from your controllers or anywhere in your application:

use App\Events\MessageSent;

// In a controller method
public function sendMessage(Request $request)
{
    $message = Message::create([
        'room_id' => $request->room_id,
        'user_id' => auth()->id(),
        'content' => $request->content,
    ]);

    // Broadcast the event
    broadcast(new MessageSent(
        $message,
        auth()->user()->name
    ));

    return response()->json($message);
}

// Or use the event() helper
event(new MessageSent($message, $userName));

// For immediate broadcasting (bypass queue)
broadcast(new MessageSent($message, $userName))->toOthers();

Client-Side Setup

Configure Laravel Echo

Initialize Echo in your bootstrap.js or app.{js,ts,tsx} file:

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,
    wsHost: import.meta.env.VITE_PUSHER_HOST,
    wsPort: import.meta.env.VITE_PUSHER_PORT,
    wssPort: import.meta.env.VITE_PUSHER_PORT,
    forceTLS: true,
    encrypted: true,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});

Listening to Events

Subscribe to channels and listen for events in your components:

// Listen to a public channel
Echo.channel('chat.1').listen('.message.sent', (event) => {
    console.log('New message:', event);
    // Update your UI with the new message
    addMessageToChat(event);
});

// Listen to multiple events
Echo.channel('notifications')
    .listen('.user.joined', (e) => {
        console.log(e.userName + ' joined');
    })
    .listen('.user.left', (e) => {
        console.log(e.userName + ' left');
    });

// Leave a channel
Echo.leave('chat.1');

Private Channels

Authorization Routes

Define channel authorization logic in routes/channels.php:

<?php

use App\Models\User;
use App\Models\Room;
use Illuminate\Support\Facades\Broadcast;

// Private channel authorization
Broadcast::channel('room.{roomId}', function (User $user, int $roomId) {
    // Return true if user can access this room
    return $user->rooms()->where('room_id', $roomId)->exists();
});

// Return data with authorization
Broadcast::channel('user.{userId}', function (User $user, int $userId) {
    if ($user->id === $userId) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'avatar' => $user->avatar_url,
        ];
    }
    return false;
});

Broadcasting to Private Channels

use Illuminate\Broadcasting\PrivateChannel;

class OrderStatusUpdated implements ShouldBroadcast
{
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('user.' . $this->order->user_id);
    }
}

Listening to Private Channels

// Subscribe to a private channel
Echo.private('user.' + userId)
    .listen('.order.updated', (event) => {
        console.log('Order updated:', event.order);
    })
    .listen('.payment.received', (event) => {
        showNotification('Payment received: $' + event.amount);
    });

Presence Channels

Presence channels let you track who's online in real-time.

Authorization with User Data

Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
    if ($user->canJoinRoom($roomId)) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'avatar' => $user->avatar_url,
        ];
    }
});

Using Presence Channels

use Illuminate\Broadcasting\PresenceChannel;

class UserJoinedRoom implements ShouldBroadcast
{
    public function broadcastOn(): Channel
    {
        return new PresenceChannel('room.' . $this->roomId);
    }
}

Client-Side Presence

let onlineUsers = [];

Echo.join('room.' + roomId)
    .here((users) => {
        // Initial users in the channel
        console.log('Users online:', users);
        onlineUsers = users;
        updateUsersList(users);
    })
    .joining((user) => {
        // User joined the channel
        console.log(user.name + ' joined');
        onlineUsers.push(user);
        addUserToList(user);
    })
    .leaving((user) => {
        // User left the channel
        console.log(user.name + ' left');
        onlineUsers = onlineUsers.filter((u) => u.id !== user.id);
        removeUserFromList(user);
    })
    .error((error) => {
        console.error('Connection error:', error);
    })
    .listen('.message.sent', (event) => {
        // Listen to events on presence channel
        addMessageToChat(event);
    });

Troubleshooting

Connection Issues

Problem: "Failed to connect to Pusher".

Solution: Check your .env credentials and ensure PUSHER_HOST is set to wss.vask.dev.

Events Not Broadcasting

Problem: Events are not being received by clients.

Solutions:

  • Ensure your queue worker is running: php artisan queue:work.
  • Check that BROADCAST_CONNECTION=pusher in .env.
  • Verify the event implements ShouldBroadcast.
  • Check Laravel logs for broadcasting errors.

Private Channel Authorization Failing

Problem: 403 Forbidden when joining private channels.

Solutions:

  • Verify authorization logic in routes/channels.php.
  • Ensure user is authenticated before subscribing.
  • Check that channel names match between backend and frontend.
  • Verify CSRF token is being sent with authorization requests.

Debug Mode

Enable Pusher debug mode to see detailed logs:

window.Echo = new Echo({
    // ... other config
    enabledTransports: ['ws', 'wss'],
    // Enable debug mode
    enableLogging: true,
});

// Also enable Pusher logging
Pusher.logToConsole = true;

Prefer raw markdown? View this page as markdown.