torann/geoip
GeoIP for Laravel resolves visitor location and currency from IP addresses via configurable services. Integrates with Laravel, supports multiple drivers/providers, and lets you publish config to choose and tune your lookup service.
Installation:
composer require torann/geoip
php artisan vendor:publish --provider="Torann\GeoIP\GeoIPServiceProvider" --tag="config"
This publishes the config/geoip.php file, which is now required (breaking change in v3.0+).
Configure a Provider:
Edit config/geoip.php to enable a provider (e.g., ipdata.co):
'providers' => [
'ipdata' => [
'enabled' => true,
'api_key' => env('IPDATA_API_KEY'),
],
],
Add your API key to .env (e.g., IPDATA_API_KEY=your_key_here).
First Use Case: Resolve geolocation in a controller or middleware:
use Torann\GeoIP\Facades\GeoIP;
$location = GeoIP::getLocation();
$country = $location->countryCode; // e.g., 'US'
$city = $location->city; // e.g., 'San Francisco'
Middleware Integration (Optional but Common):
Add GeoIPMiddleware to app/Http/Kernel.php to resolve geolocation for every request:
protected $middleware = [
\Torann\GeoIP\Middleware\GeoIPMiddleware::class,
];
Access the location via request()->geoip anywhere in your app.
Use GeoIPMiddleware to attach geolocation data to every request:
// app/Http/Middleware/GeoIPMiddleware.php (or Kernel.php)
public function handle($request, Closure $next) {
$request->merge(['geoip' => GeoIP::getLocation()]);
return $next($request);
}
Use Case: Geotargeted routing, compliance checks, or A/B testing. Access in controllers/views:
$country = $request->geoip->countryCode;
Cache results to reduce API calls (default: 1 hour):
// Cache for 24 hours
$location = GeoIP::getLocation(['cache_minutes' => 1440]);
Advanced: Use tagged caching for invalidation:
Cache::tags(['geoip'])->put('location:'.$ip, $data, 60);
Leverage provider capabilities (e.g., MaxMind’s ISP data or ipdata.co’s currency):
$location = GeoIP::getLocation(['provider' => 'maxmind']);
$currency = $location->currency; // Only available for ipdata.co
Listen for geolocation events to trigger custom logic:
// EventServiceProvider.php
protected $listen = [
'geoip.resolved' => [
\App\Listeners\LogGeoIP::class,
\App\Listeners\TriggerComplianceCheck::class,
],
];
Use Case: Analytics, compliance logging, or dynamic feature flags.
Override provider settings per request:
$location = GeoIP::getLocation([
'provider' => 'ipfinder',
'api_key' => 'dynamic_key_123',
]);
TrustProxies for cloud/CDN environments:
$ip = $request->ip(); // Respects X-Forwarded-For
$location = GeoIP::getLocationByIp($ip);
public function authorize() {
return GeoIP::getLocation()->countryCode === 'US';
}
@if(request()->geoip->countryCode === 'GB')
<p>Welcome to the UK! Use GBP.</p>
@endif
$currency = GeoIP::getLocation()->currency ?? 'USD';
Stripe::setApiKey(env('STRIPE_KEY'));
$tracker->track('Page View', [
'country' => $location->countryCode,
'city' => $location->city,
]);
GeoIP::shouldReceive('getLocation')
->once()
->andReturn((object) ['countryCode' => 'DE']);
GeoIP::fake() for isolated testing:
GeoIP::fake(['countryCode' => 'FR']);
Missing Config File:
Class 'Torann\GeoIP\GeoIP' not found or Call to undefined method.php artisan vendor:publish --provider="Torann\GeoIP\GeoIPServiceProvider" --tag="config" after installing.composer.post-autoload-dump in composer.json:
"scripts": {
"post-autoload-dump": [
"php artisan vendor:publish --tag=geoip-config --ansi"
]
}
Provider API Limits:
GeoIP::extend('ipdata', function ($app) {
$client = new \GuzzleHttp\Client();
$client->getMiddleware()->push(
new \App\Http\Middleware\LogApiCalls()
);
return new \Torann\GeoIP\Providers\Ipdata($client);
});
IPv6 Support:
ipdata.co (IPv6-friendly).Middleware Order:
GeoIPMiddleware must run before logic that depends on request()->geoip.$middleware or $middlewareGroups['web'].Caching Edge Cases:
Cache::forget('geoip:location:'.$ip);
Provider-Specific Quirks:
country_name (e.g., "United States") instead of countryCode (e.g., "US").
Fix: Normalize in a service:
$countryCode = strtoupper(substr($location->country_name, 0, 2));
'maxmind' => [
'database_path' => database_path('geoip/GeoLite2-Country.mmdb'),
]
Enable Logging:
Add to config/geoip.php:
'log' => [
'enabled' => true,
'channel' => 'single',
],
Check logs for provider errors (e.g., API failures, rate limits).
Inspect Raw Responses: Extend a provider to log raw data:
GeoIP::extend('ipdata', function ($app) {
$provider = new \Torann\GeoIP\Providers\Ipdata($app['http.client']);
$provider->setLogger(app('log')->channel('geoip'));
return $provider;
});
Test with Known IPs: Use hardcoded IPs to debug:
$location = GeoIP::getLocationByIp('8.8.8.8'); // Google DNS
Validate Provider Responses:
Ensure required fields exist (e.g., countryCode):
$location = GeoIP::getLocation();
if (empty($location->countryCode)) {
throw new \RuntimeException('Invalid geolocation data');
}
How can I help you explore Laravel packages today?