Skip to content

Guide

How do I set up a repeatable multi-location Google Business Profile Performance API export?

By Sergey Sulimko, Founder9 min read

Authenticate with the business.manage OAuth scope, enumerate every accessible account and location until each nextPageToken is gone, then repeat one daily-metrics request and one monthly-keyword request for each selected locations/{locationId} resource. Save the request dates, metric names, pagination state, and returned value types beside the data so the next run can be compared without changing what Google's response means.1234

This is the operational layer behind the Google Business Profile Performance API overview. The API's daily and monthly methods are scoped to a location,13 so a multi-location export is a controlled loop over a location manifest, not one request containing every location.

After exporting, use the Google Business Profile performance comparison workflow to normalize the location rows and compare equivalent metrics.

What should I save for each export?

Treat the export as five linked records. The data file is not complete without the request manifest that explains its scope.

Record Save Why it matters
Authentication OAuth scope, token time, and the account used for discovery The documented account, location, and Performance API methods require the business.manage scope.123
Location manifest Account resource, returned location resource, and a stable label when Google returns one Performance requests use the exact locations/{locationId} resource name for an unobfuscated listing ID; keep any business label as metadata, not as the request path.13
Daily request Selected dailyMetrics, inclusive startDate, inclusive endDate, and the raw response A daily range includes both endpoints, and the multi-metric method still addresses one location at a time.14
Monthly request Inclusive startMonth, inclusive endMonth, pageSize, every pageToken, and the raw response Monthly keyword results aggregate over the requested months and can span multiple pages.3
Validation record Profile verification, associated-account access, available metrics, freshness check, and data scope A missing card can mean that a metric does not apply. It is not automatically zero.5

Keep the raw response as well as any reporting table. A normalized table can make comparisons easier, but it must not erase whether Google omitted a zero daily value or returned a monthly threshold.

How do I authenticate and enumerate all accessible locations?

Use one OAuth authorization with the scope below, then build the manifest in two paginated passes.

https://www.googleapis.com/auth/business.manage
  1. Call accounts.list for the authenticated user.
  2. Store every account returned, and call again with the returned pageToken until nextPageToken is absent. Google says this list includes accounts the user owns and accounts where the user has management rights. The personal account is first unless it is filtered out.2
  3. For each account, call accounts.locations.list with a readMask. Set pageSize between 1 and 100; the default is 10.
  4. Follow the location list's nextPageToken until it is absent. Do not treat the first response as the full location set.3
  5. Keep the returned location resource in the form locations/{locationId}. The Performance API expects an unobfuscated listing ID in that resource name. If your system starts with another identifier, verify its mapping before calling the Performance API.13

The account type changes what the location list can return. For a PERSONAL account, Google returns only locations directly owned by that account. Other account types return all locations accessible through that account, directly or indirectly.3 Keep the account that produced each manifest row so the same location is not silently attributed to the wrong account when you reconcile multiple pages.

Which daily metrics should I request?

Choose the daily enums your report needs, and keep the enum names beside the result. The current Performance reference documents these metric families:

Metric enum Google-defined meaning
BUSINESS_IMPRESSIONS_DESKTOP_MAPS Business impressions on Google Maps from desktop devices
BUSINESS_IMPRESSIONS_DESKTOP_SEARCH Business impressions on Google Search from desktop devices
BUSINESS_IMPRESSIONS_MOBILE_MAPS Business impressions on Google Maps from mobile devices
BUSINESS_IMPRESSIONS_MOBILE_SEARCH Business impressions on Google Search from mobile devices
BUSINESS_DIRECTION_REQUESTS Requests for directions to the business location
CALL_CLICKS Clicks on the Business Profile call button
WEBSITE_CLICKS Clicks on the Business Profile website
BUSINESS_BOOKINGS Bookings made through Reserve with Google
BUSINESS_FOOD_MENU_CLICKS Clicks to view or interact with menu content

Google marks BUSINESS_CONVERSATIONS and BUSINESS_FOOD_ORDERS as deprecated in the same enum reference.4 Keep those labels visible if an old configuration still requests them, but do not add deprecated enums to a new default metric set without rechecking Google's current documentation.4

For reader-facing definitions of Views, Searches, calls, directions, bookings, and menu activity, use the Google Business Profile performance metrics guide. The API enum and the owner-facing report label are not always the same thing,45 so preserve both when your reporting layer maps one to the other.

How do I fetch daily data for every location?

