Skip to main content

Streaming AI Responses with Laravel and Ressonance

· 4 min read
Leonardo Lemos
Laravel FullStack Developer, Websockets Specialist

Token-by-token AI output — the little "typing" effect you get from ChatGPT — isn't a nice-to-have anymore, it's the expected UX for anything that talks to an LLM. And the wrong way to build it is polling an endpoint every few hundred milliseconds hoping the next chunk is ready.

The demo is a Laravel application using Ressonance but this can be achieved with any other language or any other reverb/pusher compatible websocket provider.

Prerequisites

  • A Laravel app with Laravel AI installed and at least one provider configured in config/ai.php (OpenAI, Anthropic, Ollama — any of them work, streaming isn't provider-specific).
  • A free Ressonance app (it's a drop-in Pusher-protocol replacement, so setup is just grabbing your app key/secret/host).

Step 1 — Point broadcasting at Ressonance

Ressonance speaks the same protocol as Laravel Reverb, so there's no new driver to install — you configure the reverb connection in config/broadcasting.php and point it at Ressonance's host instead of your own server:

'reverb' => [
'driver' => 'reverb',
'key' => env('REVERB_APP_KEY'),
'secret' => env('REVERB_APP_SECRET'),
'app_id' => env('REVERB_APP_ID'),
'options' => [
'host' => env('REVERB_HOST'),
'port' => env('REVERB_PORT', 443),
'scheme' => env('REVERB_SCHEME', 'https'),
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
],
],

And in .env, use the credentials from your Ressonance app dashboard:

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=your-app-id
REVERB_APP_KEY=your-app-key
REVERB_APP_SECRET=your-app-secret
REVERB_HOST="your-app.ressonance.com"
REVERB_PORT=443
REVERB_SCHEME=https

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

That's the entire backend infrastructure setup. No server to provision, no process to keep alive.


Step 2 — Install and configure Laravel Echo

npm install --save-dev laravel-echo pusher-js

Create resources/js/echo.js:

import Echo from 'laravel-echo';

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

window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});

Then import it from your main entry point, resources/js/app.js:

import './echo';

Why pusher-js if we're not using Pusher?

Ressonance and Reverb both implement the Pusher protocol, and laravel-echo's reverb broadcaster is built on top of the pusher-js client under the hood. You never talk to Pusher's servers — the wsHost config is what actually decides where the socket connects.


Step 3 — Broadcast AI tokens as they're generated

Laravel AI's agent()->stream() yields a sequence of stream events as the model responds. Each token arrives as a TextDelta event, and it exposes a broadcast() method — hand it a channel and it goes straight out over the wire:

use Illuminate\Broadcasting\Channel;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Streaming\Events\TextDelta;

use function Laravel\Ai\agent;

class TestingController extends Controller
{
public function index()
{
$stream = agent()->stream('Tell me a short story', provider: Lab::Ollama);

foreach ($stream as $event) {
if ($event instanceof TextDelta) {
$event->broadcast(new Channel('new-text-delta'));
}
}

return '';
}
}

Why check instanceof TextDelta?

A stream isn't only text — depending on what the agent is doing, you can also get events for tool calls, message boundaries, and so on. Filtering to TextDelta means you only broadcast the actual token chunks, not the plumbing around them.


Step 4 — Listen for tokens in the browser

First, make sure the compiled assets are actually loaded — add @vite to your view's <head>:

@vite('resources/js/app.js')

Then drop a text area to render into, and listen on the same channel you broadcast to:

<textarea id="stream-output" rows="20" readonly></textarea>

<script>
document.addEventListener("DOMContentLoaded", () => {
const streamOutput = document.getElementById('stream-output');

Echo.channel('new-text-delta')
.listen('.text_delta', (e) => {
streamOutput.value += e.delta;
});
});
</script>

Why the leading dot in .text_delta?

TextDelta::broadcast() sets a custom event name (text_delta) instead of relying on Laravel's default namespaced event name. Echo assumes any event name is namespaced under App.Events unless you tell it otherwise — the leading dot says "this is a raw event name, don't prefix it." Without it, Echo listens for an event that never arrives.

Why hand this off to Ressonance

Everything above works exactly the same way against a self-hosted Reverb server — Ressonance doesn't change a line of the code. What it removes is running that server yourself: no process to keep alive, no scaling it when concurrent streams spike, no TLS termination to configure. Since it speaks the same Pusher protocol Echo already expects, swapping in Ressonance is a config change, not a rewrite.

If you're already prototyping AI streaming locally and want it production-ready without standing up your own WebSocket infrastructure, Ressonance is built for exactly this.

What Are WebSockets? (A Developer Focused Guide to Real Time Apps)

