
Languages : Laravel
How to Get User Location From IP in Laravel
Learn three ways to resolve a visitor’s city, country, coordinates, and timezone from their IP address in Laravel:
- a package-first method
- a DIY HTTP client method with hosted APIs
Why IP Geolocation?
- Personalize content and currency.
- Geo-based analytics and rate limiting.
- Compliance prompts (consent banners per region).
Approach 1: Package-First with stevebauman/location
Install
composer require stevebauman/location
php artisan vendor:publish --provider="Stevebauman\Location\LocationServiceProvider"
Make controller called LocationController
php artisan make:controller LocationController
Open Controller file and paste this code
// app/Http/Controllers/LocationController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Stevebauman\Location\Facades\Location;
class LocationController extends Controller
{
public function approach1(Request $request){
$ip = $request->ip();
// or
// $ip = $_SERVER['REMOTE_ADDR'];
// NOTE: Location::get($ip) works in server not in localhost
$location = Location::get($ip);
return view('location', [
'geo' => $location ? [
'ip' => $ip,
'country' => $location->countryName,
'countryCode' => $location->countryCode,
'region' => $location->regionName,
'city' => $location->cityName,
'postal' => $location->postalCode,
'lat' => $location->latitude,
'lon' => $location->longitude,
'timezone' => $location->timezone,
] : null,
'error'=>$location? null : 'We could not determine your location'
]);
}
}
Route file
// routes/web.php
use App\Http\Controllers\LocationController;
Route::get('/approach1', [LocationController::class, 'approach1'])->name('approach1');
Blade Code
<div class="max-w-xl mx-auto mt-8 p-6 bg-white dark:bg-gray-800 shadow rounded-xl">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">
🌍 IP Location
</h2>
{{-- Error Section --}}
@if($error)
<div class="p-3 mb-4 text-sm text-red-800 rounded bg-red-100 dark:bg-red-200 dark:text-red-900">
{{ $error }}
</div>
@endif
{{-- Geo Section --}}
@if($geo)
<ul class="space-y-2 text-gray-700 dark:text-gray-200">
<li><strong>IP:</strong> {{ $geo['ip'] }}</li>
<li><strong>Country:</strong> {{ $geo['country'] }} ({{ $geo['countryCode'] }})</li>
<li><strong>Region:</strong> {{ $geo['region'] }}</li>
<li><strong>City:</strong> {{ $geo['city'] }}</li>
<li><strong>Postal:</strong> {{ $geo['postal'] }}</li>
<li><strong>Timezone:</strong> {{ $geo['timezone'] }}</li>
<li><strong>Lat/Lon:</strong> {{ $geo['lat'] }}, {{ $geo['lon'] }}</li>
</ul>
@endif
</div>
Approach 2: DIY HTTP Client + Hosted APIs (ipapi, IPinfo, ip-api)
Make controller called LocationController
php artisan make:controller LocationController
Open Controller file and paste this code
// app/Http/Controllers/LocationController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
class LocationController extends Controller
{
public function approach2(Request $request){
$ip = $request->ip();
// or
// $ip = $_SERVER['REMOTE_ADDR'];
// NOTE: Location::get($ip) works in server not in localhost
try {
$res = Http::get("http://ip-api.com/json/{$ip}");
if (!$res->ok() || $res->json('status') == 'fail') {
return view('location', [
'geo' => null,
'error' => 'We could not determine your location',
]);
}
return view('location', [
'geo' => [
'ip' => $ip,
'country' => $res->json('country'),
'countryCode' => $res->json('countryCode'),
'region' => $res->json('region'),
'city' => $res->json('city'),
'postal' => $res->json('zip'),
'lat' => $res->json('lat'),
'lon' => $res->json('lon'),
'timezone' => $res->json('timezone'),
'org' => $res->json('org'),
],
'error'=>null
]);
} catch (ConnectionException $exception) {
return view('location', [
'geo' => null,
'error' => 'Unexpected error: ' . $exception->getMessage(),
]);
}
}
}
Route file
// routes/web.php
use App\Http\Controllers\LocationController;
Route::get('/approach2', [LocationController::class, 'approach2'])->name('approach2');
Blade Code
<div class="max-w-xl mx-auto mt-8 p-6 bg-white dark:bg-gray-800 shadow rounded-xl">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">
🌍 IP Location
</h2>
{{-- Error Section --}}
@if($error)
<div class="p-3 mb-4 text-sm text-red-800 rounded bg-red-100 dark:bg-red-200 dark:text-red-900">
{{ $error }}
</div>
@endif
{{-- Geo Section --}}
@if($geo)
<ul class="space-y-2 text-gray-700 dark:text-gray-200">
<li><strong>IP:</strong> {{ $geo['ip'] }}</li>
<li><strong>Country:</strong> {{ $geo['country'] }} ({{ $geo['countryCode'] }})</li>
<li><strong>Region:</strong> {{ $geo['region'] }}</li>
<li><strong>City:</strong> {{ $geo['city'] }}</li>
<li><strong>Postal:</strong> {{ $geo['postal'] }}</li>
<li><strong>Timezone:</strong> {{ $geo['timezone'] }}</li>
<li><strong>Lat/Lon:</strong> {{ $geo['lat'] }}, {{ $geo['lon'] }}</li>
@if(isset($geo['org']))
<li><strong>Organization:</strong> {{ $geo['org'] }}</li>
@endif
</ul>
@endif
</div>
Comparison Table
Criterion | Package (stevebauman/location ) | DIY HTTP + API |
---|---|---|
Setup speed | Very fast | Fast |
Accuracy | Provider-dependent | High (paid tiers) |
Rate limits | Provider-dependent | Vendor-defined |
Privacy | Provider-dependent | Provider-dependent |
Cost | Free (provider may bill) | Free → Paid |
Maintenance | Low | Low–Medium |
Happy coding 🚀