<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jim Miller</title>
    <description>The latest articles on DEV Community by Jim Miller (@jimmiller26).</description>
    <link>https://dev.to/jimmiller26</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200639%2F6134cfd7-84fb-4011-bb86-465b4e38bc2c.png</url>
      <title>DEV Community: Jim Miller</title>
      <link>https://dev.to/jimmiller26</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jimmiller26"/>
    <language>en</language>
    <item>
      <title>Google Maps Data via MCP: Cursor, Claude Code, Codex, and Claude Desktop</title>
      <dc:creator>Jim Miller</dc:creator>
      <pubDate>Sat, 31 Oct 2026 01:21:12 +0000</pubDate>
      <link>https://dev.to/jimmiller26/google-maps-data-via-mcp-cursor-claude-code-codex-and-claude-desktop-3p2c</link>
      <guid>https://dev.to/jimmiller26/google-maps-data-via-mcp-cursor-claude-code-codex-and-claude-desktop-3p2c</guid>
      <description>&lt;p&gt;&lt;em&gt;Connect your AI client, pull one page of businesses, then check reviews or photos for a single place.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I work on growth at GMapsScraper.AI. This post is about the workflow: getting Google Maps business data into an AI client and keeping each request small enough to check by hand.&lt;/p&gt;

&lt;p&gt;My usual question is which businesses operate in an area and which deserve a second look. I could write a script for that. With MCP, I ask in Cursor and the model calls the tool. The &lt;a href="https://gmapsscraper.ai/google-maps-scraper-mcp" rel="noopener noreferrer"&gt;GMapsScraper.AI MCP server&lt;/a&gt; has three tools: business search, reviews, and photos.&lt;/p&gt;

&lt;p&gt;I'll walk through it in Cursor. Setup for Claude Code, Codex, and Claude Desktop is further down; the prompts don't change between clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Cursor
&lt;/h2&gt;

&lt;p&gt;In your &lt;a href="https://gmapsscraper.ai" rel="noopener noreferrer"&gt;GMapsScraper.AI account&lt;/a&gt;, go to &lt;strong&gt;Dashboard &amp;gt; Settings &amp;gt; Create API Key&lt;/strong&gt;. The snippets below use &lt;code&gt;YOUR_API_KEY&lt;/code&gt; as the placeholder; paste your key there and keep the space after &lt;code&gt;Bearer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the server to &lt;code&gt;.cursor/mcp.json&lt;/code&gt; for one project, or &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt; for all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gmapsscraper"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://gmapsscraper.ai/api/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the file already has servers, add the &lt;code&gt;gmapsscraper&lt;/code&gt; entry inside the existing &lt;code&gt;mcpServers&lt;/code&gt; object. If the project-level file sits in a shared repo, add it to &lt;code&gt;.gitignore&lt;/code&gt; or use the home-directory version.&lt;/p&gt;

&lt;h2&gt;
  
  
  First search: one page, five rows on screen
&lt;/h2&gt;

&lt;p&gt;For the example, I'm searching for roofing contractors with &lt;code&gt;scrape_google_maps_search&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"roofing contractor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ll"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@40.6970194,-74.3093048,11z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ll&lt;/code&gt; is &lt;code&gt;@lat,lng,zoom&lt;/code&gt;; this one is centered in northern New Jersey at zoom 11. Always set it. Leave it out and the tool falls back to a default US location, and a table of roofers from the wrong region looks exactly as convincing as the right one. &lt;code&gt;hl&lt;/code&gt; and &lt;code&gt;gl&lt;/code&gt; default to &lt;code&gt;en&lt;/code&gt; and &lt;code&gt;us&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Call &lt;code&gt;scrape_google_maps_search&lt;/code&gt; once with the arguments above, page 1 only. Show up to five businesses with Name, Fulladdress, Phone, Website, Average Rating, and Review Count. Keep each Fid and Google Maps URL for later. Leave missing values blank. Don't call reviews, photos, or another page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Five is a display limit, not a request size. The last sentence is what keeps the model from fetching more on its own.&lt;/p&gt;

