PHPackages                             mayaram/laravel-browser-location - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mayaram/laravel-browser-location

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mayaram/laravel-browser-location
================================

HTML5 browser geolocation package for Laravel with Livewire 4 support, GPS capture, reverse geocoding, maps, and API integration.

v2.1.3(3mo ago)10161↓86.4%[2 PRs](https://github.com/mayaramyadav/laravel-browser-location/pulls)MITPHPPHP ^8.2CI passing

Since Feb 24Pushed 1w agoCompare

[ Source](https://github.com/mayaramyadav/laravel-browser-location)[ Packagist](https://packagist.org/packages/mayaram/laravel-browser-location)[ Docs](https://github.com/mayaramyadav/laravel-browser-location)[ GitHub Sponsors](https://github.com/mayaram)[ RSS](/packages/mayaram-laravel-browser-location/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (8)Dependencies (10)Versions (14)Used By (0)

Laravel Browser Location
========================

[](#laravel-browser-location)

Capture browser-based GPS location in Laravel using the HTML5 Geolocation API.
Works with **Laravel 10-13**, **plain Blade**, and **Livewire 3 / 4**.

Table of Contents
-----------------

[](#table-of-contents)

- [Core features](#core-features)
- [Installation](#installation)
- [Usage: Blade component](#usage-blade-component)
    - [All Component Props](#all-component-props)
    - [Browser Events](#browser-events)
    - [JavaScript API](#javascript-api)
- [Configuration](#configuration)
- [Geocoder service (Google / Mapbox / OpenStreetMap)](#geocoder-service-google--mapbox--openstreetmap)
    - [Configure provider in `.env`](#configure-provider-in-env)
    - [Usage via facade](#usage-via-facade)
    - [Usage via dependency injection (preferred)](#usage-via-dependency-injection-preferred)
    - [Normalized response shape](#normalized-response-shape)
    - [Best practices](#best-practices)
- [Location persistence collections](#location-persistence-collections)
    - [1) Add the `HasLocations` trait to your model](#1-add-the-haslocations-trait-to-your-model)
    - [2) Save locations manually (Spatie-style API)](#2-save-locations-manually-spatie-style-api)
    - [3) Read stored locations](#3-read-stored-locations)
    - [4) Automatic saving flow (no manual save required)](#4-automatic-saving-flow-no-manual-save-required)
    - [Persistence config](#persistence-config)
    - [Optional explicit locationable models](#optional-explicit-locationable-models)
- [Livewire integration (v3 &amp; v4)](#livewire-integration-v3--v4)
    - [Basic setup](#basic-setup)
    - [Trait helper methods](#trait-helper-methods)
    - [Livewire 3 &amp; 4 — recommended attributes](#livewire-3--4--recommended-attributes)
    - [Livewire 4: using #\[On\] to react via JS dispatch](#livewire-4-using-on-to-react-via-js-dispatch)
- [Compatibility matrix](#compatibility-matrix)
- [Middleware Validation](#middleware-validation)
- [Testing](#testing)
- [License](#license)

---

Core features
-------------

[](#core-features)

- Accurate GPS capture with HTML5 Geolocation
- Works with **plain Blade** and **Livewire 3** — Livewire is fully optional
- Ready-to-use Blade component (``)
- SPA-friendly: re-captures after every Livewire navigation without page reload
- Permission + error handling for denied / timeout / unavailable states
- Accuracy detection (`excellent`, `good`, `poor`, `unknown`)
- Typed PHP helper methods on the Livewire trait
- Provider-based geocoding + reverse geocoding (Google, Mapbox, OpenStreetMap)
- Cache-ready geocoder responses for fast repeated lookups
- Spatie-style location collections with polymorphic model ownership
- Automatic DB persistence (`JS → API → Laravel`)
- Auto-loaded migration for `browser_locations` table
- One-command setup: `php artisan browser-location:install`
- Middleware alias for route-level location validation (`browser-location.validate`)

---

Installation
------------

[](#installation)

```
composer require mayaram/laravel-browser-location
```

Run the installer command:

```
php artisan browser-location:install
```

This publishes config / views / migrations and runs migrations automatically.

---

Usage: Blade component
----------------------

[](#usage-blade-component)

Drop the tracker anywhere in any Blade view — including inside a Livewire component:

```

```

> **Default behaviour:** `auto-capture="true"` and `force-permission="true"` are on by default, so the browser will request the user's location immediately. Set them to `false` if you want manual control.

### All Component Props

[](#all-component-props)

PropTypeDefaultDescription`button-text`string`'Share GPS location'`Label for the (hidden by default) trigger button.`auto-capture`bool`true`Requests location on page load and after every Livewire navigation.`force-permission`bool`true`Shows a full-screen overlay until the user grants permission.`watch`bool`false`Continuously tracks position using `watchPosition()`.`livewire-method`string`'setBrowserLocation'`Livewire component method called on successful capture. Leave empty in plain Blade.`required-accuracy-meters`float`200`Threshold for the `is_accurate` flag in the payload.`enable-high-accuracy`bool`true`Requests the most accurate reading from the device GPS.`timeout`int`12000`Milliseconds before the location request times out.`maximum-age`int`0`Milliseconds a cached location is considered fresh (`0` = always fresh).`auto-save`bool`false`Automatically POSTs captures to the package save endpoint.`capture-endpoint`string`'/browser-location/capture'`Endpoint used by JS for automatic persistence.`collection-name`string`'default'`Target location collection for automatic save.`locationable-type`stringauth user morph classOverride the model class that owns the location (must be allow-listed).`locationable-id`mixedauth user keyOverride the model key.`event-name`string`'browser-location:updated'`JS event dispatched on successful capture.`error-event-name`string`'browser-location:error'`JS event dispatched on error.`permission-event-name`string`'browser-location:permission'`JS event dispatched when permission state changes.**Example with custom options:**

```

```

### Browser Events

[](#browser-events)

The tracker dispatches these native DOM events on `document`:

EventDescription`browser-location:updated`Successful capture — payload contains full location data`browser-location:error`Error — payload contains `code` and `message``browser-location:permission`Permission state changed — payload contains `state``browser-location:saved`Location persisted to DB — payload contains persistence result`browser-location:save-error`Persistence request failed```
document.addEventListener("browser-location:updated", (e) => {
    console.log(e.detail.latitude, e.detail.longitude);
});
```

### JavaScript API

[](#javascript-api)

```
// Last-initialized tracker on the page:
window.BrowserLocationTracker.capture(); // Trigger a fresh capture
window.BrowserLocationTracker.requestPermission(); // Alias for capture()
window.BrowserLocationTracker.getJson(); // Returns latest data as JSON string

// Named instance (if you have multiple trackers):
window.BrowserLocation["browser-location-"].capture();
```

---

Configuration
-------------

[](#configuration)

```
php artisan vendor:publish --tag=browser-location-config
```

Creates `config/browser-location.php`. Key options:

```
'auto_save'          => false,   // persist every capture automatically
'min_accuracy'       => 200,     // max accepted accuracy in metres
'prevent_duplicates' => true,    // skip saves within 20 m of last point
'default_collection' => 'default',

'component' => [
    'auto_capture'    => true,
    'force_permission' => true,
    'watch'           => false,
    'livewire_method' => 'setBrowserLocation',
],
```

---

Geocoder service (Google / Mapbox / OpenStreetMap)
--------------------------------------------------

[](#geocoder-service-google--mapbox--openstreetmap)

### Configure provider in `.env`

[](#configure-provider-in-env)

```
# Provider: google | mapbox | openstreetmap
BROWSER_LOCATION_GEOCODER_PROVIDER=openstreetmap

# Google
BROWSER_LOCATION_GOOGLE_API_KEY=

# Mapbox
BROWSER_LOCATION_MAPBOX_ACCESS_TOKEN=

# OpenStreetMap (required for Nominatim policy compliance)
BROWSER_LOCATION_OSM_USER_AGENT="your-app-name/1.0 (admin@example.com)"
BROWSER_LOCATION_OSM_EMAIL=admin@example.com

# Cache
BROWSER_LOCATION_GEOCODER_CACHE_ENABLED=true
BROWSER_LOCATION_GEOCODER_CACHE_TTL=3600
```

### Usage via facade

[](#usage-via-facade)

```
use Mayaram\BrowserLocation\Facades\Geocoder;

$reverse = Geocoder::reverse(28.6139, 77.2090);
$forward = Geocoder::forward('New Delhi, India');
```

### Usage via dependency injection (preferred)

[](#usage-via-dependency-injection-preferred)

```
use Mayaram\BrowserLocation\Contracts\Geocoder;

class CheckoutController
{
    public function __construct(private readonly Geocoder $geocoder) {}

    public function __invoke(): array
    {
        return $this->geocoder->reverse(28.6139, 77.2090);
    }
}
```

### Normalized response shape

[](#normalized-response-shape)

```
[
    'provider' => 'openstreetmap',
    'query'    => [...],
    'resolved' => [
        'formatted_address' => '...',
        'latitude'          => 28.6139,
        'longitude'         => 77.209,
        'place_id'          => '...',
        'components'        => [...],
    ],
    'results' => [...],
    'raw'     => [...],
]
```

### Best practices

[](#best-practices)

- Prefer dependency injection for testability.
- Keep API credentials in `.env` — never commit keys.
- Enable cache in production to reduce cost and latency.
- For OpenStreetMap/Nominatim, always supply a real `user_agent` and contact email.
- Catch `Mayaram\BrowserLocation\Exceptions\GeocoderException` at your application boundary.

---

Location persistence collections
--------------------------------

[](#location-persistence-collections)

### 1) Add the `HasLocations` trait to your model

[](#1-add-the-haslocations-trait-to-your-model)

```
use Mayaram\BrowserLocation\Concerns\HasLocations;

class User extends Authenticatable
{
    use HasLocations;
}
```

### 2) Save locations manually (Spatie-style API)

[](#2-save-locations-manually-spatie-style-api)

```
$user->addLocation($data)->toLocationCollection('checkins');
$order->addLocation($data)->toLocationCollection('delivery');
$user->addLocation($data)->toSingleLocationCollection('live');
```

### 3) Read stored locations

[](#3-read-stored-locations)

```
$latest = $user->getLatestLocation();
$visits = $user->getLocations('visits');
```

### 4) Automatic saving flow (no manual save required)

[](#4-automatic-saving-flow-no-manual-save-required)

When `` captures a location the package:

1. POSTs coordinates to `POST /browser-location/capture`
2. Validates via `browser-location.validate` middleware
3. Applies quality checks (accuracy threshold + anti-duplicate rules)
4. Persists in `browser_locations` and enriches `meta` with raw GPS, geocoder response, IP, user-agent

### Persistence config

[](#persistence-config)

```
'auto_save'          => false,
'min_accuracy'       => 200,
'prevent_duplicates' => true,
'default_collection' => 'default',
'capture_endpoint'   => '/browser-location/capture',
```

### Optional explicit locationable models

[](#optional-explicit-locationable-models)

```
// config/browser-location.php
'allowed_locationable_models' => [
    App\Models\Order::class,
],
```

---

Livewire integration (v3 &amp; v4)
----------------------------------

[](#livewire-integration-v3--v4)

### Basic setup

[](#basic-setup)

**1. Add the trait to your Livewire component:**

```