Call locations.fetchMultiDailyMetricsTimeSeries once for each selected location. The method accepts repeated dailyMetrics query values, requires a dailyRange, and uses an empty request body. Its path contains one locations/* resource, so the loop over the manifest is what makes the export multi-location.1

If a separate job needs only one daily metric for a location, Google's locations.getDailyMetricsTimeSeries method is the single-metric alternative. Keep the same location resource and inclusive date-range record.6

For each location, persist these request fields before accepting the response:

location: locations/{unobfuscatedLocationId}
dailyMetrics[]: [the exact enum names requested]
dailyRange.startDate: YYYY-MM-DD
dailyRange.endDate: YYYY-MM-DD
requestBody: empty

Both startDate and endDate are inclusive. Store them next to every time series, not only in a job-level configuration, because the date range is part of what the value means.14

The response contains a metric, an optional dailySubEntityType, and a time series of date-value pairs. Google says the value field is not present when the value is zero.4 Normalize that deliberately:

  • value present: store the returned integer.
  • value absent in a returned date-value pair: store 0 with a state such as omitted_zero.
  • The metric or response is absent because the request failed or the response is incomplete: store an error or incomplete state, not zero.
  • dailySubEntityType absent: keep it absent. Do not invent a breakdown.

This distinction protects the export from turning a valid zero into an unknown value or turning an incomplete response into a false zero.

How do I export monthly search keywords?

Run locations.searchkeywords.impressions.monthly.list separately for each location. Use the same locations/{locationId} resource from the manifest, set an inclusive startMonth and endMonth, and continue with nextPageToken until no token remains.3

The monthly range is month-granular. Google considers only the year and month fields, not a day within the month. pageSize defaults to 100 and cannot exceed 100.3

Store each keyword row with these fields:

Field Preserve it as
searchKeyword Google's lower-cased string
insightsValue.value The exact aggregate when Google returns the value arm
insightsValue.threshold A threshold state, meaning the actual value is below the returned threshold
startMonth, endMonth The inclusive months used for the request
location The locations/{locationId} resource that was queried

insightsValue is a union. It contains either the sum of unique users who used the keyword across the requested months or a threshold below which the actual value falls.3 A threshold is not an exact count. Keep the union arm in the file and render a threshold as “below [threshold]” rather than as that number.

How do I validate the file before I accept it?

Run these checks in order. The first failed check identifies what to repair before a comparison or dashboard consumes the file.

Check Pass condition If it fails
Authorization The token carries the business.manage scope Reauthorize before discovering accounts or calling Performance methods
Account discovery Every account page was read until nextPageToken was absent Rebuild the account manifest; do not compare a partial account set
Location discovery Every location page used a required readMask, a pageSize from 1 to 100, and all returned page tokens Rebuild the location manifest and retain the account type exception
Location identity Every request uses the exact locations/{locationId} resource for an unobfuscated listing ID Stop the row and verify any identifier mapping before calling the Performance API
Daily range Every daily request stores both inclusive dates and the exact metric enums Reject the comparison until the request window is known
Daily response Omitted daily value fields are marked as zero omissions, while failed or incomplete responses are not zero-filled Re-run or label the response incomplete
Monthly keywords The month range is inclusive, nextPageToken is exhausted, and value remains distinct from threshold Rebuild the monthly result before aggregating it
Profile eligibility The profile is verified and the authenticated user is signed in to the Google Account associated with it Resolve access or verification before treating missing data as a metric result
Metric availability The file records which metrics Google returned and does not fill an unavailable metric with zero Mark the metric unavailable for that profile
Freshness A new month's Searches data is allowed up to five days to appear after the month starts Mark Searches as pending refresh inside that window
Data scope The file says whether its performance data includes organic Search results and Google Ads Preserve the scope before comparing files

Google says Performance data is available only for verified Business Profiles, requires the associated Google Account, and shows only metrics that apply to the business. Google also says the Searches metric updates at the start of each month and can take up to 5 days to appear.5

Can I use Google's manual download as a cross-check?

Yes. Use it as a control check for profile selection and timeframe, not as proof that the spreadsheet and API response have identical columns or semantics.

In Business Profile Manager on a computer:

  1. Select the checkbox beside the profiles to compare.
  2. At the top right, click Actions, then Insights.
  3. Select the timeframe.
  4. Click Download Report.5

Save the selected profiles, timeframe, and downloaded filename beside the API export. Compare the profile set and date or month scope first. Keep the API's daily zero-omission state, monthly value versus threshold, and exact location resource names in the API record even when the manual file presents a different layout.

Sources

  1. Google for Developers, “Method: locations.fetchMultiDailyMetricsTimeSeries,” last updated 2024-10-16, read 2026-10-12. Read the multi-metric method

  2. Google for Developers, “Method: accounts.list,” last updated 2024-10-16, read 2026-10-12. Read the account-list method

  3. Google for Developers, “Method: accounts.locations.list” and “Method: locations.searchkeywords.impressions.monthly.list,” last updated 2024-10-16, read 2026-10-12. Read the location-list method and read the monthly keyword method

  4. Google for Developers, “Package google.mybusiness.performance.v1,” last updated 2026-10-05, read 2026-10-12. Read the Performance API RPC reference

  5. Google Business Profile Help, “Understand your Business Profile performance & insights,” date not stated on page, read 2026-10-12. Read Google's performance guidance

  6. Google for Developers, “Method: locations.getDailyMetricsTimeSeries,” last updated 2024-10-16, read 2026-10-12. Read the single-metric method

See where your profile stands

The audit shows how this applies to your own profile: it reads a verified Google Business Profile and scores it the same way every month.

Visibility Score

0 to 100

20 scored factors across profile completeness, performance, competitive position. Free, no signup, on any verified Google Business Profile.

Run the free Visibility Score audit

No signup, no card. You get the score and the factors behind it.

Common questions

Does fetchMultiDailyMetricsTimeSeries fetch every location in one request?
No. The method bundles several daily metrics for one `locations/*` resource. A multi-location export repeats the request for each selected location.
Is an absent daily `value` an API failure?
Not necessarily. Google documents that the `value` field is omitted when the value is zero. Keep that zero omission separate from a failed or incomplete response.
Is a monthly keyword threshold an exact count?
No. A threshold says the actual value is below the returned threshold. Preserve it as a threshold instead of reporting the threshold as the keyword's exact count.
Why is a monthly Searches value missing just after the month starts?
Google says Searches updates at the start of each month and may take up to 5 days to appear. Check the refresh window before treating a missing monthly value as a broken export.