SearchOps + Google Sheets and Data Studio
Give every client a live results dashboard, rank your whole book in a league table, and add "does ChatGPT recommend you?" to the monthly report.
Client reporting ends up in Google Sheets and Data Studio (formerly Looker Studio). A short, free Apps Script pulls each location's Business Profile results and the work done from the SearchOps API every Monday at 7am, and Data Studio turns the sheet into dashboards that update themselves. The same pattern adds Map Pack history, AI visibility and the searches people used to find each profile.
A live dashboard per client
Calls, website clicks and direction requests week on week, beside the tasks finished: proof of value they can open any time.
The whole book in a league table
Every client ranked by change in calls and directions, so you know who to call before they call you.
AI visibility as a report line
How often ChatGPT and Gemini name each client, month by month: a number no other report has.
The searches that find them
The terms people typed before a client's profile appeared, a favourite slide in any review meeting.
Free and self-running
Apps Script runs in your Google account on a weekly trigger. No relay, no extra subscription.
Honest blanks
Locations without Business Profile data get a blank cell, never a misleading zero.
Recipes
What agencies build with Google Sheets and Data Studio
Live results dashboard for every client
GET /locations, /weekAgencies that want clients to see value without asking
- 1Paste the script below into Extensions, Apps Script, and run setup once.
- 2In Data Studio, connect the sheet and build one report: calls, website clicks and directions week on week, beside tasks done.
- 3Filter it to each client's locations and share it read-only.
Portfolio league table: who needs a call this week
GET /weekAgency owners and heads of accounts
- 1Use the same weekly sheet; add columns for the change in calls and directions against last week.
- 2In Data Studio, a table sorted by the biggest fall, with conditional colours.
- 3Monday stand-up: the top five rows are this week's calls to make.
AI visibility in the monthly report
GET /ai-visibilityAgencies selling AI search as a service
- 1Add a monthly function that calls /api/v1/locations/{id}/ai-visibility?engine=chatgpt and engine=gemini for each client.
- 2Write the visibility rate and share of voice to an AI tab, one row per client per month.
- 3Chart it in Data Studio beside the Business Profile results.
Map Pack coverage trend with its likely range
scan.completed- 1Send scan.completed through Zapier or Make into a Scans tab.
- 2Keep keyword, engine, share, share_low, share_high and completed_at.
- 3Plot a line per keyword with share_low to share_high as a band, so clients see real progress, not wobble.
Setup
Connect Google Sheets and Data Studio, step by step
- 1
Create an API key
In SearchOps, open Developers, then API & MCP Credentials, and create a key. Copy it: it is shown once.
- 2
Open Apps Script from your sheet
In the Google Sheet, choose Extensions, then Apps Script. In Project Settings, add a script property called SEARCHOPS_API_KEY with your key, so the key never sits in the code.
- 3
Paste the script and run setup
Replace the editor's contents with the script below, save, and run setup. Google asks you to allow the script to reach external services and edit the sheet. It writes this week's rows straight away and then every Monday between 7 and 8am.
Apps Script// Extensions > Apps Script in your Google Sheet. Then Project Settings > // Script properties: add SEARCHOPS_API_KEY = lp_live_... // Run setup() once (it asks for permission); weeklyPull() then runs every Monday. const BASE = 'https://searchops.co/api/v1'; const SHEET = 'SearchOps weekly'; function api_(path) { const key = PropertiesService.getScriptProperties().getProperty('SEARCHOPS_API_KEY'); const res = UrlFetchApp.fetch(BASE + path, { headers: { Authorization: 'Bearer ' + key }, muteHttpExceptions: true, }); const code = res.getResponseCode(); if (code === 429) { Utilities.sleep(60000); return api_(path); } // over 120 a minute: wait if (code !== 200) throw new Error(path + ' -> ' + code + ' ' + res.getContentText().slice(0, 200)); return JSON.parse(res.getContentText()); } function allLocations_() { const out = []; for (let offset = 0; ; offset += 100) { const page = api_('/locations?limit=100&offset=' + offset).data; out.push(...page); if (page.length < 100) return out; } } function weeklyPull() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sh = ss.getSheetByName(SHEET) || ss.insertSheet(SHEET); if (sh.getLastRow() === 0) { sh.appendRow(['pulled_at', 'location_id', 'business_name', 'from', 'through', 'calls', 'website_clicks', 'direction_requests', 'views', 'calls_prev', 'website_clicks_prev', 'direction_requests_prev', 'views_prev', 'tasks_done', 'tasks_open', 'tasks_suggested']); } const pulledAt = new Date(); const rows = []; for (const loc of allLocations_()) { const w = api_('/locations/' + loc.id + '/week').data; if (!w) continue; const g = w.gbp; // null = no connected profile or no data yet: a blank, not zero rows.push([pulledAt, loc.id, loc.business_name, g ? g.from : '', g ? g.through : '', g ? g.current.calls : '', g ? g.current.website : '', g ? g.current.directions : '', g ? g.current.views : '', g ? g.previous.calls : '', g ? g.previous.website : '', g ? g.previous.directions : '', g ? g.previous.views : '', w.done.length, w.open, w.suggested]); Utilities.sleep(600); // stay under 120 requests a minute } if (rows.length) sh.getRange(sh.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows); } function setup() { ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t)); ScriptApp.newTrigger('weeklyPull').timeBased().onWeekDay(ScriptApp.WeekDay.MONDAY).atHour(7).create(); weeklyPull(); } - 4
Build the Data Studio report
In Data Studio, choose Create, then Data source, then Google Sheets. Pick the spreadsheet and the SearchOps weekly tab with Use first row as headers on, and connect. Data Studio refreshes from the sheet every 15 minutes by default.
- 5
Add more data the same way
The api_ helper in the script calls any endpoint: /profile/performance?months=1 for monthly totals and action rate, /profile/search-terms for what people searched, /ai-visibility?engine=chatgpt for AI visibility. Write each to its own tab.
Field reference
The fields you'll map most
From the SearchOps webhook payload. Every event also carries type, id, created_at and the location's id and business name.
| Field | Use it for |
|---|---|
| calls / calls_prev | Calls from the Business Profile, this week and last |
| website_clicks / direction_requests / views | The other profile actions and views, with _prev for last week |
| from / through | The week Google has reported. It runs about four days behind |
| tasks_done / tasks_open / tasks_suggested | Work done this week and what's waiting |
| blank cells | No connected profile or no data yet. Not zero |
What you need
- SearchOps Pro, Agency or Enterprise. Webhooks and the API are included; an owner or admin sets them up.
- A Google account. Apps Script and Data Studio are free; Apps Script allows 20,000 web requests a day on a personal account and 100,000 on Workspace.
- The script waits 0.6 seconds between calls to stay under 120 requests a minute, so about 100 locations take a couple of minutes.
- The Map Pack trend needs a relay for scan.completed: Zapier (paid plan for webhooks) or Make.
Steps checked against the vendor's own documentation on 12 October 2026. Tools change their menus often; if a step no longer matches, the help article has the latest.
Works well alongside
FAQ
SearchOps and Google Sheets and Data Studio
Is Looker Studio the same as Data Studio?
Yes. Google renamed Looker Studio back to Data Studio in April 2026. The steps here work under either name.
Can I report ChatGPT visibility to clients?
Yes. /locations/{id}/ai-visibility returns how often ChatGPT (or Gemini) names the business across the questions you track, and the share of voice against rivals. Write it to a sheet monthly and chart it.
Do I need Zapier?
Not for the weekly results, league table or AI visibility: Apps Script calls our API directly and is free. Only the per-scan trend, which listens for events, needs Zapier or Make.
Why are some cells blank?
A blank means the location has no connected Business Profile or Google hasn't reported that week yet. We leave it blank rather than writing 0, so averages and charts stay honest.
Is there a packaged Data Studio connector?
Not yet. The sheet-based route uses Data Studio's own Google Sheets connector and needs no extra software.