spatie/geocoder turns addresses into coordinates through Google
Geocode addresses to coordinates
At a glance
- What is it?
- This small PHP package calls Google's geocoding service and returns a plain array of coordinates, accuracy and address data, with Laravel wiring on top. It is a convenience wrapper, and it is deliberately thin enough that you can replace it with a direct HTTP call when you outgrow it.
- Who is it for?
- Adopt spatie/geocoder when your PHP application needs one-off address lookups, when you want a single array shape instead of a raw response, and when a Laravel project should not have to reimplement provider registration and config publishing. Do not adopt it as a geocoding platform: it targets a single provider, exposes no batching, caching or retry behaviour, and returns plain arrays rather than typed objects.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 57 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A thin wrapper over the Google geocoding endpoint
spatie/geocoder exists to do one thing: send an address string to Google's geocoding service and hand back the coordinates that come with it. The README leads with the shortest possible example, a single static call on the Geocoder facade.
Geocoder::getCoordinatesForAddress('Samberstraat 69, Antwerpen, Belgium');What comes back is a plain PHP array. The documented shape carries lat and lng, an accuracy string, a formatted_address, and a viewport block with northeast and southwest corners. For the Antwerpen example the accuracy value is ROOFTOP and the formatted address comes back normalized to include the postal code.
That is the whole value proposition, and it is worth being blunt about it. This is not a geocoding platform with retries, caching, queues or a database of places. It is a small client that turns a REST response into an array, with the option to reuse an existing Guzzle client. For a Laravel application that occasionally needs to convert a form input into a lat and lng, that is exactly enough. For anything continuous, you will be writing the surrounding machinery yourself.
Composer install, and the Laravel registration that follows
Installation is a single Composer command, and the package works in plain PHP projects as well as Laravel ones.
composer require spatie/geocoderIn Laravel 5.5 and later the package autoregisters itself. In older Laravel versions you add the service provider and the facade alias by hand in config/app.php, with the provider listed first.
'providers' => [
'...',
Spatie\Geocoder\GeocoderServiceProvider::class
];The facade alias follows the same pattern.
'aliases' => array(
...
'Geocoder' => Spatie\Geocoder\Facades\Geocoder::class,
)After registering, the config file has to be published into the application, otherwise the key and the region settings never reach the package.
php artisan vendor:publish --provider="Spatie\Geocoder\GeocoderServiceProvider" --tag="config"The vendor:publish step is the part teams forget, and the symptom is a package that loads fine and then has no API key to send. The README does not spell out that failure mode, so it is worth knowing before the first request rather than after it.
The config file holds the parameters that change results
The published config file exposes five settings, and the comments in the file point at the Google documentation for each one. The reduced shape of it looks like this.
'key' => env('GOOGLE_MAPS_GEOCODING_API_KEY', ''),
'language' => '',
'region' => '',
'bounds' => '',
'country' => '',The key is read from the GOOGLE_MAPS_GEOCODING_API_KEY environment variable with an empty default, so an unset variable produces an empty key rather than a crash at boot. The language parameter sets response translations for textual data, the region parameter finetunes the geocoding process, the bounds parameter finetunes it further using a viewport, and the country parameter limits results to a specific country.
That last group is the interesting part, and the distinction matters. Language changes how the textual fields are translated. Region, bounds and country change which result you get. Setting a country bias is how the package returns an address from the right country when the same street name exists in several, and leaving them empty means the service decides.
The README also shows the same settings applied directly on the object, which is how you override them per call rather than per application.
Constructing the geocoder yourself when you need different parameters
Outside Laravel, or when a single request needs a different country than the global default, you construct the object yourself with a Guzzle client. That is the usage the README documents in full.
$client = new \GuzzleHttp\Client();
$geocoder = new Geocoder($client);
$geocoder->setApiKey(config('geocoder.key'));
$geocoder->setCountry(config('geocoder.country', 'US'));
$geocoder->getCoordinatesForAddress('Infinite Loop 1, Cupertino');Note that the client is injected rather than created internally, which means you decide the timeout, the retry behaviour and the proxy settings that your environment needs. The README does not document which of those the package sets itself, so an injected default client is a reasonable place to start and a poor place to leave production traffic.
The result for that Cupertino address is documented with the same keys as the facade example, including an accuracy of ROOFTOP and a viewport block. The two documented examples use slightly different values for the same address, which is a good reminder that a geocoding result is a service response rather than a deterministic function of the query.
Three query shapes: one result, all results, and a reverse lookup
The package exposes three ways to ask. The first returns the first result for an address. The second returns every candidate, which matters when a street name is ambiguous.
$geocoder
->getAllCoordinatesForAddress('Infinite Loop 1, Cupertino');That call returns an array of arrays, and the documented output shows two entries, each with a place_id. The place_id is the only piece of the response that identifies a location stably, and it is present in the all-results output. A caller that stores the first result and discards the rest throws that identifier away, which matters if you later need to reverse geocode the same point and want Google to recognise it.
The third shape goes the other way, turning coordinates back into an address.
$geocoder->getAddressForCoordinates(40.714224, -73.961452);Response language is set separately with setLanguage, which is what changes the formatted_address text and leaves the coordinates alone.
$geocoder->setLanguage('it');The Italian example in the README shows the same Cupertino coordinates with an Italian formatted_address, and the numbers are slightly different from the default language result, so even the lat and lng shift when the language parameter changes.
What the package leaves to you: batching, errors and alternate providers
The limits are easier to see from the surface area than from the documentation. There is no batch endpoint, no queue, no cache layer and no persistence of previously geocoded addresses, so importing ten thousand rows means ten thousand sequential HTTP requests unless you build that loop yourself. The README does not describe any rate limit handling, and it does not document how errors from the geocoding service are surfaced, so a failed request ends up in whatever your Guzzle client's error handling produces rather than in a typed exception from the package.
The provider question is even simpler. Everything in the package is written against Google. The config comments, the key name and the accuracy and viewport field names are all Google's. A different geocoding service would need a different implementation, and nothing in the repository suggests otherwise.
Calling the Google Geocoding API directly with Guzzle is the honest alternative, and the difference is worth spelling out. A direct call gives you the untouched response body, which means place_id, partial_match and address component breakdowns stay available, and it lets you implement retries and caching without working around a wrapper. The package earns its place by giving you a normalized array, a config file, a service provider and a facade, so the trade is convenience and consistency against control.
Version 4.1.0 shipped on 2026-09-01 under the MIT license
The package is MIT licensed, with the LICENSE file in the repository root, and it is not archived. The last push was on 2026-09-01, and the release list shows 4.1.0 on 2026-09-01, 4.0.0 on 2026-02-20 and 3.16.2 on 2025-11-20. Two of those three releases land in a seven month window, and the jump from a 3.x line to 4.0.0 in February 2026 is the kind of major bump that deserves a look at the CHANGELOG.md before you upgrade an existing application.
The repository layout matches a small, well behaved Composer package: composer.json at the root, the package code in src/, the default configuration in config/, tests alongside a phpunit.xml.dist file, and a .php-cs-fixer.dist.php style configuration. There is also an .editorconfig file and a .github directory, which is where the continuous integration lives.
Since the code depends on Google's response format, upgrading the package after Google changes its geocoding response would be a service-side event rather than a package release, and the MIT terms let you vendor and modify the code without obligations beyond keeping the license file. Whether the MIT license of the package affects the terms of the Google geocoding service is a separate question, and one the repository does not address.
Editorial conclusion
Adopt spatie/geocoder when your PHP application needs one-off address lookups, when you want a single array shape instead of a raw response, and when a Laravel project should not have to reimplement provider registration and config publishing. Do not adopt it as a geocoding platform: it targets a single provider, exposes no batching, caching or retry behaviour, and returns plain arrays rather than typed objects. Before the first request, confirm the GOOGLE_MAPS_GEOCODING_API_KEY is present in your environment, publish the config with php artisan vendor:publish --provider="Spatie\Geocoder\GeocoderServiceProvider" --tag="config", and decide whether you need the country, region, bounds and language settings that the config file exposes, because those parameters change the results rather than merely format them.
Frequently asked questions
How do I install spatie/geocoder in a Laravel application?
Run composer require spatie/geocoder, then publish the config file with php artisan vendor:publish --provider="Spatie\Geocoder\GeocoderServiceProvider" --tag="config". In Laravel 5.5 and later the package autoregisters itself, while older versions need the service provider and facade added to config/app.php.
Where does spatie/geocoder get its API key from?
The published config file reads it from the GOOGLE_MAPS_GEOCODING_API_KEY environment variable, with an empty string as the default. The key is used when sending geocoding requests to Google.
How do I get every match for an ambiguous address with spatie/geocoder?
Call getAllCoordinatesForAddress instead of getCoordinatesForAddress. The documented output is an array of result arrays, each with a place_id alongside the coordinates, accuracy, formatted_address and viewport.
Can spatie/geocoder reverse geocode coordinates into an address?
Yes. The README shows getAddressForCoordinates(40.714224, -73.961452) returning an address record, and setLanguage can be used beforehand to change the language of the textual response fields.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/spatie-geocoder)Was this useful?