&lt;p&gt;The response has &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;data&lt;/code&gt;. The keys inside &lt;code&gt;data&lt;/code&gt; aren't consistent: &lt;code&gt;Fulladdress&lt;/code&gt; is one word, &lt;code&gt;Review Count&lt;/code&gt; and &lt;code&gt;Average Rating&lt;/code&gt; have spaces, and the contact fields are lowercase (&lt;code&gt;emails&lt;/code&gt;, &lt;code&gt;facebook_links&lt;/code&gt;). I copy them into prompts as-is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the rows before asking for more
&lt;/h2&gt;

&lt;p&gt;I check addresses first, then &lt;code&gt;Categories&lt;/code&gt;, to see whether each business is the kind I searched for. If the page looks right, I filter what's already there instead of fetching more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the search data already returned, list businesses where Website is blank, with Name, Fulladdress, Phone, Review Count, and Google Maps URL. Label them "website not returned." No new tool calls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The label is deliberate: a blank &lt;code&gt;Website&lt;/code&gt; means the field came back empty, not that the business has no site.&lt;/p&gt;

&lt;p&gt;I leave &lt;code&gt;extra&lt;/code&gt; at &lt;code&gt;false&lt;/code&gt; on this pass. Setting it to &lt;code&gt;true&lt;/code&gt; asks for emails and social links, but the API doesn't return those fields on the free plan, and emails only appear when a listing has one.&lt;/p&gt;

&lt;p&gt;Since emails came up: respect Google's terms and privacy and anti-spam laws (GDPR, CCPA, CAN-SPAM), collect only what you need, honor opt-outs, and don't target individual reviewers.&lt;/p&gt;

&lt;h2&gt;
  
  
  One place, one follow-up
&lt;/h2&gt;

&lt;p&gt;Pick one business and pass its returned &lt;code&gt;Fid&lt;/code&gt; to the next tool as &lt;code&gt;fid&lt;/code&gt;, not an identifier the model rebuilds from the business name. Both follow-up tools also accept a Google Maps place URL as &lt;code&gt;url&lt;/code&gt;, handy for a link a teammate pasted. Then choose reviews or photos, whichever answers your question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviews
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scrape_google_maps_reviews&lt;/code&gt; takes &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;page&lt;/code&gt;, and &lt;code&gt;sort_by&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt;: relevant&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt;: newest&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt;: highest rating&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt;: lowest rating&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For the business I picked, call &lt;code&gt;scrape_google_maps_reviews&lt;/code&gt; with its Fid as fid, page 1, sort_by 2. Summarize recurring service themes from that page without naming reviewers. Say that the summary covers page 1, newest first. Report next, then stop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The response includes &lt;code&gt;reviews&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;place&lt;/code&gt;. If I'm looking for a recurring complaint, &lt;code&gt;sort_by&lt;/code&gt; 4 gets there faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Photos
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scrape_google_maps_photos&lt;/code&gt; takes &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt; plus &lt;code&gt;page&lt;/code&gt;, with no &lt;code&gt;sort_by&lt;/code&gt;. Its response has &lt;code&gt;photos&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;place&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other clients
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http gmapsscraper https://gmapsscraper.ai/api/mcp &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;Codex reads the key from an environment variable. Set &lt;code&gt;GMAPS_API_KEY&lt;/code&gt; to your key where Codex runs (for example, &lt;code&gt;export GMAPS_API_KEY=...&lt;/code&gt; in your shell profile), then pass the variable's name, not &lt;code&gt;$GMAPS_API_KEY&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex mcp add gmapsscraper &lt;span class="nt"&gt;--url&lt;/span&gt; https://gmapsscraper.ai/api/mcp &lt;span class="nt"&gt;--bearer-token-env-var&lt;/span&gt; GMAPS_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Claude Desktop through mcp-remote
&lt;/h3&gt;

&lt;p&gt;Claude Desktop's config file launches local stdio servers, so this goes through the open-source &lt;code&gt;mcp-remote&lt;/code&gt; bridge, run via &lt;code&gt;npx&lt;/code&gt; (Node required):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gmapsscraper"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://gmapsscraper.ai/api/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${GMAPS_AUTH}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"GMAPS_AUTH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your key goes only in &lt;code&gt;env.GMAPS_AUTH&lt;/code&gt;; leave &lt;code&gt;Authorization:${GMAPS_AUTH}&lt;/code&gt; as written, with no space after the colon.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the tools don't show up
&lt;/h2&gt;

