Skip to main content
Integrate the Char agent into your Laravel application with Livewire. The key is placing the agent outside your Livewire components so it persists across updates.

Installation

Basic Usage

Place the agent in your layout, outside Livewire components:
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
    <meta name="id-token" content="{{ auth()->user()?->id_token }}">
    @vite(['resources/css/app.css', 'resources/js/app.js'])
    @livewireStyles
</head>
<body>
    <div>
        {{ $slot }}
    </div>

    {{-- Agent outside Livewire components persists --}}
    <char-agent id="chat-widget"></char-agent>

    @livewireScripts

    <script type="module">
        import '@mcp-b/char/web-component';

        document.addEventListener('livewire:navigated', () => {
            const agent = document.getElementById('chat-widget');
            const idToken = document.querySelector('meta[name="id-token"]')?.content;
            const clientId = document.querySelector('meta[name="client-id"]')?.content;

            if (agent && idToken && clientId) {
                agent.connect({ idToken, clientId });
            }
        });

        // Also connect on initial load
        document.addEventListener('DOMContentLoaded', () => {
            const agent = document.getElementById('chat-widget');
            const idToken = document.querySelector('meta[name="id-token"]')?.content;
            const clientId = document.querySelector('meta[name="client-id"]')?.content;

            if (agent && idToken && clientId) {
                agent.connect({ idToken, clientId });
            }
        });
    </script>
</body>
</html>

With Laravel Socialite

If using Socialite for OAuth:
// app/Http/Controllers/Auth/OAuthController.php
class OAuthController extends Controller
{
    public function callback(string $provider)
    {
        $socialiteUser = Socialite::driver($provider)->user();

        // Store the ID token in session or user model
        session(['id_token' => $socialiteUser->token]);

        // Or store on user
        $user = User::updateOrCreate(
            ['email' => $socialiteUser->email],
            ['id_token' => $socialiteUser->token]
        );

        auth()->login($user);

        return redirect('/dashboard');
    }
}

Alpine.js Integration

If using Alpine.js alongside Livewire:
<char-agent
    id="chat-widget"
    x-data
    x-init="$el.connect({ idToken: '{{ auth()->user()?->id_token }}', clientId: '{{ config('services.char.client_id') }}' })"
></char-agent>

With Livewire Component

Create a Livewire component for dynamic token updates:
// app/Livewire/CharAgent.php
<?php

namespace App\Livewire;

use Livewire\Component;

class CharAgent extends Component
{
    public ?string $idToken = null;

    public function mount()
    {
        $this->idToken = auth()->user()?->id_token;
    }

    public function render()
    {
        return view('livewire.char-agent');
    }
}
{{-- resources/views/livewire/char-agent.blade.php --}}
<div wire:ignore>
    @if($idToken)
        <char-agent
            id="chat-widget"
            x-data
            x-init="$el.connect({ idToken: '{{ $idToken }}', clientId: '{{ config('services.char.client_id') }}' })"
        ></char-agent>
    @endif
</div>
Use wire:ignore to prevent Livewire from updating the agent element, which would disconnect it.

SSR with Ticket Exchange

For enhanced security, exchange tokens server-side:
// app/Services/CharService.php
<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;

class CharService
{
    public function getTicket(string $idToken): ?array
    {
        $response = Http::withToken($idToken)
            ->post('https://api.usechar.ai/api/auth/ticket', [
                'client_id' => config('services.char.client_id'),
            ]);

        if ($response->successful()) {
            return $response->json();
        }

        return null;
    }
}
@php
    $ticketAuth = app(App\Services\CharService::class)->getTicket(auth()->user()->id_token);
@endphp

@if($ticketAuth)
    <char-agent
        id="chat-widget"
        x-data
        x-init="$el.connect({ ticketAuth: {{ json_encode($ticketAuth) }} })"
    ></char-agent>
@endif

See Also