· 5 min read
Victor Gazotti
Laravel FullStack Developer

The perspective I rarely see (and why I’m writing this)

Most “what are WebSockets” articles explain the API and stop there. That helps you demo a chat, but it does not help you ship real time features that survive load spikes, deploys, mobile networks, and annoying edge cases.

I’m writing this because, in 2026, WebSockets are not a novelty, they are a reliability problem you either solve once (well), or keep re learning in production. If you want real time UX without building a whole messaging infrastructure, you need the mental model, plus a checklist you can actually follow, and a platform that removes the sharp edges.

When WebSockets Become Infrastructure?

· 4 min read
Victor Gazotti
Laravel FullStack Developer

Real-time communication is no longer a feature. It is infrastructure.

I am writing this from a perspective that many teams only reach after pain. At first, WebSockets feel like an enhancement, live notifications, chat updates, dashboards. But at scale, WebSockets stop being product features and start becoming critical infrastructure.

If you are building modern applications with WebSockets, there is a moment where everything changes.

This is that moment.

How WebSockets Work (Deep Dive)

· 5 min read
Victor Gazotti
Laravel FullStack Developer

WebSockets are often described as “a persistent connection between client and server”, but that definition hides most of the complexity and the real power behind the protocol.

In this How WebSockets Work deep dive, I want to go beyond surface level explanations and break down what actually happens at the protocol, infrastructure, and architectural level. This perspective comes from building Ressonance, an open source WebSocket as a Service platform, and seeing firsthand where teams struggle when moving from request based systems to real time communication.

If you are building dashboards, notifications, collaborative tools, or any system that depends on real time communication, understanding how WebSockets really work is not optional.

SSE vs WebSockets

· 4 min read
Victor Gazotti
Laravel FullStack Developer

Real-time communication is no longer optional. Dashboards, notifications, collaborative tools, and live updates are now expected in modern applications. Yet one question keeps coming up among developers and architects: SSE vs WebSockets.

I’m writing this because most discussions oversimplify the topic. The truth is simple but often ignored: Server-Sent Events and WebSockets solve different real-time problems. Treating them as interchangeable usually leads to overengineering or painful rewrites later.

In this article, we’ll break down server sent events vs websockets, explore how each behaves in production, and help you choose the right strategy for scalable real-time communication.

Building a Real-Time Dashboard with Laravel and WebSockets

· 8 min read
Victor Gazotti
Laravel FullStack Developer

Real-time features are no longer a “nice to have.” Dashboards, notifications, live metrics, and collaborative tools are now expected behaviors in modern applications.

As Laravel developers, we’re in a great position: the ecosystem offers first-class support for WebSockets through Laravel Echo and Reverb. Still, many tutorials stop at theory or overused chat examples.

In this Laravel WebSockets tutorial, I want to share a practical, production-adjacent example: a real-time dashboard that updates totals instantly, without polling, using Echo and Reverb.

This is a hands-on guide aimed at developers who want to understand how WebSockets actually work in Laravel, not just copy-paste code.

Running Ressonance with docker

· 4 min read
Victor Gazotti
Laravel FullStack Developer

This article walks developers through running Ressonance self hosted using Docker, from local development to production-ready setups. It explains the architecture, exposed ports, and data persistence while highlighting why Ressonance offers a unique, open, and unopinionated approach to real-time infrastructure. Whether you want full control or a smooth path to the cloud, the post shows how to get started quickly and confidently — with a free tier available to explore real-time at your own pace.

Ressonance.com is now open source!

· 6 min read
Victor Gazotti
Laravel FullStack Developer

Ressonance is now open source, and that changes everything. In this post, we share why we chose transparency over black boxes, how building in public shapes every technical decision we make, and what this means for developers building real-time applications with Laravel and WebSockets. From the hidden complexity of scaling real-time infrastructure to the concrete benefits of open source trust and collaboration, this article explains the philosophy behind Ressonance and invites you to experience it yourself through our free tier.

What is the difference between channels and events?

· 6 min read
Victor Gazotti
Laravel FullStack Developer

Learn the difference between channels and events in WebSockets, why it matters for real-time apps, and how Ressonance helps you build faster with a generous free tier.

This post offers a clear, actionable explanation of these two essential real-time concepts. Perfect for developers building chat apps, dashboards, or collaborative tools, it breaks down how channels group communication streams and how events describe meaningful actions within them.

You’ll learn common mistakes to avoid, best practices to follow, and how to implement real-time features with ease. We also introduce Ressonance, a modern WebSocket platform with a generous free tier, secure channels, real-time analytics, and simple SDKs.

Whether you're just starting with real-time architecture or improving an existing system, this guide will help you build smarter, faster, and more scalable applications.