&lt;p&gt;Before rewording prompts, rule out the connection with MCP Inspector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @modelcontextprotocol/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose &lt;strong&gt;Streamable HTTP&lt;/strong&gt;, enter &lt;code&gt;https://gmapsscraper.ai/api/mcp&lt;/code&gt;, add an &lt;code&gt;Authorization&lt;/code&gt; header with the value &lt;code&gt;Bearer YOUR_API_KEY&lt;/code&gt;, connect, and run &lt;code&gt;tools/list&lt;/code&gt;. You should see three tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;scrape_google_maps_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scrape_google_maps_reviews&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scrape_google_maps_photos&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If they appear here but not in your client, the problem is the client config: the env var for Codex, &lt;code&gt;GMAPS_AUTH&lt;/code&gt; or &lt;code&gt;npx&lt;/code&gt; for Claude Desktop, the JSON for Cursor. If they don't appear here either, check the key and header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quota
&lt;/h2&gt;

&lt;p&gt;MCP uses the same key, rate limits, quota, and response shapes as the &lt;a href="https://gmapsscraper.ai/google-maps-scraper-api" rel="noopener noreferrer"&gt;GMapsScraper.AI REST API&lt;/a&gt;, so the field names here carry over if you move to a script later. API usage is billed by request quota, separate from web app credits; check &lt;a href="https://gmapsscraper.ai/pricing" rel="noopener noreferrer"&gt;GMapsScraper.AI pricing&lt;/a&gt; before planning anything bigger than this walkthrough.&lt;/p&gt;

&lt;p&gt;That's also why my first request is always a single page. If I got &lt;code&gt;ll&lt;/code&gt; wrong, I've spent one request finding out.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jim Miller, Growth at GMapsScraper.AI&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>cursor</category>
      <category>claude</category>
      <category>api</category>
    </item>
    <item>
      <title>A Google Maps Review Scraper for a Place Shortlist</title>
      <dc:creator>Jim Miller</dc:creator>
      <pubDate>Fri, 30 Oct 2026 13:49:31 +0000</pubDate>
      <link>https://dev.to/jimmiller26/a-google-maps-review-scraper-for-a-place-shortlist-361m</link>
      <guid>https://dev.to/jimmiller26/a-google-maps-review-scraper-for-a-place-shortlist-361m</guid>
      <description>&lt;h1&gt;
  
  
  A Google Maps Review Scraper for a Place Shortlist
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Fetch recent review pages with Python, keep each request tied to a place, and stop at a clear limit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The shortlist already has names and addresses. The open question is whether recent reviews mention long waits.&lt;/p&gt;

&lt;p&gt;For that, I use the &lt;a href="https://gmapsscraper.ai/google-maps-reviews-scraper" rel="noopener noreferrer"&gt;GMapsScraper.AI reviews scraper&lt;/a&gt;. The Python script below fetches review pages for one place, saves the full responses, and tells me whether there's another page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which branch is this?
&lt;/h2&gt;

&lt;p&gt;The request takes either &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt;. Use the &lt;code&gt;Fid&lt;/code&gt; from a business search, or that business's Google Maps place URL. A business name alone won't work here. For chains, compare the full address with your shortlist before copying the reference.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Place Id&lt;/code&gt; looks like the obvious field to copy, but the reviews call wants &lt;code&gt;Fid&lt;/code&gt; as &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;Google Maps URL&lt;/code&gt; as &lt;code&gt;url&lt;/code&gt;. &lt;code&gt;Place Id&lt;/code&gt; is a different key in the search response, so don't pass it as &lt;code&gt;fid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Without either reference, search first with &lt;code&gt;POST /api/v1/search&lt;/code&gt;. It only needs &lt;code&gt;q&lt;/code&gt;, but set &lt;code&gt;ll&lt;/code&gt;, &lt;code&gt;hl&lt;/code&gt;, and &lt;code&gt;gl&lt;/code&gt; for location, language, and country; without &lt;code&gt;ll&lt;/code&gt;, the search defaults to a US location. Compare the returned name and address with the shortlist row.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gmapsscraper.ai/google-maps-scraper-api" rel="noopener noreferrer"&gt;GMapsScraper.AI API reference&lt;/a&gt; covers both calls. Once the address matches, copy that row's &lt;code&gt;Fid&lt;/code&gt; or URL into the shortlist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review order
&lt;/h2&gt;

