devrabiul/laravel-geo-genius
Laravel GeoGenius adds IP geolocation, automatic timezone detection and conversion, locale detection with translation and number helpers, plus a country picker with phone formatting and validation. Livewire-ready, cookie/header based, and easy to drop into any Laravel app.
Verdict up front: adopt on a narrow, non-authoritative scope (UX defaults: suggested locale, default country in phone input, display timezone), not as a system of record for locale/timezone/compliance decisions. Exit cost is low, blast radius is contained, but two design choices — third-party IP lookups on free public endpoints and session-coupled state — create governance and fit problems that must be resolved before this touches authenticated user records or persisted timestamps.
Architecture fit
laravelGeoGenius()) + two service classes (GeoLocationService, TimezoneService) + namespaced functions. That's a conventional Laravel package shape and it composes cleanly with existing HTTP kernel middleware.genius_local_Language) and the v1.6 release is explicitly a session flow refactor, so the package's contract is session-shaped by design. Queue workers, console commands, scheduled jobs and broadcasting have no request context — the helper will yield defaults or trigger outbound calls with no user.composer require buys four capabilities but also four separate risk surfaces; you cannot adopt timezone handling without pulling in the translation and intl-tel-input code paths. Mitigate by defining an internal interface (GeoContext, LocaleContext) that our code depends on, with the package as one implementation. That keeps the vendor swap to one adapter class.Integration feasibility
vendor:publish, config tuning, and a Blade include. A single engineer can have a read-only pilot in 1–2 days.TrustProxies configuration so getClientIp() returns the visitor and not the load balancer; deciding cache store and TTL; CSP conformance for the injected <script>/<link> tags; disabling outbound calls in test and CI; and instrumenting the provider call so degradation is observable.geo:add-timezone-column {table} mutates schema outside version-controlled migrations, and the geo:translations-generate / geo:translate-* family writes language files into the repo. Both are fine as developer conveniences, both are dangerous as pipeline steps. Treat them as local scaffolding only; the resulting migrations and language files must be committed and reviewed like hand-written code.Technical risk
| # | Risk | Severity | Why it matters |
|---|---|---|---|
| 1 | Third-party IP processors (ipwho.is, ip-api.com, ipify.org) receive end-user IPs |
High | IP is personal data in GDPR/UK-GDPR/CCPA contexts. Requires a processor assessment, disclosure update, and a documented legitimate-interest or consent basis. The documented ip-api.com free tier is HTTP-only, which means user IPs traversing plaintext. This is the single largest blocker to broad rollout. |
| 2 | Silent degradation to defaults | High | Free tiers are rate-limited; on throttle or outage the package "returns default structure". Users then see the wrong country in the phone dropdown, the wrong currency/locale, and the wrong timezone — with no error surfaced to our monitoring. |
| 3 | Proxy misconfiguration → single geo identity | Medium-High | If TrustProxies is not configured for the CDN/LB, every request resolves to the edge IP. Everyone shares one cache entry and one locale/timezone. Subtle and hard to reproduce in staging. |
| 4 | Session coupling / statelessness | Medium | No session means no detected locale; Livewire is claimed compatible, but each Livewire round-trip re-enters the stack and must be memoized or it's a per-request API call. |
| 5 | Injected CDN assets ([email protected] via jsdelivr) |
Medium | Version is pinned in PHP source, no SRI, no Vite/npm path, inline script tags break nonce-based CSP. Also a supply-chain surface for a payment-adjacent input (phone). |
| 6 | Machine translation of production copy | Medium | Auto-translate commands write user-facing strings from an undisclosed provider. Brand, legal, and safety-critical copy must never enter that pipeline unflagged. |
| 7 | Bus factor / validation signals | Medium | 182 stars, 0 dependents, single maintainer, no CI or security policy referenced, and a recent core refactor of session handling. Low adoption means few downstream bug reports; expect to be the first to find edge cases. |
| 8 | Test-suite and CI behavior | Medium | Localhost/::1 triggers an external IP fetch by design. Without a config kill-switch and Http::fake, test suites become network-dependent and flaky. |
| 9 | add-timezone-column drift |
Low-Medium | Schema mutated outside migrations creates environments that disagree. |
Mitigating factors: MIT license, small readable surface (a few services plus helpers), and no exotic runtime dependencies. If the vendor disappears, an in-house replacement is roughly one to two sprints of work — the replacement cost is dominated by the phone-input and translation pieces, not the geolocation call itself.
Key questions
geo:translate-* commands call, with what credentials, what data leaves our servers, and is there a rate-limit/cost model?TrustProxies/X-Forwarded-For, and is there a supported way to inject a resolved IP (e.g., from Cloudflare CF-IPCountry) instead of calling out?initIntlPhoneInput() output be published as static assets bundled through Vite, with SRI and CSP-nonce support — or must it remain inline?laravel-geo-genius following semver, and what is the deprecation policy for the helper functions and session key?Stack fit
App\Support\Geo\GeoContext with countryCode(), timezone(), suggestedLocale(). Application code depends on the interface, never on laravelGeoGenius(). This is the single most valuable architectural decision here — it converts a vendor risk into a one-file swap and makes the package mockable in tests.users.timezone and users.locale (nullable, user-editable, defaulting from detection). Detection becomes a one-time seed value, not a per-request lookup. The package's geo:add-timezone-column is a starting point only; commit the equivalent migration by hand.Migration path
Http::fake-based tests, verify getClientIp() correctness behind the CDN, and confirm CSP behavior of initIntlPhoneInput(). Output: a risk memo and a go/no-go on the phone input as-is.GeoContext + a NullGeoContext and a ConfigGeoContext for tests so no product code knows the vendor exists.timezone/locale columns, seed from one detection event at login, expose in user settings, and switch all rendering to the stored value.GeoContext implementation is kept and exercised by tests, so removing the package is a config change plus cleanup PR.If a strict data-processing posture is required (EU traffic, regulated customers), skip the free public APIs entirely in phase 2 and either self-host MaxMind GeoLite2 behind the same GeoContext interface or consume a header set by our own edge/CDN. This is the recommended path; the package's public-API default is the compromise variant.
Compatibility
^1.6) and treat minor bumps as reviewable PRs, not automatic updates — the v1.6 release refactored core session handling, which is exactly the kind of change that can silently alter what users see.intl-tel-input is a hard front-end dependency with its own version lifecycle. Either accept the pinned CDN version or vendor it through Vite; do not leave it half-managed.script-src relaxation or inline nonces, that's an architecture review item, not a config tweak.Sequencing (with gates)
| Phase | Scope | Exit gate |
|---|---|---|
| 0 | Spike + outbound-call inventory | Written DPA/legitimate-interest stance; CSP assessment; proxy verification |
| 1 | GeoContext adapter + null implementation |
Tests pass with zero network; package absent = no behavior change |
| 2 | Cosmetic defaults behind a flag | Rollback via flag, no DB writes |
| 3 | Persist locale/timezone on the user record | Stored value wins over detected value everywhere |
| 4 | Translation pipeline (optional, decoupled) | Human review step mandatory; legal/safety strings excluded |
| 5 | Detection reduced to first-visit hints | Steady-state outbound calls near zero |
The translation tooling and the phone input should be sequenced as separate tracks from geolocation. They share a vendor but not a risk profile, and bundling them into one launch date is how a cosmetic locale tweak becomes a payments-adjacent incident.
Maintenance
Support
GeoContext, every such ticket escalates to engineering. Build a small internal diagnostics route (behind auth) that dumps resolved IP, detection source, cache hit/miss, and the stored user preference.Scaling
Failure modes
| Failure | Detection | User-visible effect | Mitigation |
|---|---|---|---|
| Provider outage or rate-limit | None from the package — silent default fallback | Wrong default country, wrong locale, wrong timezone | Wrap calls with logging/metrics + alert on fallback rate; serve last-known-good from cache |
TrustProxies misconfigured |
Anomalously low unique-IP count; all users same locale | Uniform wrong defaults site-wide | Explicit proxy config + assertion test in staging |
| Plaintext HTTP geolocation endpoint | Discovered in review, not runtime | User IPs exposed on the wire | Block non-HTTPS providers in adapter; prefer edge headers/MaxMind |
| Machine translation of legal/safety copy | Post-hoc, in review or by customer complaint | Brand/legal exposure in a market | Deny-list of files/keys excluded from the pipeline; mandatory human review gate |
intl-tel-input CDN unavailable or version drift |
Front-end error monitoring | Phone field unformatted/unvalidated at a conversion step | Bundle locally; server-side validation remains authoritative |
Schema drift from geo:add-timezone-column |
Environment diff during deploy | Migration conflicts, failed deploys | Ban the command in pipelines; hand-authored migrations only |
| Test/CI flakiness from outbound calls | Intermittent CI failures, slow suites | Delivery friction | Global outbound-disable flag + Http::fake in the base test case |
| Session loss / guest churn | Elevated detection call rate | Repeated detection cost, flickering locale | Accept and cache; fall back to config('app.locale') deterministically |
Ramp-up
GeoContext adapter and a feature flag; hold broad adoption until the IP-processor and CSP questions are closed. The package earns its place as a UX-defaults convenience and a translation scaffolding tool. It does not earn a place in the authoritative path for identity, jurisdiction, or persisted time.How can I help you explore Laravel packages today?