How to Determine User Online Status & Last Seen in Laravel

in Laravel, we can easily determine the user is online or not. In this article, we will learn about how to detect a user is online or offline and store last seen data. Let’s start:

Note: Last tested on Laravel 8.9.0.

Table of Contents

  1. Install Laravel and Basic Configurations
  2. Modify User Table
  3. Create a Middleware
  4. Add Middleware to Kernel
  5. Check Online Status in Controller
  6. Check Online Status in Blade File
  7. Check Live Status Using jQuery

Install Laravel and Basic Configurations

Each Laravel project needs this thing. That’s why I have written an article on this topic. Please see this part from here: Install Laravel and Basic Configurations.

Modify User Table

We need to add one column in the users table called last_seen. Open users table migration file from database>migrations folder and in the up() functions add like this:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->timestamp('last_seen')->nullable();
        $table->rememberToken();
        $table->timestamps();
    });
}

Now migrate the migrations:

php artisan migrate

For an existing project, you can just add last_seen column to the users table.

Create a Middleware

Create a middleware named LastUserActivity by typing this command:

php artisan make:middleware LastUserActivity

Now open the middleware LastUserActivity.php from app>Http>Middleware and paste this code:

LastUserActivity.php
<?php

namespace App\Http\Middleware;

use App\User;
use Closure;
use Auth;
use Cache;
use Carbon\Carbon;

class LastUserActivity
{
    public function handle($request, Closure $next)
    {
        if (Auth::check()) {
            $expiresAt = Carbon::now()->addMinutes(1); // keep online for 1 min
            Cache::put('user-is-online-' . Auth::user()->id, true, $expiresAt);

            // last seen
            User::where('id', Auth::user()->id)->update(['last_seen' => (new \DateTime())->format("Y-m-d H:i:s")]);
        }

        return $next($request);
    }
}

In the middleware, we’re checking the user is active or not.

Add Middleware to Kernel

Go to app>Http and open Kernel.php. We have to add \App\Http\Middleware\LastUserActivity::class, line to $middlewareGroups like this:

Kernel.php
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \App\Http\Middleware\LastUserActivity::class,
    ],

    'api' => [
        'throttle:60,1',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

Check Online Status in Controller

We have done all the tasks. Now we can check the online status in the controller:

Create a controller named UserController:

php artisan make:controller UserController

Open the controller from app>Http>Controllers and paste this code:

UserController.php
<?php

namespace App\Http\Controllers;

use App\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Cache;

class UserController extends Controller
{
    /**
     * Show user online status.
     */
    public function index()
    {
        $users = \App\Models\User::all();
        return view('users', compact('users'));
    }

    /**
     * Show user online status.
     */
    public function status()
    {
        $users = User::all();

        foreach ($users as $user) {

            if (Cache::has('user-is-online-' . $user->id))
                echo $user->name . " is online. Last seen: " . Carbon::parse($user->last_seen)->diffForHumans() . " 
"; else { if ($user->last_seen != null) { echo $user->name . " is offline. Last seen: " . Carbon::parse($user->last_seen)->diffForHumans() . "
"; } else { echo $user->name . " is offline. Last seen: No data
"; } } } } /** * Live status page. */ public function liveStatusPage() { $users = \App\Models\User::all(); return view('live', compact('users')); } /** * Live status. */ public function liveStatus($user_id) { // get user data $user = User::find($user_id); // check online status if (Cache::has('user-is-online-' . $user->id)) $status = 'Online'; else $status = 'Offline'; // check last seen if ($user->last_seen != null) $last_seen = "Active " . Carbon::parse($user->last_seen)->diffForHumans(); else $last_seen = "No data"; // response return response()->json([ 'status' => $status, 'last_seen' => $last_seen, ]); } }

Open routes>web.php and create a route:

web.php
Route::get('users', 'UserController@index');
Route::get('status', 'UserController@status');
Route::get('live', 'UserController@liveStatusPage');
Route::get('live-status/{id}', 'UserController@liveStatus');

// Laravel 8.x & up
Route::get('users', [UserController::class, 'index']);
Route::get('status', [UserController::class, 'status']);
Route::get('live', [UserController::class, 'liveStatusPage']);
Route::get('live-status/{id}', [UserController::class, 'liveStatus']);

Now run the project by typing php artisan serve and visit the route to see the output.

Check Online Status in Blade File

We can also easily show online status in the blade file. Here’s the syntax:

@if(Cache::has('user-is-online-' . $user->id))
    <span class="text-success">Online</span>
@else
    <span class="text-secondary">Offline</span>
@endif

Let’s see a full example. From resources>views, open users.blade.php and paste this code:

users.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Users</div>
                <div class="card-body">
                    <div class="container">
                        <table class="table table-bordered">
                            <thead>
                            <tr>
                                <th>Name</th>
                                <th>Email</th>
                                <th>Status</th>
                                <th>Last Seen</th>
                            </tr>
                            </thead>
                            <tbody>
                            @foreach($users as $user)
                                <tr>
                                    <td>{{$user->name}}</td>
                                    <td>{{$user->email}}</td>
                                    <td>
                                        @if(Cache::has('user-is-online-' . $user->id))
                                            <span class="text-success">Online</span>
                                        @else
                                            <span class="text-secondary">Offline</span>
                                        @endif
                                    </td>
                                    <td>
                                        @if($user->last_seen != null)
                                            {{ \Carbon\Carbon::parse($user->last_seen)->diffForHumans() }}
                                        @else
                                            No data
                                        @endif
                                    </td>
                                </tr>
                            @endforeach
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Now login to your Laravel project to see the output like this:

Check Live Status Using jQuery

I’ve written a simple way to show live users online status. Create & open live.blade.php and paste this code:

live.blade.php
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Live Users Status</title>
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">

</head>
<body>

@extends('layouts.app')
@section('content')

{{-- jQuery --}}
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<div class="container" style="margin-top: 50px;">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Live Users Status</div>
                <div class="card-body">
                    <div class="container">
                        <table id="userTable" class="table table-bordered">
                            <thead>
                            <tr>
                                <th>Name</th>
                                <th>Email</th>
                                <th>Status & Last Seen</th>
                            </tr>
                            </thead>
                            <tbody>
                            @foreach($users as $user)
                                <tr>
                                    <td>{{$user->name}}</td>
                                    <td>{{$user->email}}</td>
                                    <td>
                                        <span id="status_{{$user->id}}"></span>
                                        <script>
                                            window.setInterval(function(){
                                                $.ajax({
                                                    url: "{{ url('live-status') }}/{{ $user->id }}",
                                                    method: 'GET',
                                                    success: function (result) {
                                                        console.log(result);
                                                        $('#status_{{$user->id}}').html("Status: " + result.status + "<br/>Last Seen: " + result.last_seen);
                                                    }
                                                });
                                            }, 10000); // call every 10 seconds
                                        </script>
                                    </td>
                                </tr>
                            @endforeach
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

The Output:

That’s it. Thanks for reading.