&lt;p&gt;The place reference stays the same. Add &lt;code&gt;page&lt;/code&gt; and &lt;code&gt;sort_by&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Relevant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Newest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highest rating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lowest rating&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I use &lt;code&gt;2&lt;/code&gt; for this question. If you sort by highest or lowest rating instead, write that in your notes, so nobody reads a lowest-first page as typical.&lt;/p&gt;

&lt;p&gt;Newest first isn't a date filter. There's no start or end date in this request. If you need a cutoff, such as the last few months, check the dates in the saved reviews before choosing which ones to include.&lt;/p&gt;

&lt;p&gt;The response includes &lt;code&gt;reviews&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;place&lt;/code&gt;. The boolean &lt;code&gt;next&lt;/code&gt; signals another page. The script's &lt;code&gt;--max-pages&lt;/code&gt; cap limits each run, and I keep it at one until I've opened the JSON. Anything you conclude from that file covers only the reviews on that page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save the raw pages
&lt;/h2&gt;

&lt;p&gt;Create an API key under &lt;strong&gt;Dashboard &amp;gt; Settings &amp;gt; Create API Key&lt;/strong&gt; and set it in the shell you'll use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GMAPS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'YOUR_API_KEY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this complete block as &lt;code&gt;fetch_reviews.py&lt;/code&gt;. It needs only Python's standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urlopen&lt;/span&gt;

&lt;span class="n"&gt;ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://gmapsscraper.ai/api/v1/reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;positive_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentTypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use a positive integer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_mutually_exclusive_group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--fid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;positive_int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--max-pages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;positive_int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--sort-by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GMAPS_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Set GMAPS_API_KEY to your real API key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fid&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The place reference cannot be blank&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_pages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sort_by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Inspect next in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing reviews in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;; next=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a first call. Replace the placeholder with the place URL from the shortlist row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 fetch_reviews.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'YOUR_GOOGLE_MAPS_PLACE_URL'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--sort-by&lt;/span&gt; 2 &lt;span class="nt"&gt;--max-pages&lt;/span&gt; 1 &lt;span class="nt"&gt;--out&lt;/span&gt; review-check-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pass &lt;code&gt;--fid 'YOUR_FID'&lt;/code&gt; instead of &lt;code&gt;--url&lt;/code&gt;. The command refuses both together. If the saved page has &lt;code&gt;next: true&lt;/code&gt;, you can continue with &lt;code&gt;--page 2&lt;/code&gt; and a new output folder. &lt;code&gt;--max-pages&lt;/code&gt; counts pages from that starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read page one against the question
&lt;/h2&gt;

&lt;p&gt;Open &lt;code&gt;page-1.json&lt;/code&gt; and compare &lt;code&gt;place&lt;/code&gt; with the shortlist address and &lt;code&gt;params&lt;/code&gt; with the sort you asked for, before reading any review.&lt;/p&gt;

&lt;p&gt;Inspect one saved review before choosing the text, date, and rating fields for your parser. The parser reads the saved file, so changing it costs no requests. Print the record keys locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review-check-01/page-1.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My notes for each place stay short: the question, the sort order, the pages I read, and the source page for each point. If I set a date cutoff, it goes in the note too. A teammate can then see what was read without fetching it again.&lt;/p&gt;

&lt;p&gt;To call waiting time a common complaint, you need a count. Decide first whether comments like "slow service" belong under waiting time, then count mentions against the number of reviews you read.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the run stops
&lt;/h2&gt;

&lt;p&gt;Each response is written to disk before the loop looks at &lt;code&gt;next&lt;/code&gt;. If a request fails, the script stops there with no retry, and pages saved before the failure stay in the folder. Open the last one before deciding which page to request next. Every run needs a new folder; putting the place in its name keeps pages from two branches apart.&lt;/p&gt;

&lt;p&gt;If the last page says &lt;code&gt;next: true&lt;/code&gt;, the cap stopped the run while more pages were available. If it says &lt;code&gt;next: false&lt;/code&gt;, there are no further pages for that place and sort.&lt;/p&gt;

&lt;p&gt;API calls draw on request quota, which is separate from web app credits, and each key is rate limited. Fetching the same place and page again spends another request, so I parse from the saved files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read with an MCP client if that's where you work
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://gmapsscraper.ai/google-maps-scraper-mcp" rel="noopener noreferrer"&gt;GMapsScraper.AI MCP guide&lt;/a&gt; covers &lt;code&gt;scrape_google_maps_reviews&lt;/code&gt;. It takes &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;page&lt;/code&gt;, and &lt;code&gt;sort_by&lt;/code&gt;, with the same key, quota, rate limits, and response shapes as REST.&lt;/p&gt;

