syriable / laravel-user-context
User presence, timezone awareness, locale context and login metadata for Laravel — know who is online, where they are, and what time it is for them.
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- barryvdh/laravel-debugbar: ^4.2
- fakerphp/faker: ^1.24.1
- geoip2/geoip2: ^3.1
- larastan/larastan: ^3.9.6
- laravel/boost: ^2.4
- laravel/pao: ^1.0.6
- laravel/pint: dev-feat/blade-support
- laravel/sail: ^1.58.0
- mockery/mockery: ^1.6.12
- nunomaduro/collision: ^8.9.4
- orchestra/testbench: ^10.0||^11.0
- pestphp/pest: ^4.7.0
- pestphp/pest-plugin-laravel: ^4.1.0
- pestphp/pest-plugin-type-coverage: ^4.0.4
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- rector/rector: ^2.4.2
Suggests
- geoip2/geoip2: Required to use the MaxMind GeoLite2 local database geolocation driver (^3.0).
This package is auto-updated.
Last update: 2026-07-18 19:00:32 UTC
README
Know who is online, where they are, and what time it is for them — presence, timezone awareness, locale context and login metadata for any Laravel app.
A lightweight, database-driven foundation package. No Redis, no heavy dependencies — presence works without a queue worker; geolocation lookups are queued by default so they never block the request path.
$user->isOnline(); // true $user->presence()->lastSeen(); // CarbonImmutable|null $user->location()->countryName(); // "Sweden" (from ISO country code) $user->timezone()->now(); // CarbonImmutable in the user's zone $user->greeting(); // "Good afternoon" // A user in New York checking the best time to message a user in Shanghai: $comparison = $newYorkUser->timeFor($shanghaiUser); $comparison->formattedOffset(); // "+12:00" $comparison->isNight(); // true → maybe wait $comparison->isConvenientTime(); // false → not a good time to ping
Requirements
- PHP 8.3+
- Laravel 11, 12 or 13
Installation
composer require syriable/laravel-user-context
Publish and run the migrations:
php artisan vendor:publish --tag="laravel-user-context-migrations"
php artisan migrate
Optionally publish the config file:
php artisan vendor:publish --tag="laravel-user-context-config"
Add the trait to your authenticatable model:
use Syriable\UserContext\Concerns\HasUserContext; class User extends Authenticatable { use HasUserContext; }
Register the tracking middleware so activity is recorded on each request. In
bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ \Syriable\UserContext\Http\Middleware\TrackUserContext::class, ]); })
That's it — logins, logouts, presence, locale and (optionally) geolocation are now tracked automatically.
Documentation
Publish the config (php artisan vendor:publish --tag="laravel-user-context-config")
and read the comments in config/user-context.php for every key. Notable defaults:
| Key | Default | Why |
|---|---|---|
ip.privacy |
anonymize |
Store /24 (IPv4) / /48 (IPv6) — not raw IPs |
geolocation.driver |
null |
No external lookup until you opt into ipinfo / maxmind / ipapi |
queue.enabled |
true |
Geo lookups never block the request that recorded activity |
routes.middleware |
web, auth, throttle:60,1 |
Heartbeat is auth-gated and rate-limited |
use Syriable\UserContext\Facades\UserContext; UserContext::isOnline($user); UserContext::timezoneFor($user)->now(); UserContext::for($user); // ContextSnapshot
Usage at a glance
Presence
$user->isOnline(); // bool $user->presence()->status(); // "online" | "offline" $user->presence()->lastSeen(); // ?CarbonImmutable $user->presence()->lastLogin(); // ?CarbonImmutable UserContext::online()->count(); // query builder over online users
Keep a browser tab "online" with the bundled heartbeat component:
<x-user-context::heartbeat />
Timezone & locale
$user->timezone()->name(); // "Asia/Shanghai" (or null if unknown) $user->localTime(); // CarbonImmutable in their timezone $user->isNight(); // bool $user->greeting(); // localized "Good evening" $user->locale(); // "en_US" // Explicit overrides always win over IP / header detection: UserContext::overrideTimezone($user, 'Europe/Berlin'); UserContext::overrideLocale($user, 'de');
Location
$user->location()->countryCode(); // "SE" $user->location()->countryName(); // "Sweden" $user->location()->city(); // "Stockholm"
User-to-user time comparison
$c = $userA->timeFor($userB); $c->theirTime; // CarbonImmutable in B's timezone $c->formattedOffset(); // "+12:00" $c->dayPeriod; // DayPeriod::Night $c->isConvenientTime(); // is it a reasonable local hour to contact B?
Blade components
<x-user-context::user-presence :user="$user" /> <x-user-context::local-time :user="$user" format="H:i" /> <x-user-context::heartbeat />
API
GET /user-context/me returns the authenticated user's context:
{
"online": true,
"last_seen": "2026-07-18T10:30:00+00:00",
"timezone": "Europe/Stockholm",
"local_time": "15:30",
"country": "Sweden",
"locale": "sv_SE"
}
Events
Listen for any of: UserOnline, UserOffline, UserLocationUpdated,
UserTimezoneChanged, UserLoginRecorded. See Extending.
Testing
composer test
Changelog
Please see CHANGELOG for what has changed recently.
Credits
License
The MIT License (MIT). Please see License File for more information.