Skip to content

danielbacsur/openplaces

Repository files navigation

openplaces

Look up places, businesses, addresses, and location metadata without a proprietary places API.

openplaces


Installation

npm install openplaces
claude mcp add openplaces -- npx -y @openplaces/mcp@latest

OpenPlaces works with or without a Google Maps API key. With a key, it calls the official Google Places API on your behalf — fully compliant with Google Maps Platform Terms and billed to your Google Cloud project.

Without one, it falls back to scraping. No key, no bill, no setup — but you are responsible for ensuring your usage complies with the terms of the upstream services and your local laws. This mode is intended for prototyping, research, and personal projects; if you are shipping to production or operating at scale, use a key.


Querying

Search queries can express more than a single lookup. Use AND or OR to search for multiple things at once, and IN to pin a query to a location. When combined, they expand into every combination automatically — searching for coffee and tea in paris or london runs four queries, not one. Wrap multi-word phrases in quotes to treat them as a single term, and use parentheses when you need finer control over which queries belong to which location.

COFFEE OR TEA IN PARIS AND "BED AND BREAKFAST" IN AMSTERDAM

The parser is a recursive descent implementation that tokenizes the input, respects operator precedence, expands everything into a flat list of { query, location } pairs, and hands those off to the search backends. Each pair is executed independently and the results are merged into a single unified stream.


Usage

import { OpenPlaces } from "openplaces";

const client = new OpenPlaces();

All examples below assume you've already imported and instantiated client — do that once and keep it in scope. If you want to route requests through the official Google Places API, pass an apiKey to the constructor. Otherwise, you can skip configuration entirely and use the scraping backend with no setup needed.


places.search

await client.places.search("eiffel tower");

await client.places.search("restaurants in tokyo", { limit: 10 });

await client.places.search("coffee and tea in paris or london", { limit: 40 });

A convenience wrapper around places.stream that drives the async iterator to completion, aggregates every emitted place, and resolves with a flat array. Use places.search when you need the complete result set before doing anything with it and the volume is manageable.


places.stream

const stream = client.places.stream("restaurants in tokyo", { limit: 200 });

for await (const place of stream) {
  console.log(place.name);
}

Under the hood, places.stream is the engine the library is built on. It returns an async iterator that yields places one at a time as they are discovered, so your loop can start processing results long before collection is complete. You can break out of the loop early and no further network work is done.

When you use the query language to constrain a search to a specific area, the stream can gather an effectively unbounded number of results by recursively subdividing the search space. The target area is treated as a root cell. When a cell's results suggest more places exist than a single query can surface, the algorithm divides that cell into four equal sub-cells and searches each one independently — repeating until every branch has been fully exhausted. This lets the stream fan out across dense areas automatically, without any manual tiling or pagination on your part.

About

A free, open-source alternative to Google’s Places API.

Topics

Resources

License

Stars

Watchers

Forks

Contributors