&lt;p&gt;Give the client the &lt;code&gt;fid&lt;/code&gt; or URL and a short instruction: fetch page one with &lt;code&gt;sort_by: 2&lt;/code&gt;, report &lt;code&gt;next&lt;/code&gt;, and stop. Then ask the client to list mentions of waiting time, quote each one, and state how many reviews it read. Check each quote against the full review before sharing the summary.&lt;/p&gt;

&lt;p&gt;If page one doesn't settle the waiting-time question, fetch page two: &lt;code&gt;--page 2&lt;/code&gt; with a new folder, or ask the client for it.&lt;/p&gt;

&lt;p&gt;Reviewer names, and sometimes the review text itself, can identify a person. Keep the saved JSON inside the team, quote only the lines the summary needs, and leave names out of anything that goes further. Check Google's terms and the privacy rules you work under before keeping those files past the task.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jim Miller, Growth at GMapsScraper.AI&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>scraping</category>
      <category>mcp</category>
    </item>
    <item>
      <title>How to Scrape Google Maps Leads from Claude Desktop or Cursor with an MCP Server</title>
      <dc:creator>Jim Miller</dc:creator>
      <pubDate>Thu, 22 Oct 2026 13:51:23 +0000</pubDate>
      <link>https://dev.to/jimmiller26/how-to-scrape-google-maps-leads-from-claude-desktop-or-cursor-with-an-mcp-server-4e9d</link>
      <guid>https://dev.to/jimmiller26/how-to-scrape-google-maps-leads-from-claude-desktop-or-cursor-with-an-mcp-server-4e9d</guid>
      <description>&lt;p&gt;I wanted a quick list of roofers in one area without leaving Cursor. Names, phone numbers, websites, and review counts would do. I didn't need a long report. I needed a table I could check.&lt;/p&gt;

&lt;p&gt;That's the workflow I'll walk through here: connect GMapsScraper.AI, fetch one search page, and use those rows to decide what to look at next. The &lt;a href="https://gmapsscraper.ai/google-maps-scraper-mcp" rel="noopener noreferrer"&gt;GMapsScraper.AI MCP connection guide&lt;/a&gt; covers the remote server for business searches, reviews, and photos.&lt;/p&gt;

&lt;p&gt;The useful part is being specific. “Find me leads” leaves the area and amount of work open. “Find roofers here, fetch page 1, then stop” gives you a clear first step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your API key
&lt;/h2&gt;

&lt;p&gt;Start by &lt;a href="https://gmapsscraper.ai" rel="noopener noreferrer"&gt;signing up for GMapsScraper.AI&lt;/a&gt;. Open &lt;strong&gt;Settings &amp;gt; Create API Key&lt;/strong&gt; in the dashboard. You'll use the same key for MCP and the REST API.&lt;/p&gt;

&lt;p&gt;The endpoint is &lt;code&gt;https://gmapsscraper.ai/api/mcp&lt;/code&gt;. Choose &lt;strong&gt;Streamable HTTP&lt;/strong&gt; as the transport. Authentication uses the header &lt;code&gt;Authorization: Bearer YOUR_API_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;YOUR_API_KEY&lt;/code&gt; in the setup below with your key. Keep configs containing it out of shared repositories and screenshots. Pick the client you use; you don't need to set up all four.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Cursor
&lt;/h2&gt;

&lt;p&gt;Add this to &lt;code&gt;.cursor/mcp.json&lt;/code&gt; for one project, or &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt; for all your projects. If the file already has servers, keep them and add this entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gmapsscraper"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://gmapsscraper.ai/api/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'd make the first request small. One page gives you something you can read through before you spend more quota. Check the addresses and field names before asking Cursor to build a longer list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Claude Code
&lt;/h2&gt;

&lt;p&gt;Run this command to add the HTTP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http gmapsscraper https://gmapsscraper.ai/api/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the space between &lt;code&gt;Bearer&lt;/code&gt; and your key. It's a small detail that's easy to lose when copying a header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Claude Desktop with mcp-remote
&lt;/h2&gt;

