nulled avatar
nulled
Under maintenance

Pricing

from $1.00 / 1,000 results

Go to Apify Store
nulled

nulled

Under maintenance

Scalable Google Maps lead scraper for agencies and growth teams. Extracts clean business data with bulk mode, deduplication, and API-ready datasets. Built for reliable, low-cost lead generation and automation at scale.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

Team Cyber Orbit

Team Cyber Orbit

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

1

Monthly active users

a month ago

Last modified

Share

Google Maps Scraper Actor

Author: Assad Baloch

Apify Actor License: ISC

A robust, production-ready Google Maps scraper using the Apify/Crawlee Playwright stack. The actor supports single and bulk queries, persistent deduplication (dataset-level or global), per-query dataset creation, run summaries, and backup/restore utilities for KV and dataset snapshots.

πŸš€ Features

  • βœ… Single and bulk queries with per-query dataset creation
  • βœ… Persistent deduplication (dataset-level or global) with TTL and key strategy (place_id preferred)
  • βœ… Structured output β€” full lead serialization with metadata and raw snapshots
  • βœ… Backup & restore scripts for KV and datasets
  • βœ… Testable design β€” scraping logic is in lib/scrape.js for unit testing

πŸš€ Features

  • βœ… Low Cost - Session reuse and concurrency=1 minimize proxy usage
  • βœ… Complete Data - Name, website, phone, category, address, rating, reviews
  • βœ… Auto Pagination - Scrolls through results until target reached
  • βœ… No External Visits - Only scrapes Google Maps (no website crawling)
  • βœ… JSON Output - Structured data pushed to Apify Dataset
  • βœ… API Ready - Instant access via Apify API

πŸ“₯ Input Parameters

{
"keyword": "restaurants",
"location": "New York, NY",
"maxResults": 50
}
ParameterTypeRequiredDefaultDescription
keywordstringβœ… Yes-Search term (e.g., "coffee shops", "plumbers")
locationstringβœ… Yes-Location to search (e.g., "Los Angeles, CA")
maxResultsinteger❌ No50Max number of results (1-500)
nichestring❌ No-Optional label used to group results into a named dataset
datasetNamestring❌ No-Optional exact dataset name to save results into
perRunDatasetboolean❌ NofalseIf true, creates a timestamped dataset for this run
  • dedupEnabled | boolean | ❌ No | true | Enable or disable deduplication (recommended: true) | | dedupScope | string | ❌ No | dataset | dataset or global scope for deduplication | | dedupKeyStrategy | string | ❌ No | place_id | place_id preferred; fallback to name_address | | dedupTTLdays | integer | ❌ No | 0 | Days to keep an entry in dedup store (0 = no expiry) | | dedupAutoAdd | boolean | ❌ No | true | Automatically add saved records to dedup store | | dedupSkip | boolean | ❌ No | true | If true, duplicates are skipped (not saved); otherwise they are flagged | | bulkQueries | string | ❌ No | - | Multiline textarea. Each line: keyword | location | tag(optional) | | autoCreateDatasets | boolean | ❌ No | true | If true, creates/uses per-query datasets for bulk runs | | datasetNameTemplate | string | ❌ No | gmaps-{tag || keyword}-{location} | Template for dataset names | | maxParallelQueries | integer | ❌ No | 3 | Max concurrency for bulk queries | | maxQueriesPerRun | integer | ❌ No | 200 | Max queries processed in one run | Note: If you provide a custom datasetName or niche, the actor will sanitize it (lowercase, letters/numbers and hyphens only) to comply with Apify dataset naming rules; you’ll see a warning in logs if the name is modified.

πŸ“€ Output Format

Each business record includes:

{
"business_name": "Blue Bottle Coffee",
"website_url": "https://bluebottlecoffee.com",
"phone_number": "+1 415-555-0123",
"category": "Coffee shop",
"address": "66 Mint St, San Francisco, CA 94103",
"google_maps_url": "https://www.google.com/maps/place/...",
"rating": 4.5,
"total_reviews": 1234
}

