Extracting Data from Google Maps with JavaScript: Complete Guide
Google Maps contains 50M+ business listings. Each listing = address, phone, reviews, hours, photos, website. It’s a goldmine for prospecting, market research, competitive analysis.
But how do you extract this data at scale? There are three approaches: the official Google Maps API, custom JavaScript web scraping, or a dedicated tool. This article covers all three — with their real costs, limits, and when to use each.
Why Extract Data from Google Maps?
Before diving into the technique, clarify your need. Use cases are not the same.
Commercial Prospecting
A cleaning agency wants to find 500 restaurants within a 10 km radius. It exports: name, address, phone, email. It does targeted cold calling.
Need: basic data (name, contact), speed, average volume.
Competitive Analysis
A restaurateur analyzes 50 competing restaurants: Google reviews, number of reviews, hours, prices (via the website), photos, technologies used (do they use Uber Eats? Deliveroo? Their own site?).
Need: enriched data (reviews, tech stack), context, low to medium volume.
Market Research
A franchisor analyzes 1,000+ hairdressers in France to identify underserved areas. It extracts: location, Google rating, number of reviews, hours, claimed or unclaimed listing.
Need: structured data, advanced filtering, high volume, monthly updates.
Qualified Lead Detection
An SEO agency looks for restaurants with a rating < 3 stars (potential dissatisfied customers). It exports those with 50+ reviews (significant size) and a website without Google Analytics.
Need: Google reviews (text + rating + date), technology detection, complex filters, medium volume.
Each use case involves a different approach. Let’s look at the options.
Option 1: The Official Google Maps JavaScript API
Google offers a free JavaScript API (with quotas). It works in the browser or in Node.js server-side.
Basic Features
The Google Maps JavaScript API allows for 3 main things:
- Geocoding: convert an address → GPS coordinates
- Places API: search for places (restaurants, plumbers, etc.) around a location
- Place Details: retrieve detailed information about a place (reviews, hours, photos, URL, etc.)
Step 1: Get an API Key
- Go to Google Cloud Console
- Create a project
- Enable these APIs: - Maps JavaScript API - Places API - Geocoding API
- Create an API key (type: browser key or server key depending on your usage)
- Configure restrictions (allowed domains, quotas)
Important: Google charges beyond the free quotas. By default: 25,000 calls/day free for Places, then €0.017 per call.
Step 2: Implement Geocoding
Convert an address to latitude/longitude.
const geocoder = new google.maps.Geocoder();
geocoder.geocode(
{ address: '75 Rue de Rivoli, Paris' },
(results, status) => {
if (status === 'OK') {
const lat = results[0].geometry.location.lat();
const lng = results[0].geometry.location.lng();
console.log(`Coordinates: ${lat}, ${lng}`);
} else {
console.error(`Error: ${status}`);
}
}
);
Step 3: Search for Nearby Places (Nearby Search)
Find all restaurants within a 5 km radius around Paris.
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 48.8566, lng: 2.3522 }, // Paris
zoom: 15
});
const service = new google.maps.places.PlacesService(map);
const request = {
location: new google.maps.LatLng(48.8566, 2.3522),
radius: 5000, // 5 km
type: 'restaurant',
keyword: 'pizza' // Optional: filter by keyword
};
service.nearbySearch(request, (results, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
results.forEach(place => {
console.log(`${place.name} - ${place.vicinity}`);
});
}
});
Important limitation: nearbySearch() returns max 60 results per request, with pagination. To get 500 restaurants, you need to make 9 requests.
Step 4: Retrieve Complete Details (Place Details)
Each place returned by nearbySearch() has a place_id. Use it to get the complete details.
const request = {
placeId: 'ChIJIQBpAG2ahYAR_6128GltTXQ', // Example: Eiffel Tower
fields: [
'name',
'formatted_address',
'formatted_phone_number',
'website',
'opening_hours',
'reviews',
'rating',
'user_ratings_total',
'photos'
]
};
service.getDetails(request, (place, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
console.log(`Name: ${place.name}`);
console.log(`Address: ${place.formatted_address}`);
console.log(`Phone: ${place.formatted_phone_number}`);
console.log(`Website: ${place.website}`);
console.log(`Rating: ${place.rating} (${place.user_ratings_total} reviews)`);
console.log(`Hours:`, place.opening_hours.weekday_text);
// Google Reviews
place.reviews.forEach(review => {
console.log(`${review.author_name}: ${review.rating}/5 - "${review.text}"`);
});
}
});
Real Costs of the Google Maps API
| Operation | Free Quota | Price Beyond |
|---|---|---|
| Geocoding | 25,000/day | €0.005 per call |
| Nearby Search | 25,000/day | €0.032 per call |
| Place Details | 25,000/day | €0.017 per call |
| Text Search | 25,000/day | €0.032 per call |
Real example: extract 1,000 restaurants with complete details.
- 1,000 Nearby Searches = 17 calls (60 results/call max) = €0.54
- 1,000 Place Details = €17
Total: ~€17.50 for 1,000 restaurants.
It seems low, but: - You need to do it again every month for updates - You are limited to 60 results per request (hard to paginate) - The returned Google reviews are limited (max 5 per place) - You do not get detected technologies (WordPress, Shopify, etc.)
Limitations of the Google Maps JavaScript API
| Limitation | Impact |
|---|---|
| Max 60 results per request | Complex manual pagination |
| Max 5 reviews per place | No complete review analysis |
| No filtering by Google rating | You retrieve all results |
| No filtering by number of reviews | No targeting on "mature" listings |
| No technology detection | You don’t know if the site uses WordPress, Shopify, etc. |
| No SIRET data (France) | No legal/financial enrichment |
| Limited quotas | Costs can rise quickly at scale |
Option 2: Custom JavaScript Web Scraping with Puppeteer
If you want to bypass the limitations of the official API, you can scrape the Google Maps site directly with Puppeteer (a Node.js library that automates a Chrome browser).
Why Puppeteer?
Puppeteer launches an automated Chrome browser, goes to Google Maps, simulates clicks/scrolls, and extracts the HTML. This way, you can retrieve more than 60 results, complete reviews, photos, etc.
Installation
npm install puppeteer
Example: Scraping Restaurants in Paris
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Go to Google Maps
await page.goto('https://www.google.com/maps/search/restaurants+paris', {
waitUntil: 'networkidle2'
});
// Wait for the results to load
await page.waitForSelector('[role="listitem"]');
// Scroll to load more results
const resultsContainer = await page.$('[role="main"]');
for (let i = 0; i < 5; i++) {
await resultsContainer.evaluate(el => {
el.scrollTop = el.scrollHeight;
});
await page.waitForTimeout(1000); // Wait for loading
}
// Extract the data
const restaurants = await page.evaluate(() => {
const items = document.querySelectorAll('[role="listitem"]');
return Array.from(items).map(item => {
const nameEl = item.querySelector('[role="heading"]');
const ratingEl = item.querySelector('[aria-label*="étoile"]');
const addressEl = item.querySelector('[data-item-id*="address"]');
return {
name: nameEl ? nameEl.textContent : 'N/A',
rating: ratingEl ? ratingEl.getAttribute('aria-label') : 'N/A',
address: addressEl ? addressEl.textContent : 'N/A'
};
});
});
console.log(restaurants);
await browser.close();
})();
Issues with This Approach
-
Google blocks quickly: After 10-20 requests, Google detects scraping and asks you to confirm you are not a robot (CAPTCHA).
-
Constant maintenance: Google regularly changes its HTML. Your code breaks every 2-3 months.
-
Slow: Puppeteer has to launch a full browser for each search. Scraping 10,000 restaurants = 10,000 browsers launched = hours of execution.
-
Resource-intensive: Each browser consumes 100-200 MB of RAM. Scraping in parallel = powerful server required.
-
Against terms of service: Google explicitly prohibits scraping Maps.
Verdict: Puppeteer works for one-off tests (50-100 results), not for large-scale extraction.
Option 3: Use a Dedicated No-Code Tool
This is the most pragmatic solution for 95% of use cases. Instead of coding, you use a tool that:
- Handles extraction at scale
- Bypasses Google blocks
- Returns structured data (CSV, JSON, API)
- Includes complete Google reviews
- Detects technologies used
- Updates data monthly
Why a Dedicated Tool?
| Criterion | Google API | Puppeteer | Dedicated Tool |
|---|---|---|---|
| Cost for 10,000 results | €170+ | Free (but slow) | €44-99/month |
| Time for 10,000 results | 2-3 days (quotas) | 4-6 hours | 5 minutes |
| Complete Google reviews | Max 5 per place | Yes | Yes |
| Filtering by Google rating | No | No | Yes |
| Technology detection | No | No | Yes |
| Maintenance | High (API changes) | High (HTML changes) | Zero |
| Google blocking | Rare | Frequent | Never |
Practical Use Cases with JavaScript
Here are 3 real scenarios and how to implement them.
Case 1: Find 50 Plumbers in Lyon with the Google Maps API
Need: name, address, phone, website, rating. Low volume. Limited budget.
Solution: Official Google Maps API.
async function findPlumbers(city, limit = 50) {
const geocoder = new google.maps.Geocoder();
// Geocode the city
const cityCoords = await new Promise((resolve) => {
geocoder.geocode({ address: city }, (results) => {
resolve(results[0].geometry.location);
});
});
const map = new google.maps.Map(document.getElementById('map'), {
center: cityCoords,
zoom: 12
});
const service = new google.maps.places.PlacesService(map);
const allResults = [];
// Make multiple requests (max 60 per request)
for (let i = 0; i < Math.ceil(limit / 60); i++) {
const results = await new Promise((resolve) => {
service.nearbySearch(
{
location: cityCoords,
radius: 15000,
type: 'plumber',
pageToken: i === 0 ? null : nextPageToken
},
(results, status, pagination) => {
nextPageToken = pagination.nextPage ? pagination.nextPageToken : null;
resolve(results || []);
}
);
});
allResults.push(...results);
if (allResults.length >= limit) break;
}
// Retrieve details for each result
const details = await Promise.all(
allResults.slice(0, limit).map(place => {
return new Promise((resolve) => {
service.getDetails(
{
placeId: place.place_id,
fields: ['name', 'formatted_address', 'formatted_phone_number', 'website', 'rating']
},
(place) => resolve(place)
);
});
})
);
return details.map(p => ({
name: p.name,
address: p.formatted_address,
phone: p.formatted_phone_number,
website: p.website,
rating: p.rating
}));
}
// Usage
findPlumbers('Lyon').then(plumbers => {
console.table(plumbers);
// Export to CSV
downloadCSV(plumbers);
});
Cost: ~€0.50 (17 Nearby requests + 50 Place Details)
Time: 30 seconds
Limitation: You don’t know which are claimed, how many reviews they have, or if they use a custom site/Wix/Squarespace.
Case 2: Analyze 200 Competing Restaurants (Reviews, Technologies)
Need: complete reviews, rating, number of reviews, technologies used. Medium volume. Average budget.
Solution: Dedicated tool (the Google Maps API only gives 5 max reviews).
With a tool, you export in 5 minutes:
Name,Address,Rating,Number of Reviews,Review (text),Review (date),Review (author),Website,Detected Technologies
Le Jules Verne,5 Rue Eiffel,4.8,1250,"Excellent value for money",2024-01-15,Pierre M.,lejulesverne.fr,"WordPress, WooCommerce, Google Analytics"
Septime,80 Rue Charonne,4.7,890,"Impeccable service",2024-01-14,Marie D.,septimeparis.com,"Custom, Shopify"
You can then: - Identify well-rated restaurants (4.5+) with 500+ reviews (significant size) - Read negative reviews to identify competitors' weaknesses - See which restaurants use Shopify (they sell online) vs WordPress (custom site)
Case 3: ABM Prospecting — Find 500 Restaurants with Website Without Google Analytics
Need: medium-sized restaurants (50-200 reviews), rating 3.5+, website without Google Analytics (potential lead for SEO/analytics agency).
Solution: Dedicated tool with advanced filters and technology detection.
```javascript // Pseudo-code (the Google Maps API cannot do this) const restaurants = await tool.search({ location: 'France', category: 'restaurant', minRating: 3.5, minReviews: 50, maxReviews: 200, hasWebsite: true, missingTechnology: 'Google Analytics' // EXCLUSIVE });
// Result: 500 qualified restaurants // You contact them with: "We noticed your site doesn’t have
Ready to get started?
Access every Google Maps business, enriched with emails and legal data.
Try IBLead freeRelated articles
10 Proven Tips to Get Customers to Leave More Google Reviews on Maps
Learn 10 actionable strategies to increase Google Maps reviews. Timing, incentives, QR codes, and response tactics that actually work.
7 Cold Email Mistakes to Avoid: Examples & Templates
Avoid these 7 cold email mistakes to avoid examples that kill response rates. Real examples, AIDA templates, and proven fixes for better outreach.
ABM Google Maps Data: The Complete Strategic Guide
Learn how abc account based marketing google maps data drives 208% more revenue. Build precise target lists with 50M+ pre-indexed businesses.