&lt;p&gt;Claude Desktop's config launches local stdio servers. Use the open-source &lt;code&gt;mcp-remote&lt;/code&gt; bridge to reach this remote server. Add this entry to your Claude Desktop MCP config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gmapsscraper"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"mcp-remote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://gmapsscraper.ai/api/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Authorization:${GMAPS_AUTH}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"GMAPS_AUTH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need &lt;code&gt;npx&lt;/code&gt; available locally. Leave &lt;code&gt;Authorization:${GMAPS_AUTH}&lt;/code&gt; as written. Put your key in &lt;code&gt;env.GMAPS_AUTH&lt;/code&gt; and keep its &lt;code&gt;Bearer&lt;/code&gt; prefix. The bridge runs on your machine and connects to the remote MCP endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Codex
&lt;/h2&gt;

&lt;p&gt;Set the key in the shell you'll use to run Codex, then add the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GMAPS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'YOUR_API_KEY'&lt;/span&gt;
codex mcp add gmapsscraper &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://gmapsscraper.ai/api/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bearer-token-env-var&lt;/span&gt; GMAPS_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last argument takes the &lt;strong&gt;name of the environment variable&lt;/strong&gt;. Keep &lt;code&gt;GMAPS_API_KEY&lt;/code&gt; there. Don't replace it with the token or &lt;code&gt;$GMAPS_API_KEY&lt;/code&gt;. That variable needs to stay available when you run Codex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the connection
&lt;/h2&gt;

&lt;p&gt;If you want to check the server directly, open MCP Inspector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @modelcontextprotocol/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose &lt;strong&gt;Streamable HTTP&lt;/strong&gt;, enter the endpoint, and add an &lt;code&gt;Authorization&lt;/code&gt; header with the value &lt;code&gt;Bearer YOUR_API_KEY&lt;/code&gt;. Connect and run &lt;code&gt;tools/list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should see &lt;code&gt;scrape_google_maps_search&lt;/code&gt;, &lt;code&gt;scrape_google_maps_reviews&lt;/code&gt;, and &lt;code&gt;scrape_google_maps_photos&lt;/code&gt;. Next, try the search arguments below. I like this check because it lets me work through the connection setup before writing a longer prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a business search
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;scrape_google_maps_search&lt;/code&gt; accepts these parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;What to put in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Required search text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Page number; defaults to &lt;code&gt;1&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Location as &lt;code&gt;@lat,lng,zoom&lt;/code&gt;; defaults to a US location.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Language; defaults to &lt;code&gt;"en"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Country; defaults to &lt;code&gt;"us"&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extra&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean requesting email and social fields.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's a first request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"roofing contractor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ll"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@40.6970194,-74.3093048,11z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the location yourself. Change &lt;code&gt;ll&lt;/code&gt;, &lt;code&gt;hl&lt;/code&gt;, and &lt;code&gt;gl&lt;/code&gt; to match your search area, language, and country. Each call fetches one page, so put the page limit in your prompt too.&lt;/p&gt;

&lt;p&gt;The response contains &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and a &lt;code&gt;data&lt;/code&gt; array. For a first table, I'd use &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Fulladdress&lt;/code&gt;, &lt;code&gt;Phone&lt;/code&gt;, &lt;code&gt;Website&lt;/code&gt;, &lt;code&gt;Review Count&lt;/code&gt;, and &lt;code&gt;Average Rating&lt;/code&gt;. Keep &lt;code&gt;Google Maps URL&lt;/code&gt; and &lt;code&gt;Fid&lt;/code&gt; handy for follow-up calls. Code that reads these fields needs their exact spelling and case.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;extra: true&lt;/code&gt; to request emails and social links. The free API plan doesn't return those extra fields. Emails are only available when present, so leave missing contacts blank.&lt;/p&gt;

&lt;p&gt;Before sorting the table, read a few rows. Are the addresses in the area you meant? Is the search term right for the businesses you want? Fix the search first if those basics look wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull reviews or photos for one business
&lt;/h2&gt;

