Google Maps leads to Google Sheets, automatically
By Doug Nielsen, Product Manager · Updated · first published
A free Apps Script that adds a Hubertino menu to any Google Sheet. From it you start a Google Maps scrape and pull the businesses, with emails, phones, websites and social profiles, into a tab. Rows are matched on Google's place_id, so refreshing, or scraping the same area next month, updates the businesses you already have and appends only new ones. No add-on to install: two files you paste into the sheet's script editor.
Hubertino
├─ Start scrape… categories × locations, max results per search, country
├─ Refresh results pulls rows into the "Hubertino leads" tab (works mid-scrape too)
├─ Auto-refresh until done refreshes every 5 minutes, then removes its own trigger
├─ Set API key… stores your hub_live_… key in Script Properties
└─ HelpSet it up in about three minutes
- 1. Get an API key. Sign up (100 free credits, no card), then create a key in Dashboard → Settings. It starts with
hub_live_and is shown once. - 2. Open the script editor. In your spreadsheet, choose Extensions → Apps Script.
- 3. Paste the code. Replace the contents of
Code.gswith the downloadedCode.gs. - 4. Paste the manifest. Open Project Settings (the gear), tick Show "appsscript.json" manifest file in editor, then replace
appsscript.jsonwith the downloaded one. It limits the script to this spreadsheet and to network calls tohttps://hubertino.com/. - 5. Save and reload the spreadsheet. A Hubertino menu appears next to Help.
- 6. Set the key. Hubertino → Set API key… and paste it; the script checks it against the API before saving. The first run asks you to authorize the script. Google shows “unverified app” for any personal script: choose Advanced → Go to (project name).
- 7. Start a scrape. Hubertino → Start scrape…, fill in categories and locations (one per line), then Refresh results a minute or two later, or choose Auto-refresh until done.
Prefer to set the key by hand? Project Settings → Script Properties → Add script property, named HUBERTINO_API_KEY, with your key as the value.
How the place_id dedupe works
Each refresh reads the tab, indexes it by place_id and then, for every row the API returns, either updates the matching line or appends a new one. When Maps hides the place id, the key falls back to Google's feature id, then the CID, then the Maps link.
- • Nothing gets blanked. An empty value never overwrites a filled cell, so a later scrape run without email lookup keeps the emails you already have.
- • first_seen sticks. It records the day a place first reached the sheet and is never overwritten, so filtering on it shows what's new since your last scrape.
- • Text stays text. Text values carry Sheets' text marker, so
+1 512…phone numbers aren't read as formulas, ZIP codes keep their leading zeros and long CIDs aren't rounded. - • Your columns are safe. The script reads and writes only its own 42 columns (A to
last_updated). Add notes, statuses or formulas to the right. If its header row has been changed, it stops with an explanation instead of writing.
What lands in the sheet
A tab called Hubertino leads, created on first use: place_id first, then the API's other 37 place columns (name, category, email, phone, website, domain, the split address, coordinates, rating, reviews, hours, the five social links, order and booking links, the Maps link and Google's IDs; see the full list), then four the script maintains:
| hubertino_status | found → extracted → enriched, or failed: how complete the row is; excluded for a place on your existing-contacts list (listed free, no email lookup) |
| hubertino_scrape_id | The scrape the row last came from |
| first_seen | The date the place first appeared in this sheet; never overwritten |
| last_updated | When the row was last written |
Refreshing mid-scrape is fine: rows fill in as the scrape progresses and later refreshes complete them. Auto-refresh runs every 5 minutes and removes its own trigger when the scrape finishes or fails, or when the API answers 401, 404 or 410.
Limits and costs
- • Credits. 1 credit per business delivered, from $0.276 per 1,000. Starting a scrape reserves categories × locations × max results (capped at your balance) and refunds what it didn't use. Emails and social links cost nothing extra. See pricing.
- • Size. 1–500 results per search, up to 2,000 category × location searches per scrape, 12 new scrapes per 5 minutes.
- • Big scrapes. The script pages through results 1,000 rows at a time, and Apps Script stops any run after 6 minutes. For tens of thousands of rows, download the CSV from the dashboard or the export endpoint instead.
- • Places only. Review jobs started in the dashboard can't be imported here; refreshing one says so and writes nothing.
Permissions and your key
The key lives in the script's Script Properties. Anyone with edit access to the spreadsheet can open the script editor and read it, so don't share edit access with people who shouldn't spend your credits, and rotate the key in Settings if it leaks. The manifest asks for four scopes: this spreadsheet only, external requests (limited to hubertino.com), the menu and dialogs, and the auto-refresh trigger.
{
"timeZone": "Etc/UTC",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/script.scriptapp"
],
"urlFetchWhitelist": [
"https://hubertino.com/"
]
}Want this to run inside a bigger workflow, or to HubSpot? Use the n8n templates. All integrations: /integrations.
Get a key for your sheet
Start free with 100 credits, no card. The script works on every plan.
Start free with 100 credits