🎯 Usage

Via Apify Console

  1. Go to Apify Console
  2. Find your actor
  3. Click "Start"
  4. Enter input parameters
  5. View results in Dataset tab

Example inputs

  • Run into a per-niche dataset and skip duplicates automatically:
{
"keyword": "coffee shop",
"location": "Seattle, WA",
"niche": "coffee-shops-seattle",
"deduplication": "per_niche",
"dedupAuto": true
}
  • Run into a timestamped snapshot dataset and generate a CSV file for download:
{
"keyword": "plumbers",
"location": "Chicago, IL",
"perRunDataset": true,
"downloadAsCsv": true,
"csvOptions": {
"filename": "plumbers-chicago.csv",
"includeDuplicates": false,
"delimiter": ","
}
}

Tip: If you only want to collect results and do dedup manually later, set dedupAuto=false and duplicates will be marked with is_duplicate: true in the saved records.

Via API

Start a Run

curl -X POST https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"keyword": "dentists",
"location": "Chicago, IL",
"maxResults": 100
}'

Get Results

# Get latest run results as JSON
curl https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs/LAST/dataset/items?format=json \
-H "Authorization: Bearer YOUR_API_TOKEN"
# Get as CSV
curl https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs/LAST/dataset/items?format=csv \
-H "Authorization: Bearer YOUR_API_TOKEN"