&lt;p&gt;Once you've picked a business, reuse its returned &lt;code&gt;Fid&lt;/code&gt; as &lt;code&gt;fid&lt;/code&gt;, or pass its Google Maps place URL as &lt;code&gt;url&lt;/code&gt;. That keeps the next request tied to the listing you chose.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scrape_google_maps_reviews&lt;/code&gt; takes &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;page&lt;/code&gt;, and &lt;code&gt;sort_by&lt;/code&gt;. The sort values are &lt;code&gt;1&lt;/code&gt; for relevant, &lt;code&gt;2&lt;/code&gt; for newest, &lt;code&gt;3&lt;/code&gt; for highest rating, and &lt;code&gt;4&lt;/code&gt; for lowest rating. For recent reviews, use &lt;code&gt;page: 1&lt;/code&gt; and &lt;code&gt;sort_by: 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The response includes &lt;code&gt;reviews&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;place&lt;/code&gt;. The boolean &lt;code&gt;next&lt;/code&gt; tells you whether another page exists. When summarizing reviews, say which page you read so you can see the scope later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;scrape_google_maps_photos&lt;/code&gt; takes &lt;code&gt;fid&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt;, plus &lt;code&gt;page&lt;/code&gt;. It returns &lt;code&gt;photos&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, and &lt;code&gt;place&lt;/code&gt;. I'd inspect the returned photo data before deciding what belongs in an audit. A count alone won't tell you how old the photos are or how well the business is doing.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gmapsscraper.ai/google-maps-scraper-api" rel="noopener noreferrer"&gt;GMapsScraper.AI REST API reference&lt;/a&gt; has the underlying request and response fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five prompts I'd use
&lt;/h2&gt;

&lt;p&gt;Start with a search, then work from the rows already in the conversation. Replace the location or supply the selected business when needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Get a small lead table&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find roofing contractors with ll "@40.6970194,-74.3093048,11z", hl "en", gl "us", and extra false. Fetch page 1 only. Show Name, Phone, Website, Average Rating, and Review Count. Leave blanks as blanks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. Make a review-count shortlist&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From that page, show businesses with fewer than 30 reviews. Include their Google Maps URLs. No more tool calls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;3. Check missing websites&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From that page, show Name, Fulladdress, and Phone where Website is blank. Label them “website not returned.” Don't guess domains. No new calls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4. Read recent reviews&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For the place URL I give you, fetch reviews page 1 with sort_by 2. Summarize repeated service themes without reviewer names. Show next, then stop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;5. Get photo data for an audit&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use the Fid of the business I pick. Fetch photos page 1 only. Show total and next, then summarize the returned photo data. Stop there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A shortlist is where I start checking businesses. Fewer reviews doesn't tell me whether someone wants help. A blank website field means I should check the listing before pitching a website. Those checks make the list more useful than adding another page of names.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep an eye on quota
&lt;/h2&gt;

&lt;p&gt;MCP uses the same rate limits, request quota, and response shapes as REST. Each API key is rate limited. API request billing is separate from web app credits.&lt;/p&gt;

&lt;p&gt;The web app's free plan gives you 1,000 credits per month, with one credit per business. It allows up to two keywords per task and one concurrent task. Check the &lt;a href="https://gmapsscraper.ai/pricing" rel="noopener noreferrer"&gt;GMapsScraper.AI plans and pricing&lt;/a&gt; when choosing how to use it.&lt;/p&gt;

&lt;p&gt;My approach is simple: read the search page, pick a business, then decide whether reviews or photos would help. Reusing the table for filters saves calls and makes it easier to follow your work.&lt;/p&gt;

&lt;h2&gt;
  
  
  If something goes wrong
&lt;/h2&gt;

&lt;p&gt;If tools don't appear, try &lt;code&gt;tools/list&lt;/code&gt; in Inspector with the same endpoint and key. Compare the settings with your client config. Check the JSON and header first. For Claude Desktop, check that &lt;code&gt;npx&lt;/code&gt; is available too.&lt;/p&gt;

&lt;p&gt;For an auth error, check the &lt;code&gt;Bearer&lt;/code&gt; prefix. In Codex, check that the named environment variable contains the key. In Claude Desktop, check &lt;code&gt;GMAPS_AUTH&lt;/code&gt;. If you hit a quota or rate limit, check API usage and pause further calls while you sort it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep collection focused
&lt;/h2&gt;

&lt;p&gt;GMapsScraper.AI collects publicly available business data. Respect Google's terms and privacy and anti-spam laws, including GDPR, CCPA, and CAN-SPAM. Collect only what you need, honor opt-outs, and don't target individual reviewers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jim Miller, Growth at GMapsScraper.AI&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>cursor</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
