Analytics - v1.0.0-beta1

Realtime Visitors

The Realtime Visitors component displays a live count of currently active visitors on your site.

Basic Usage

<livewire:artisanpack-analytics::realtime-visitors />

Properties

Property Type Default Description
siteId ?int null Site ID for multi-tenant
minutes int 5 Minutes to consider "active"
refreshInterval int 30 Seconds between refreshes

Usage Examples

Custom Time Window

<livewire:artisanpack-analytics::realtime-visitors
    :minutes="10"
/>

Faster Refresh Rate

<livewire:artisanpack-analytics::realtime-visitors
    :refresh-interval="15"
/>

Multi-Tenant

<livewire:artisanpack-analytics::realtime-visitors
    :site-id="$site->id"
/>

Data Structure

The component provides:

$this->realtimeData = [
    'active_visitors' => 23,      // Currently active visitors
    'active_pages' => [           // Pages being viewed
        [
            'path' => '/products',
            'title' => 'Products',
            'visitors' => 8,
        ],
        [
            'path' => '/',
            'title' => 'Home',
            'visitors' => 5,
        ],
        // ...
    ],
    'sources' => [                // Current traffic sources
        [
            'source' => 'google',
            'visitors' => 12,
        ],
        [
            'source' => 'direct',
            'visitors' => 8,
        ],
    ],
    'devices' => [                // Device breakdown
        'desktop' => 15,
        'mobile' => 6,
        'tablet' => 2,
    ],
];

Methods

loadData()

Refresh the realtime data:

$this->loadData();

refreshData()

Called automatically based on refreshInterval.

Auto-Refresh

The component automatically refreshes using Livewire's polling:

<div wire:poll.{{ $refreshInterval }}s>
    {{-- Content --}}
</div>

Configuration

Enable/disable realtime tracking in config:

// config/artisanpack/analytics.php
'dashboard' => [
    'realtime_enabled' => env('ANALYTICS_REALTIME_ENABLED', true),
    'realtime_interval' => env('ANALYTICS_REALTIME_INTERVAL', 30),
],

Customization

Publishing Views

php artisan vendor:publish --tag=analytics-views

Edit resources/views/vendor/artisanpack-analytics/livewire/widgets/realtime-visitors.blade.php.

Custom Display

Example custom view:

<div wire:poll.{{ $refreshInterval }}s class="card bg-base-100 shadow">
    <div class="card-body">
        {{-- Main counter --}}
        <div class="text-center mb-6">
            <div class="flex items-center justify-center gap-2">
                <span class="relative flex h-3 w-3">
                    <span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-success opacity-75"></span>
                    <span class="relative inline-flex rounded-full h-3 w-3 bg-success"></span>
                </span>
                <span class="text-4xl font-bold">{{ $realtimeData['active_visitors'] }}</span>
            </div>
            <p class="text-gray-500 mt-1">Active visitors right now</p>
        </div>

        {{-- Active pages --}}
        @if (!empty($realtimeData['active_pages']))
            <div class="mt-4">
                <h4 class="font-medium mb-2">Currently viewing:</h4>
                <ul class="space-y-1">
                    @foreach (array_slice($realtimeData['active_pages'], 0, 5) as $page)
                        <li class="flex justify-between text-sm">
                            <span class="truncate">{{ $page['title'] ?: $page['path'] }}</span>
                            <span class="badge badge-sm">{{ $page['visitors'] }}</span>
                        </li>
                    @endforeach
                </ul>
            </div>
        @endif
    </div>
</div>

Animated Counter

Add animation to the visitor count:

<div
    x-data="{ count: {{ $realtimeData['active_visitors'] }} }"
    x-init="$watch('$wire.realtimeData.active_visitors', value => {
        const start = count;
        const end = value;
        const duration = 500;
        const startTime = performance.now();

        const animate = (currentTime) => {
            const elapsed = currentTime - startTime;
            const progress = Math.min(elapsed / duration, 1);
            count = Math.round(start + (end - start) * progress);

            if (progress < 1) {
                requestAnimationFrame(animate);
            }
        };

        requestAnimationFrame(animate);
    })"
>
    <span class="text-4xl font-bold" x-text="count"></span>
</div>

Integration Examples

Header Badge

Display active visitors in your site header:

<nav class="navbar">
    <div class="flex-1">
        <a href="/" class="text-xl">My Site</a>
    </div>
    <div class="flex-none">
        <livewire:artisanpack-analytics::realtime-visitors />
    </div>
</nav>

Dashboard Card

<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
    {{-- Realtime visitors --}}
    <div class="md:col-span-1">
        <livewire:artisanpack-analytics::realtime-visitors />
    </div>

    {{-- Stats cards --}}
    <div class="md:col-span-3">
        <livewire:artisanpack-analytics::stats-cards />
    </div>
</div>

Minimal Badge Display

<div class="indicator">
    <span class="indicator-item badge badge-success">
        {{ $realtimeData['active_visitors'] }}
    </span>
    <span>Active now</span>
</div>

Performance Considerations

  1. Refresh Interval: Don't set too low (< 10 seconds) to avoid server load
  2. Disable When Hidden: Consider stopping polling when tab is not visible
<div
    x-data="{ visible: true }"
    x-init="
        document.addEventListener('visibilitychange', () => {
            visible = !document.hidden;
        })
    "
    x-show="visible"
    wire:poll.{{ $refreshInterval }}s
>
    {{-- Content only refreshes when tab is visible --}}
</div>
  1. Caching: Realtime data is cached briefly to reduce database queries