Local SEO & Google Business ProfileLocal rank tracking, reporting and audits · Lesson 16 of 17
Hands-on: local performance data with Search Console, GBP data, Python and Sheets
Video lecture
Hands-on: local performance data with Search Console, GBP data, Python and Sheets
The narrated lecture is in production
Every chapter is scripted and ready. Browse the chapters and read the full transcript now — the video will appear here when it’s published.
Chapters
Transcript of the narration, chapter by chapter.
0:00 Hands-on: local performance data
Here's a common monthly meeting. The SEO agency shows rankings. The profile shows calls. Analytics shows sessions. And nobody can say whether the business is actually doing better. In this lecture you'll build one simple local dashboard that combines Search Console, Business Profile performance and GA4, first with spreadsheet exports, then with a little Python so it runs the same way every month.
0:27 Why combine
Why combine the data? Because each source shows only part of the journey. Search Console shows how your location and service pages perform in organic results. Business Profile performance shows calls, direction requests and website clicks from your profile. GA4, with UTM tagged links, shows what those visitors did on your site. Together, they tell a story an owner can act on.
0:54 Start simple
Here's the key idea: start simple, then automate. Think of it like cooking. You make a recipe by hand a few times before you write it down for others. For one location, exports into a Google Sheet are enough. In Search Console, filter pages containing slash locations, and filter queries with a custom regex, like near me or your city and neighbourhood names. Export both monthly into tabs, and summarise with a pivot table or a QUERY formula.
1:28 Search Console API
Then automate with the Search Console API. The script in the lesson uses a service account whose key path lives in an environment variable, builds the Search Console service, and defines one helper that runs a query and returns a table. It runs two queries: location pages with a page contains filter, and local queries with an including regex filter on the query dimension. It saves both as CSVs, ready for the dashboard. One caution: Search Console anonymises some rare queries, so query level totals are lower than page totals.
2:07 GBP performance
Next, Business Profile performance. Without code, open Performance in your profile, choose the month, and record calls, direction requests, website clicks, bookings and views on Search and Maps. For many locations, the Business Profile manager supports multi location downloads. With code, Google's Business Profile Performance API returns daily metrics per location. But access requires an application and approval, OAuth sign in by someone who manages the location, and the business dot manage scope.
2:39 GBP Performance API call
The lesson's API example uses an authorised session. A profile manager signs in once through an OAuth flow. Then the script requests the fetch multi daily metrics time series endpoint for a location ID, asking for call clicks, website clicks and direction requests over a date range. It returns a nested time series per metric. Metric names and response shapes can change, so check the current API reference before relying on it in production, and store tokens securely.
3:13 Example 1 (simple, illustrative)
Worked example one, simple. A single location physio clinic records, each month, Search Console clicks to its location page, profile calls and direction requests, and GA4 sessions from the gbp listing campaign with booking conversions. After three months the sheet shows calls rising, but website bookings from the profile flat. They discover the profile's booking link goes to a generic contact form. Changing it to the booking page lifts profile driven bookings the next month.
3:46 Example 2 (illustrative)
Worked example two, realistic and illustrative. An optician chain with four branches in Lahore and Karachi runs the Python script monthly and pastes profile exports into the sheet. The dashboard shows Gulberg's location page gaining impressions, but its profile calls flat, while Clifton's calls rise after a category fix. Investigating, they find Gulberg's profile links to the home page instead of its location page, and the page lists the head office phone. Fixing both aligns page, profile and calls, and the next month's dashboard shows it.
4:23 GA4 + the dashboard tab
GA4 completes the picture. Build an exploration where session campaign equals gbp listing, from your UTM convention, with landing page and source dimensions, and sessions and key events as metrics. Export monthly. Then the dashboard tab: one row per location with Search Console clicks and impressions, local query clicks, profile calls, directions and website clicks, GA4 sessions and key events, new reviews and average rating, and notes. Add month on month and year on year columns, and chart the three numbers the owner cares about most.
5:00 Design for the owner
Let's pause and design the dashboard for a real owner. A restaurant owner in Lahore doesn't want forty columns. Ask them which three numbers would change what they do next week. Usually it's calls or reservations, direction requests, and online orders or bookings from the profile. Put those three at the top as simple charts with last month and the same month last year. Put everything else, impressions, positions, query tables, on a second tab for you. A dashboard is for decisions, not for proving how much data you can collect.
5:40 Watch me do it: the first local dashboard
Watch me do it. I'll build the first monthly dashboard for a four branch optician chain. First, I set the Search Console property and the service account key path as environment variables. Next, I edit the script's two queries. Location pages, with the page filter contains slash locations. Local queries, with an including regex filter: near me, lahore, karachi, gulberg, clifton. Then I run it. Two CSV files appear, and the script prints the top ten location pages by clicks. I import both into the Sheet, into the GSC tabs. Now the Business Profile data. This chain doesn't have API access, so I use the multi location performance download in the Business Profile manager for last month, and paste it into a GBP tab. Then GA4. I open my saved exploration filtered to the gbp listing campaign, with landing page and key events, and export it. Now the dashboard tab. One row per branch. SUMIF pulls location page clicks, the local query clicks, profile calls and directions, GA4 sessions and key events. I add month on month columns. Immediately, Gulberg stands out: impressions up, calls flat. That's the first observation. The second: Clifton's calls rose after last month's category fix. Finally, I chart calls, directions and bookings for the owner at the top.
7:13 Common mistakes
Common mistakes. Adding query level and page level Search Console totals together. Hard coding API keys or OAuth secrets in scripts. Reporting impressions without the actions and conversions that follow. And building the same logic separately in Sheets, Looker Studio and slides. If you use Looker Studio, connect it to the sheet, so the logic lives in one place.
7:39 Recap
Recap. Combine Search Console, Business Profile performance and GA4 for a complete local picture. Start with exports and regex filters in Sheets, then automate with the Search Console API. Use the Business Profile Performance API only with approved access and proper OAuth. Keep secrets out of code, compare like with like, and chart what owners care about. Try this now. Export last month's location page data from Search Console and your profile's calls and directions, and build the first row of your dashboard.
What you are building
A simple monthly local dashboard that combines three sources:
- Search Console — organic clicks and impressions for location and service pages, and "local" queries (city names, "near me").
- Business Profile performance — calls, direction requests, website clicks and impressions from Search and Maps.
- GA4 — sessions and conversions from the UTM-tagged profile link.
You can do all of it by exporting CSVs into Google Sheets. Python makes it repeatable for multi-location businesses.
Part 1: Search Console in Sheets (no code)
In Search Console → Performance → Search results, filter Page by "URLs containing" /locations/ (or your pattern) and export. For local queries, use Query → "Custom (regex)" with a pattern such as:
near me|nearby|lahore|gulberg|dha|karachi|cliftonSearch Console filters use RE2 regular expression syntax. Export both views monthly into tabs GSC_pages and GSC_queries, then summarise with a pivot table or:
=QUERY(GSC_pages!A:E, "select A, sum(B), sum(C) where A contains '/locations/' group by A order by sum(B) desc", 1)Part 2: Search Console API in Python (repeatable)
Create a Google Cloud service account, enable the Search Console API, and add the service account email as a user on the property. Keep the key file path in an environment variable.
import os
import pandas as pd
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
SITE = os.environ.get("GSC_SITE", "sc-domain:example.com")
creds = service_account.Credentials.from_service_account_file(
os.environ["GSC_SERVICE_ACCOUNT_JSON"],
scopes=["https://www.googleapis.com/auth/webmasters.readonly"])
gsc = build("searchconsole", "v1", credentials=creds)
def query(body: dict) -> pd.DataFrame:
try:
resp = gsc.searchanalytics().query(siteUrl=SITE, body=body).execute()
except HttpError as e:
raise SystemExit(f"Search Console API error: {e}")
rows = resp.get("rows", [])
dims = body["dimensions"]
return pd.DataFrame([{**dict(zip(dims, r["keys"])), "clicks": r["clicks"],
"impressions": r["impressions"], "position": r["position"]} for r in rows])
location_pages = query({
"startDate": "2026-08-01", "endDate": "2026-08-31",
"dimensions": ["page"],
"dimensionFilterGroups": [{"filters": [
{"dimension": "page", "operator": "contains", "expression": "/locations/"}]}],
"rowLimit": 25000,
})
local_queries = query({
"startDate": "2026-08-01", "endDate": "2026-08-31",
"dimensions": ["query", "page"],
"dimensionFilterGroups": [{"filters": [
{"dimension": "query", "operator": "includingRegex", "expression": "near me|lahore|karachi"}]}],
"rowLimit": 25000,
})
location_pages.to_csv("gsc_location_pages_2026-08.csv", index=False)
local_queries.to_csv("gsc_local_queries_2026-08.csv", index=False)
print(location_pages.sort_values("clicks", ascending=False).head(10))Note: Search Console anonymises some rare queries, so query-level totals are lower than page-level totals. Compare like with like.
Part 3: Business Profile performance data
Without code: in the Business Profile, open Performance, choose the date range and export or record the monthly figures (calls, directions, website clicks, bookings, views on Search/Maps). For many locations, the Business Profile manager supports multi-location performance downloads.
With the API (approved developers): Google's Business Profile Performance API returns daily metrics per location. Access requires applying for Business Profile API access, OAuth consent by an account that manages the location, and the https://www.googleapis.com/auth/business.manage scope. A minimal request using an authorised session:
from google.auth.transport.requests import AuthorizedSession
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file(
"client_secret.json", scopes=["https://www.googleapis.com/auth/business.manage"])
creds = flow.run_local_server(port=0) # the location's owner/manager signs in
session = AuthorizedSession(creds)
LOCATION_ID = "1234567890" # from the Business Profile / API
url = (f"https://businessprofileperformance.googleapis.com/v1/locations/{LOCATION_ID}"
":fetchMultiDailyMetricsTimeSeries")
params = [("dailyMetrics", m) for m in ("CALL_CLICKS", "WEBSITE_CLICKS", "BUSINESS_DIRECTION_REQUESTS")]
params += [("dailyRange.startDate.year", 2026), ("dailyRange.startDate.month", 8), ("dailyRange.startDate.day", 1),
("dailyRange.endDate.year", 2026), ("dailyRange.endDate.month", 8), ("dailyRange.endDate.day", 31)]
resp = session.get(url, params=params, timeout=30)
resp.raise_for_status()
print(resp.json()) # nested time series per metricMetric names and response shapes can change — check the current Business Profile Performance API reference before relying on this in production, and store OAuth tokens securely.
Part 4: GA4
In GA4, build an exploration with Session campaign = gbp-listing (from your UTM convention) and dimensions Landing page and Session source/medium, metrics Sessions, Key events (conversions). Export monthly into a GA4_gbp tab.
Part 5: The monthly dashboard tab
Location | GSC clicks (location page) | GSC impressions | Local-query clicks | GBP calls | GBP directions
GBP website clicks | GA4 gbp sessions | GA4 key events | Reviews (new) | Avg rating | NotesFill it with SUMIF/XLOOKUP from the source tabs, add month-on-month and year-on-year columns, and chart the three numbers the owner cares about most (usually calls, directions and conversions). If you use Looker Studio, connect it to the Sheet rather than rebuilding logic in two places.
Worked example (illustrative)
A 4-branch optician chain in Lahore and Karachi runs the Python script monthly and pastes GBP performance exports into the Sheet. The dashboard shows Gulberg's location page gaining impressions but its GBP calls flat, while Clifton's calls rise after a category fix. Investigation shows Gulberg's profile links to the home page rather than its location page, and the phone number on the page is the head office. Fixing both aligns the page, the profile and the calls — and the next month's dashboard shows it.
Common mistakes
- Adding query-level and page-level Search Console totals together.
- Hard-coding API keys or OAuth secrets in scripts.
- Reporting impressions without the actions and conversions that follow.
- Building the same logic separately in Sheets, Looker Studio and slides.
Key takeaways
- Combine Search Console, Business Profile performance and GA4 (UTM-tagged) data for a complete local picture.
- Sheets exports and regex filters are enough for one location; the Search Console API makes it repeatable at scale.
- The Business Profile Performance API needs approved access, OAuth by a profile manager and the business.manage scope.
- Keep secrets in environment variables, compare like with like, and chart the actions owners care about.
Check your understanding
Quick questions to lock in the lesson. They don’t count towards your certificate.
Put it into practice
Build the monthly dashboard for one business: export location-page and local-query data from Search Console, record GBP performance and GA4 gbp-listing sessions, and write two observations with actions.
Enrol for free to save your progress
Reading is always free. Enrol to keep your place, take the final assessment and earn a verifiable certificate.