# Supermarket & Grocery Scraper – OpenStreetMap Store Data (`dataquarry/supermarkets`) Actor

Extract supermarkets, grocery & convenience stores from OpenStreetMap by area, radius, or name. Get brand, opening hours, organic, payment methods, wheelchair access and address. No API key; open (ODbL) data.

- **URL**: https://apify.com/dataquarry/supermarkets.md
- **Developed by:** [Daniel Brenner](https://apify.com/dataquarry) (community)
- **Categories:** Lead generation, E-commerce, Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Supermarket & Grocery Scraper – OpenStreetMap Store Data

Extract **supermarkets, grocery & convenience stores from OpenStreetMap** by area, radius, or name — **no API key, no anti-bot battles, no Terms-of-Service violations**. Open, legal (ODbL) data you can redistribute.

Give it an area like `"Berlin, Germany"` and get back tidy rows for every supermarket, grocery and convenience store: name, **brand** (Edeka, Lidl, Rewe, Aldi, Netto, Penny, Kaufland …) and its Wikidata id, operator, opening hours, whether it's **organic**, **accepted payment methods**, **wheelchair** accessibility, full address, coordinates, and the raw OpenStreetMap tags. You can also search **around a point** (every store within X km of an address) or **filter by name/brand** (e.g. every `"Aldi"` or `"Lidl"`).

### Why use this scraper?

- **Grocery-specific fields.** Not just a generic POI dump — brand + brand Wikidata id, organic flag, accepted payment methods, opening hours and wheelchair access, all straight from OpenStreetMap.
- **Legal & open.** OpenStreetMap data is licensed under the ODbL — redistributable with attribution. No Terms-of-Service violation, no login, no scraping a retailer's site.
- **No API key.** No data-provider account, no per-call quota.
- **Search by area, radius, or name/brand.** A whole city/country, everything within X metres of a point, or every store of one brand.
- **Pick the store types.** Supermarkets, convenience stores, greengrocers — or any subset.
- **No duplicates.** When OpenStreetMap maps one store twice (a node and an area), you get a single, richer row.
- **Honest data.** Every value comes straight from OpenStreetMap; anything not mapped is left empty (`null`) — never guessed or padded.
- **Global coverage & reliable.** Anywhere OSM has data; retries across multiple Overpass mirrors.

### Great for

- Retail location intelligence & store-network mapping
- Brand coverage & market-share analysis (Edeka vs. Rewe vs. Lidl vs. Aldi …)
- Site selection & catchment / competition analysis for new stores
- Local-commerce, delivery and "find a supermarket near me" apps
- Lead generation for FMCG / grocery suppliers, and AI/RAG pipelines

### Input

| Field | Type | Description |
|---|---|---|
| `area` | string | Place to search within, e.g. `"Berlin, Germany"`. Geocoded to a bounding box. |
| `aroundLocation` | string | *(optional)* Address/place to search **around** within a radius, e.g. `"Alexanderplatz, Berlin"`. Pair with `radiusMeters`. |
| `radiusMeters` | integer | *(optional)* Radius in metres for around-a-location search (default `5000`). |
| `centerPoint` | object | *(advanced)* Explicit center `{ "lat":.., "lon":.. }` to search around. |
| `boundingBox` | object | *(advanced)* Explicit `{ "south":.., "west":.., "north":.., "east":.. }`. Overrides `area`. |
| `storeTypes` | array | *(optional)* Which store types to include — any of `supermarket`, `convenience`, `greengrocer`. Default: all of them. |
| `searchTerm` | string | *(optional)* Only return stores whose **name** contains this text (case-insensitive), e.g. `"Aldi"`. |
| `maxResults` | integer | Maximum number of stores to return (default `1000`). |

#### Example input

```json
{
  "area": "Berlin, Germany",
  "storeTypes": ["supermarket", "convenience"],
  "maxResults": 500
}
```

Every Lidl within 10 km of a point:

```json
{
  "aroundLocation": "Alexanderplatz, Berlin",
  "radiusMeters": 10000,
  "searchTerm": "Lidl"
}
```

### Output

One row per store:

| Field | Description |
|---|---|
| `name` | Store name |
| `brand`, `brand_wikidata`, `operator` | Brand, its Wikidata id, and who operates the store |
| `branch` | Branch / location name of a chain outlet (OSM `branch`), e.g. `Times Square` — disambiguates multiple outlets of one chain; `null` when not tagged |
| `brand_logo` | Official brand logo image URL, from the brand's Wikidata entity (P154) when it has one; `null` otherwise (optional enrichment — never guessed) |
| `shop` | OSM store type: `supermarket`, `convenience`, or `greengrocer` |
| `opening_hours` | Opening hours (OSM syntax) |
| `organic` | Organic offering when tagged (`yes` / `only` / `no`) |
| `wheelchair` | Wheelchair accessibility (yes/no/limited) when tagged |
| `payment_methods` | Array of accepted payment methods, e.g. `["cash","visa","mastercard"]` |
| `latitude`, `longitude` | Coordinates |
| `street`, `housenumber`, `city`, `postcode`, `country` | Address |
| `state` | State / province (`addr:state` / `addr:province`) — common in US/CA/AU, `null` where not tagged |
| `phone`, `website` | Contact |
| `osm_id`, `osm_type`, `all_tags`, `source_url` | OpenStreetMap identifiers, raw tags, and link |
| `full_address` | All present address parts in one string (e.g. `Main St 1, 10115 Berlin`) |
| `map_url` | Google Maps link to the coordinates |

#### Example output

```json
{
  "name": "Edeka",
  "brand": "Edeka",
  "brand_wikidata": "Q701755",
  "operator": "Edeka Müller",
  "shop": "supermarket",
  "opening_hours": "Mo-Sa 08:00-22:00",
  "organic": "only",
  "wheelchair": "yes",
  "payment_methods": ["cash", "visa", "mastercard"],
  "city": "Berlin",
  "street": "Beusselstraße",
  "housenumber": "55",
  "postcode": "10553",
  "country": "DE",
  "latitude": 52.5301,
  "longitude": 13.3217,
  "osm_type": "node",
  "source_url": "https://www.openstreetmap.org/node/..."
}
```

Any field is `null` (or an empty array) when the store hasn't tagged it in OpenStreetMap — values are never guessed.

### FAQ

**Do I need an API key or account?**
No — give it an area (plus optional radius/name/brand filters) and run. No data-provider key, no quota, no setup.

**Is the data legal to use and redistribute?**
Yes. It comes from OpenStreetMap under the Open Database License (ODbL): public data you can redistribute with attribution (© OpenStreetMap contributors). No logins, no Terms-of-Service violations.

**How is this different from a delivery-app (Glovo/iFood) or Google Maps scraper?**
It uses open OpenStreetMap data instead of scraping a site behind anti-bot defenses and Terms of Service — so it's legal, needs no API key, and returns an honest `null` for anything OSM hasn't mapped instead of guessing. You get store locations and attributes (brand, organic, payment, hours) across all chains — not one retailer's catalogue.

**How much does it cost?**
Pay-per-result: **$3 per 1,000 results** — you only pay for the rows you actually get.

**Which countries does it cover?**
Worldwide — anywhere OpenStreetMap has data.

**How fresh is the data?**
It's pulled live from OpenStreetMap at run time, so it reflects the current map.

### Data source & license

Data comes from **OpenStreetMap** via the public **Nominatim** (geocoding) and **Overpass** (querying) APIs. OpenStreetMap data is **© OpenStreetMap contributors**, licensed under the **Open Database License (ODbL)**. If you publish or redistribute results, attribute "© OpenStreetMap contributors".

### Notes

- Coverage and tag richness vary by region — OSM is community-mapped, so dense, well-surveyed areas (e.g. much of Europe) are richer. Brand, opening-hours and wheelchair tagging is especially strong in Germany, the UK, and the Netherlands.

⭐ **Found this useful?** A quick rating on this actor's Store page helps others discover it — and if something is off or you wish it did more, open an issue on the actor. I read every one.

### More OpenStreetMap data actors

Part of **dataquarry**'s family of clean, ODbL OpenStreetMap extractors — same flexible **area / radius / bounding-box / name** search, same honest-null data (a field that isn't mapped is left empty, never guessed):

