Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Geoip Laravel Package

pulkitjalan/geoip

Laravel package for IP geolocation using MaxMind GeoIP2 databases. Resolve country, region, city, postal code, coordinates, timezone, and currency for any IP address through a simple facade, with configurable database paths and caching support. Ideal for localization, analytics, and fraud checks.

Deep Wiki
Context7

Getting Started

  1. Install the package:

    composer require pulkitjalan/geoip
    

    Laravel auto-discovers PulkitJalan\GeoIP\GeoIPServiceProvider. If you're on an older Laravel or have discovery disabled, register the provider and add the GeoIP facade alias in config/app.php.

  2. Publish the config:

    php artisan vendor:publish --provider="PulkitJalan\GeoIP\GeoIPServiceProvider"
    

    This gives you config/geoip.php with a driver key and a services array of available providers.

  3. Pick a driver and set the matching env vars. The default (free, keyless) service works out of the box for a smoke test; paid/premium drivers (MaxMind, ipinfo, ipdata, etc.) need an API token or a local .mmdb path. Keep credentials in .env and reference them from the config file.

  4. First use case — resolve the visitor's country inside a controller or middleware:

    use PulkitJalan\GeoIP\Facades\GeoIP;
    
    $location = GeoIP::getLocation($request->ip());
    
    $location->countryCode; // "US"
    $location->country;     // "United States"
    $location->city;
    $location->lat;
    $location->toArray();
    

    Calling GeoIP::getLocation() with no argument falls back to the current request's IP.

Where to look first: config/geoip.php for the default driver and service list, and the Location value object (returned by getLocation()) for the fields each driver can populate. Start by writing one test that geolocates a known IP through your chosen driver — it tells you immediately whether credentials and network access are wired correctly.

Implementation Patterns

Middleware for locale/currency. Resolve the location once per request, stash it on the request or a singleton, and derive locale, currency, and timezone for the rest of the request lifecycle:

class SetLocaleFromIp
{
    public function handle($request, Closure $next)
    {
        try {
            $location = GeoIP::getLocation($request->ip());
            app()->setLocale(config("locales.{$location->countryCode}", 'en'));
        } catch (\Throwable $e) {
            report($e); // never break the request over geo lookup
        }
        return $next($request);
    }
}

Wrap it behind your own service. Bind a GeoLocator interface in the container and inject GeoIP into a single implementation. This keeps the rest of the codebase independent of the package's API and makes it trivial to stub in tests or swap providers later.

Cache by IP. External geolocation APIs are rate-limited and latency-prone. Cache the normalized result keyed on the IP for 24h–30d (residential IPs rarely move; mobile IPs are noisier):

public function locate(?string $ip): ?LocationData
{
    if (!$ip || !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        return null;
    }
    return Cache::remember("geo:{$ip}", now()->addDay(), fn () => $this->map(GeoIP::getLocation($ip)));
}

Fallback chains. Configure two services (one primary, one cheap backup). Catch the driver exception and retry with GeoIP::setDriver('...') or re-resolve a second instance from the container with alternative config.

Asynchronous enrichment. Don't block registration/login on a network call. Dispatch a queued EnrichUserGeo job after the user record exists; it fills country_code, timezone, and currency on the user model.

Normalize to a DTO. Map the package Location into your own array/DTO immediately: ['country' => $loc->countryCode, 'city' => $loc->city, 'lat' => $loc->lat, ...]. Different drivers return different field sets, so centralize null handling in one place.

Testing. Never hit real services in CI. Fake the underlying HTTP client (Http::fake()) for HTTP-based drivers, or bind a fake GeoLocator implementation in the container. The Location object is easy to construct/mock for unit-testing presentation and mapping logic.

Gotchas and Tips

  • Private and reserved IPs. 127.0.0.1, 10.0.0.0/8, 192.168.0.0/16, and IPv6 link-local addresses will return null or throw depending on the driver. Always guard before calling, and have a sensible default for local development.
  • Behind a proxy/load balancer. request()->ip() returns the proxy's IP unless you have TrustProxies configured. Geoloacting your load balancer puts everyone in the same country — configure trusted proxies and confirm with a test.
  • Field availability varies by driver. Free tiers often omit isp, timezone, postalCode, or coordinates. Null-check every field you consume; don't assume city is populated for every country.
  • Rate limits are real. Free tiers commonly throttle at tens of requests per minute. Without caching you'll exhaust the quota during a modest traffic spike. Cache aggressively and consider a paid driver for production volume.
  • MaxMind needs local data. The local database driver requires a downloaded GeoLite2-City.mmdb (or commercial equivalent) on disk. Set the path in config and schedule a recurring job (or use the official geoipupdate tool) to refresh the file — stale databases degrade accuracy.
  • Config cache. After changing drivers or env values, run php artisan config:cache (and clear it first). Driver names in GEOIP_DRIVER must exactly match keys under services; typos yield a confusing "driver not supported" failure at resolution time, not boot time.
  • Exceptions must not break the request. Geolocation is best-effort enrichment. Wrap calls in try/catch, log with the IP and driver name as context, and degrade gracefully (fallback locale, default currency).
  • ISO casing. Country codes vary in case across providers. Normalize with strtoupper() before comparisons or database lookups.
  • IP is personal data. Under GDPR/CCPA, an IP address is identifiable. Avoid storing raw IPs alongside geodata longer than necessary; consider persisting only the derived country/timezone if that covers your use case.
  • Never use geo-IP for security decisions. VPNs, proxies, and mobile carriers make IP geolocation unreliable for fraud/access control. Use it for UX (language, currency, storefront) only.
  • IPv6 support is uneven. Some free drivers handle IPv6 poorly or return empty fields. Test with an IPv6 address if your traffic mix warrants it.
  • Extension point: if you need a provider that isn't bundled, check whether the config's services entry accepts a custom driver class implementing the package's driver contract — that's the cleanest place to slot in an internal service without forking.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style