SearchOps

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.

REST APIVia Zapier, Make or n8n

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, /week

Agencies that want clients to see value without asking

Apps Script
Mondays, 7am
SearchOps API
Results + work done
Data Studio
Client's dashboard
  1. 1Paste the script below into Extensions, Apps Script, and run setup once.
  2. 2In Data Studio, connect the sheet and build one report: calls, website clicks and directions week on week, beside tasks done.
  3. 3Filter it to each client's locations and share it read-only.

Portfolio league table: who needs a call this week

GET /week

Agency owners and heads of accounts

Weekly sheet
Every location
Change columns
Calls, directions
League table
Biggest falls first
  1. 1Use the same weekly sheet; add columns for the change in calls and directions against last week.
  2. 2In Data Studio, a table sorted by the biggest fall, with conditional colours.
  3. 3Monday stand-up: the top five rows are this week's calls to make.

AI visibility in the monthly report

GET /ai-visibility

Agencies selling AI search as a service

Monthly script
Apps Script
SearchOps API
ChatGPT and Gemini
Trend chart
Named in % of answers
  1. 1Add a monthly function that calls /api/v1/locations/{id}/ai-visibility?engine=chatgpt and engine=gemini for each client.
  2. 2Write the visibility rate and share of voice to an AI tab, one row per client per month.
  3. 3Chart it in Data Studio beside the Business Profile results.

Map Pack coverage trend with its likely range

scan.completed
Scan finished
scan.completed
Add a row
Or Make
Trend per keyword
With range band
  1. 1Send scan.completed through Zapier or Make into a Scans tab.
  2. 2Keep keyword, engine, share, share_low, share_high and completed_at.
  3. 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. 1

    Create an API key

    In SearchOps, open Developers, then API & MCP Credentials, and create a key. Copy it: it is shown once.

  2. 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. 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. 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. 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.

FieldUse it for
calls / calls_prevCalls from the Business Profile, this week and last
website_clicks / direction_requests / viewsThe other profile actions and views, with _prev for last week
from / throughThe week Google has reported. It runs about four days behind
tasks_done / tasks_open / tasks_suggestedWork done this week and what's waiting
blank cellsNo 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.

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.

Start tracking your real rankings today

See where you actually rank on Google Maps, not where Google tells you. Pick the plan that fits and start tracking from day one.