Via JavaScript/Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({
token: 'YOUR_API_TOKEN',
});
// Start the actor
const run = await client.actor('YOUR_ACTOR_ID').call({
keyword: 'coffee shops',
location: 'Seattle, WA',
maxResults: 75,
});
// Get results
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Scraped ${items.length} businesses`);
items.forEach(business => {
console.log(`${business.business_name} - ${business.rating}⭐`);
});

Via Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_API_TOKEN')
# Start the actor
run = client.actor('YOUR_ACTOR_ID').call(run_input={
'keyword': 'plumbers',
'location': 'Boston, MA',
'maxResults': 50
})
# Get results
items = client.dataset(run['defaultDatasetId']).list_items().items
for item in items:
print(f"{item['business_name']} - {item['rating']}⭐")

πŸ”§ Configuration

Enable Proxies (Important!)

For best results, enable Apify residential proxies:

  1. Go to Actor Settings
  2. Scroll to "Proxy configuration"
  3. Enable "Apify proxy"
  4. Select "Residential proxies"
  5. Click "Save"

Dataset CSV export

The actor no longer generates a separate CSV file automatically. You can download the dataset for any run as CSV directly from the Apify Console (Dataset tab) or via the API using the dataset format=csv parameter.

Example (download dataset as CSV via API):

GET https://api.apify.com/v2/datasets/{datasetId}/items?format=csv
  • Memory: 2048 MB
  • Timeout: 3600 seconds (1 hour)
  • Proxy: Residential proxies

πŸ‡ΊπŸ‡Έ Bulk query examples (USA) β€” 10+ niche input set βœ…

You can paste the following sample directly into the bulkQueries textarea in the actor UI. Each line is a single query in the format keyword | location | tag(optional). The actor will process each line as an independent query and (if autoCreateDatasets is enabled) create a dataset using the datasetNameTemplate (for example: gmaps-home-contractors-united-states).

Run modes:

  • auto (default): the actor runs in bulk if bulkQueries is provided; otherwise single-query mode is used.
  • single: explicit single-query mode β€” requires keyword and location.
  • bulk: explicit bulk mode β€” requires bulkQueries (useful when you want to run a bulk job even if keyword/location are present).

This makes it convenient to use either workflow while keeping validation strict and user-friendly.

Home contractors | United States | home-contractors
HVAC services | United States | hvac
Recruitment agency | United States | recruitment-agency
Digital marketing agency | United States | digital-marketing
Plumbing contractors | United States | plumbers
Electrical contractors | United States | electricians
Landscaping services | United States | landscaping
Roofing contractors | United States | roofing
Cleaning services | United States | cleaning
IT managed services | United States | it-managed-services
Security services | United States | security
Accounting firms | United States | accounting

⚠️ Tip: Country-wide searches can return a lot of results β€” set a reasonable maxResults per query and use maxParallelQueries to balance speed vs resource usage.

You can also save this sample as examples/preset-bulk-usa.txt and copy/paste it into the UI or use it as a starting point for larger bulk runs.

πŸ“Š API Endpoints

After run completion, access results via:

# JSON format
GET https://api.apify.com/v2/datasets/{datasetId}/items?format=json
# CSV format
GET https://api.apify.com/v2/datasets/{datasetId}/items?format=csv
# Excel format
GET https://api.apify.com/v2/datasets/{datasetId}/items?format=xlsx
# XML format
GET https://api.apify.com/v2/datasets/{datasetId}/items?format=xml

Quick access to latest run:

GET https://api.apify.com/v2/acts/{actorId}/runs/LAST/dataset/items?format=json

⚑ Performance

ResultsTimeEst. Cost
10~1 min$0.01
50~3 min$0.03
100~5 min$0.05
500~20 min$0.20

Times and costs are approximate and vary by location/density

πŸ’° Cost Optimization

This actor minimizes costs through:

  1. Session Reuse - Single session used up to 50 times
  2. Low Concurrency - Only 1 concurrent request
  3. Smart Scrolling - Stops when target reached
  4. No External Crawling - Never visits business websites
  5. Efficient Extraction - Minimal wait times

πŸ› οΈ Development

Local Setup

# Clone repository
git clone https://github.com/techkaroshi-Assad/gmaps-scraper-apify-actor.git
cd gmaps-scraper-apify-actor
# Install dependencies
npm install
# Set Apify token
export APIFY_TOKEN=your_token_here
# Run locally
npm start

File Structure

.
β”œβ”€β”€ main.js # Main scraper logic
β”œβ”€β”€ package.json # Dependencies
β”œβ”€β”€ INPUT_SCHEMA.json # Input parameter definitions
β”œβ”€β”€ Dockerfile # Docker configuration
β”œβ”€β”€ .actor/
β”‚ └── actor.json # Actor metadata
└── README.md # This file

User Guide & Local Testing

  • For quick smoke tests that do not require browsers, run:
$node test-smoke.js

This will validate dataset creation, Key-Value store behavior, and run summary saving to the gmaps-run-summaries dataset and KV store.

  • To perform a full local run with browsers (Playwright), install Playwright browsers locally first (large download):
npx playwright install --with-deps
npx apify run

Note: the production Docker image used on Apify already includes browsers.

πŸ› Troubleshooting

No Results Found

  • Verify keyword and location are correct
  • Test the same search on Google Maps manually
  • Try more generic keywords (e.g., "restaurants" vs "vegan restaurants")

Missing Phone/Website

  • Some businesses don't list this information on Google Maps
  • This is expected behavior - the scraper gets all available data

Build Failures

  • Ensure all 5 files are present
  • Check package.json syntax
  • Verify Dockerfile has no extra whitespace

Run Timeouts

  • Reduce maxResults to test (try 10-20)
  • Enable residential proxies in settings
  • Increase timeout in Actor settings

πŸ“š Resources

πŸ”’ Privacy & Terms

  • This actor only scrapes publicly available data from Google Maps
  • Respects Google's robots.txt and terms of service
  • Uses residential proxies to avoid rate limiting
  • No personal data collection beyond public business information

πŸ“ License

IPO License-Tech_Karoshi_@Assad Balouch

ISC License - See LICENSE file for details

🀝 Support

⭐ Credits

Built with:


Made with ❀️ by techkaroshi-Assad

For questions or custom development, reach out via GitHub Issues