diogogpinto/filament-geolocate-me
Filament Geolocate Me adds a geolocation field to Filament forms so users can capture their current latitude and longitude, or pick a point on a map, with a single click—ideal for address, store locator, and check-in forms.
diogogpinto/filament-geolocate-me is a small Filament plugin that wires the browser's navigator.geolocation API into a Filament form so a user can hit a "locate me" control and have coordinates written straight into your form state. It is pre-1.0 (v0.1.x), so treat the API surface as unstable.
Minimal setup:
composer require diogogpinto/filament-geolocate-me
Then, in a Filament resource form, the first use case to try is a pair of coordinate fields on a model that has a physical location (store, site, delivery address, asset):
use DiogoGPinto\FilamentGeolocateMe\...; // check src/ for the exact FQCN
GeolocateMe::make('location')
->latitudeField('latitude')
->longitudeField('longitude'),
Practical order of investigation:
README.md end-to-end — it is short and is the only real documentation at this version.src/ and find the main field/action class plus the service provider. Confirm which Filament major version it targets (composer.json → filament/filament constraint) before you build anything on it.TextInput fields so you can see exactly which state paths get written. Don't integrate it into a real form until you've confirmed the state-mutation behaviour yourself.First meaningful use case: an admin panel where staff create records on-site and need the device's GPS position captured without typing numbers. Pair it with a map picker or a reverse-geocoding call for a human-readable address.
Field-level integration (most common). Use the plugin's component inside Filament\Forms\Components and point it at the sibling fields you want populated. Keep latitude/longitude on the model as nullable decimal(10,7) columns so the form works before the user ever clicks locate.
Action-level integration (more control). If the shipped component doesn't match your layout, replicate it with a plain Filament Action on a field suffix and set state yourself:
TextInput::make('latitude')->numeric()->live(),
Action::make('locate')
->label('Use my location')
->icon('heroicon-o-map-pin')
->alpineClickHandler(<<<'JS'
navigator.geolocation.getCurrentPosition(
(pos) => {
$wire.set('data.latitude', pos.coords.latitude.toFixed(7));
$wire.set('data.longitude', pos.coords.longitude.toFixed(7));
},
(err) => $wire.notify({ title: err.message, status: 'danger' }),
{ enableHighAccuracy: true, timeout: 10000 }
);
JS),
This is worth knowing because it means you are never blocked by the package — the underlying browser API is a dozen lines.
Reactive downstream fields. Coordinates are rarely the end product. Chain ->afterStateUpdated() or ->live() so the locate result triggers a reverse-geocode (via Http::get('https://nominatim...') or your own endpoint) that fills address, city, postal_code. Debounce or gate this behind an explicit button so you don't hammer a geocoding API on every keystroke.
Persisting and casting. Store raw floats; cast on the Eloquent model ('latitude' => 'float') so Livewire's string-typed state round-trips cleanly. If you later need radius queries, migrate to a spatial column and derive it from the decimal pair.
Testing. The geolocation call is client-side, so Pest/PHPUnit cannot exercise it. What you can and should test: the Livewire set path (mount the form, call set('data.latitude', ...), assert the record saves), validation rules on the coordinate fields, and any reverse-geocode service behind an Http::fake(). Assert the plugin is registered in a smoke test so a Filament major bump fails loudly.
Version pinning. With v0.1.x, pin exactly ("diogogpinto/filament-geolocate-me": "0.1.1") and review the diff on every bump. Patch releases in a 0.x package are not a guarantee of BC, and there is no changelog detail to rely on.
Secure context is mandatory. navigator.geolocation is unavailable on plain http:// except on localhost. Local dev on http://myapp.test via Laravel Herd/Valet is fine; a staging box on http:// will silently break the button for everyone. This is the number one "it doesn't work" cause.
Permission is per-origin and sticky. Once a user denies the prompt, subsequent calls fail immediately with PERMISSION_DENIED and you cannot re-prompt programmatically. Always render an error state and a fallback (manual entry, or a map picker) rather than assuming success. Show the error via a Filament notification so it isn't swallowed.
Don't call it on page load. Browsers increasingly require user activation for the permission prompt, and an unprompted location request on form mount is both bad UX and unreliably blocked. Trigger only from an explicit click.
Handle the async gap. GPS fix can take 5–15 seconds on a cold device. Pass timeout and maximumAge options, disable the button while pending, and give loading feedback. Without maximumAge you pay the full fix cost every click during a long editing session.
High accuracy costs battery and time. enableHighAccuracy: true is right for field data capture but wrong for a quick "roughly where am I" default. Make it configurable or accept the package's default.
Rounding. Browser coords come back as long floats. decimal(10,7) gives ~1cm precision — more than enough — and Laravel will happily insert an over-long float into a narrower column, silently truncating. Round in the state update (.toFixed(7)) rather than trusting the DB.
Nullable state. A user who never clicks locate submits null. Make sure columns are nullable and validation uses nullable|numeric|between:-90,90 / between:-180,180 rather than required.
Asset and view publishing. If the plugin registers Alpine components or Blade views, run php artisan filament:assets (and vendor:publish --tag=filament-geolocate-me-views if views are publishable) after every upgrade, otherwise you get stale assets and a confusing "nothing happens" symptom. Clear view:clear if you've published and overridden.
CSP. If you run a strict Content-Security-Policy, add geolocation 'self' to Permissions-Policy — otherwise the API exists but every call rejects, which looks identical to a denied prompt.
Extension points when the package is too thin. At v0.1.x expect a single component and little config. The realistic path is: use it if it fits, otherwise copy its ~30 lines of Alpine into your own Action. You lose nothing by owning that code, and you insulate yourself from a 0.x breaking change.
On v0.1.1 specifically. The release note is a bare changelog link with no described changes — no features, no deprecations, no stated breaking changes. There is nothing here that requires code changes or config migration. Treat it as housekeeping, update if your lockfile allows, and keep the exact pin plus the same smoke test in place. Given the absence of detail, run your form once in a browser after upgrading before shipping.
How can I help you explore Laravel packages today?