- [OpenStreetMap Places Scraper](https://apify.com/dataquarry/osm-places-scraper) — POI & local business, 115+ categories
- [EV Charging Stations Scraper](https://apify.com/dataquarry/ev-charging-stations) — socket types, power (kW), networks
- [Hotels & Lodging Scraper](https://apify.com/dataquarry/hotels-lodging) — stars, rooms, brands
- [Healthcare Facilities Scraper](https://apify.com/dataquarry/healthcare-facilities) — pharmacies, doctors, dentists, clinics
- [Tourist Attractions & Museums Scraper](https://apify.com/dataquarry/tourist-attractions) — Wikidata & Wikipedia links
- [Fuel Station Scraper](https://apify.com/dataquarry/fuel-stations) — fuel types, brands, payment methods
- [Supermarket & Grocery Scraper](https://apify.com/dataquarry/supermarkets) — brands, organic, payment methods

# Actor input Schema

## `area` (type: `string`):

Place to search within, e.g. "Berlin, Germany". Geocoded to a bounding box via Nominatim. Provide this OR a bounding box OR a center for radius search.

## `aroundLocation` (type: `string`):

Optional. An address or place to search AROUND within a radius, e.g. "Alexanderplatz, Berlin". Geocoded to a center point; set the radius with "radiusMeters".

## `radiusMeters` (type: `integer`):

Radius in meters for the around-a-location search (used with Around Location or Center Point). Default 5000.

## `centerPoint` (type: `object`):

Optional advanced alternative: an explicit center as {"lat":.., "lon":..} to search around. Overrides Around Location when set.

## `boundingBox` (type: `object`):

Explicit bounding box as {"south":..,"west":..,"north":..,"east":..}. Overrides Area when set.

## `storeTypes` (type: `array`):

Which store types to include. Supported: supermarket, convenience, greengrocer. Default: all of them.

## `searchTerm` (type: `string`):

Optional. Only return stores whose name contains this text (case-insensitive), e.g. "Edeka", "Lidl", "Aldi", "Rewe".

## `maxResults` (type: `integer`):

Maximum number of supermarkets / grocery stores to return.

## Actor input object example

```json
{
  "area": "Berlin, Germany",
  "radiusMeters": 5000,
  "storeTypes": [
    "supermarket",
    "convenience"
  ],
  "maxResults": 1000
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "area": "Berlin, Germany",
    "storeTypes": [
        "supermarket",
        "convenience"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataquarry/supermarkets").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "area": "Berlin, Germany",
    "storeTypes": [
        "supermarket",
        "convenience",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("dataquarry/supermarkets").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "area": "Berlin, Germany",
  "storeTypes": [
    "supermarket",
    "convenience"
  ]
}' |
apify call dataquarry/supermarkets --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataquarry/supermarkets"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xF1fB0FQZn5iSJIuq/builds/AurggGM0L953MERnN/openapi.json
