# Google Reviews Agency Client & SLA Manager (`versant_nautilus/google-reviews-multi-location-monitor`) Actor

Rank clients and branches by risk, assign account owners, surface response-SLA breaches, and generate separate agency and client reports.

- **URL**: https://apify.com/versant\_nautilus/google-reviews-multi-location-monitor.md
- **Developed by:** [Marsh](https://apify.com/versant_nautilus) (community)
- **Categories:** SEO tools, Automation, Marketing
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 location analyzeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Reviews Agency Client & SLA Manager

Turn Google Maps reviews across every agency account into a ranked client and branch action queue, response-SLA tracker, and white-label report system.

This Actor is built for local-SEO agencies and reputation-management teams that oversee several clients, while preserving a simple mode for franchises and single multi-location brands. It does more than return reviews: it identifies which client needs attention first, ranks the client's branches, assigns accountability, and recommends what the account or operations team should do next.

No AI key is required. The core ranking, alerts, themes, response-SLA checks, and report work in deterministic mode.

### See the output before you run

[Open the live-data agency sample report](https://api.apify.com/v2/key-value-stores/4do5WLMa5qc6iGy3g/records/SAMPLE_REPORT.html) · [View the separate client report](https://api.apify.com/v2/key-value-stores/4do5WLMa5qc6iGy3g/records/SAMPLE_CLIENT_REPORT.html) · [Inspect sample JSON and cost evidence](https://api.apify.com/v2/key-value-stores/4do5WLMa5qc6iGy3g/records/SAMPLE_DATA.json)

The 13 September 2026 live test fetched 25 reviews from one public location and identified two unanswered negative reviews past a demo 48-hour response target. Reviewer identities and original review/reply text have been removed from this public sample. The business is **not our customer or partner**; the portfolio and account-owner labels are illustrative. A separate two-client fixture was used to test report separation; this live sample is not a multi-location benchmark.

#### Try it in five steps

1. Keep the demo portfolio, or replace it with your client and exact Google Maps branches. Leave single-client `locations` empty when using `portfolios`.
2. For a small test, set `maxReviewsPerLocation` to **25**, `upstreamMaxChargeUsd` to **0.25**, and `aiProvider` to **none**. Set this Actor's maximum total run charge to **$0.25** as a separate control.
3. Click **Start**. If Apify asks, authorize the nested Google Maps Reviews Scraper and the monitoring storage needed for repeat runs.
4. Open **Output → Agency command-center report**. For a client-only report, open **Storage → Key-value store** and the `CLIENT_REPORT_….html` record named in the client report index.
5. Save the input as a task. Reuse the same `monitorId` on subsequent runs to avoid duplicate review-action charges. Use a different ID for an unrelated client workspace.

You still pay for fetching reviews and generating the location/report outputs on unchanged runs. Duplicate detection removes duplicate **review-action fees**, not the whole run cost.

#### A measured small-run cost example

For one location, 25 new review actions, and one report bundle, our Actor's configured event fees total **$0.07955**. In the live owner-account test, the upstream scraper charged **$0.01505** and our Actor's platform usage was **$0.001075**. At those same usage rates, an outside customer's comparable run would be approximately **$0.096 total**. This is one measured example, not a fixed quote: plan rates, upstream pricing, review counts, and optional AI can change the total.

Our owner-account test did not pay our own Actor's event fees. It is validation evidence, not a customer sale or revenue claim.

### The outcome

Each run gives you:

- A red, amber, or green health status for every branch with returned reviews, or **unknown** when no reviews are returned.
- A client risk leaderboard across the complete agency book of business.
- Account-manager ownership and a configurable response SLA for each client.
- A portfolio-wide leaderboard ranked by operational priority.
- Reasons behind every priority score, such as new negative reviews or overdue owner responses.
- New or updated review actions in the Dataset, plus a report queue that keeps previously seen unanswered negatives visible within the fetched sample.
- Rating movement compared with the previous successful run.
- An agency command-center HTML report plus a separate white-label HTML report for each client.
- JSON, CSV, and Excel-ready records for dashboards and client workflows.

Even a location with no reviews in the selected window receives a location summary. That keeps the report accountable to the complete branch list instead of silently dropping quiet locations.

### Designed around an agency workspace

Use one saved Apify task for the agency workspace:

1. Set `brandName` to your agency or internal team.
2. Add each client under `portfolios`, including its account manager and response SLA.
3. Add every client's exact Google Maps branches.
4. Give the workspace a stable `monitorId`.
5. Run once, then schedule the same task weekly or daily.

The stable workspace ID lets the Actor remember previous review fingerprints and branch metrics. Later runs return only new or changed review action items while rebuilding the complete agency, client, and branch rankings.

The HTML response queue also retains unchanged, unanswered negative reviews while they remain in the fetched sample. Those retained items are not charged again as new review actions. Answered reviews are removed from the response queue. This is not a permanent backlog of reviews outside the selected window or review cap.

### Why this is different from a basic review monitor

A basic monitor answers: “Which reviews are new?”

This Actor also answers:

- Which branch should the agency contact first?
- Why is that branch ranked above the others?
- Which negative reviews have exceeded the response SLA?
- Is the branch's recent rating improving, stable, or declining?
- What should the branch manager do next?
- What can the agency send to the client without rebuilding a report manually?

### Multi-client agency quick start

```json
{
  "brandName": "Your Local SEO Agency",
  "monitorId": "agency-weekly-command-center",
  "portfolios": [
    {
      "clientId": "northstar-coffee",
      "clientName": "Northstar Coffee",
      "accountManager": "Priya",
      "responseSlaHours": 24,
      "locations": [
        {
          "name": "Indiranagar Branch",
          "placeId": "ChIJ..."
        }
      ]
    },
    {
      "clientId": "harbor-dental",
      "clientName": "Harbor Dental",
      "accountManager": "Arun",
      "responseSlaHours": 48,
      "locations": [
        {
          "name": "Central Clinic",
          "url": "https://www.google.com/maps/place/..."
        }
      ]
    }
  ],
  "firstRunMode": "emitAll",
  "lookbackDays": 8,
  "negativeRatingThreshold": 2,
  "aiProvider": "none"
}
```

Use either `portfolios` or the single-client `locations` input, not both in one run.

### Single-client quick start

Use an exact Google Maps place/share URL or a Google Place ID for every branch:

```json
{
  "clientName": "Northstar Coffee",
  "brandName": "Your Local SEO Agency",
  "locations": [
    {
      "name": "Indiranagar Branch",
      "placeId": "ChIJ..."
    },
    {
      "name": "Koramangala Branch",
      "url": "https://www.google.com/maps/place/..."
    }
  ],
  "monitorId": "northstar-coffee-weekly",
  "firstRunMode": "emitAll",
  "lookbackDays": 8,
  "maxReviewsPerLocation": 250,
  "negativeRatingThreshold": 2,
  "responseSlaHours": 48,
  "aiProvider": "none",
  "reportTitle": "Weekly Review Portfolio Operations Report"
}
```

Keep `allowSearchUrls` off for routine monitoring. Broad Google Maps search URLs can match several unintended businesses; an exact place link or Place ID keeps each input tied to one branch.

### How the ranking works

The Actor fetches recent Google-origin reviews, normalizes them, and groups them by branch. The explainable priority score increases when it finds:

- Negative reviews that remain unanswered beyond the configured SLA.
- New negative reviews.
- A high negative-review rate in the lookback window.
- A low recent average rating.

Rating decline is reported separately as a trend and attention reason; it is not an extra component of the priority score.

Locations are sorted by priority score and given a `priorityRank`. Each location record includes `attentionReasons` and `recommendedAction`, so an agency can use the output without reverse-engineering the score.

The Actor only requests Google-origin reviews and disables the upstream scraper's personal-data option.

### Outputs

The run page provides four useful outputs:

- **Agency and client action queue** — an exportable Dataset containing agency and client summaries, ranked branches, and new or updated review actions.
- **Agency command-center report** — an HTML report with the client risk leaderboard, branch accountability, SLA breaches, and response queue.
- **Client report index** — a JSON index pointing to the separate white-label HTML report generated for each client.
- **Machine-readable summary** — run totals, billing delivery counts, agency status, client summaries, and branch summaries for automations.

In multi-client mode, the Dataset contains four record types:

| Record type | One record represents |
| --- | --- |
| `agencySummary` | The executive roll-up and risk status for the agency workspace |
| `clientSummary` | One client, its agency-wide rank, owner, SLA risk, and next action |
| `locationSummary` | One requested branch, its rank, trend, reasons, and next action |
| `review` | One new or updated review that entered the response queue |

Single-client mode retains the existing `portfolioSummary`, `locationSummary`, and `review` records for backwards compatibility.

#### What the Apify Results number means

`Results` is the number of Dataset records written by a run. It is not the number of customers, searches, or total historical reviews.

For example, an agency run with two clients, two locations, and three new reviews produces eight Results: one agency summary, two client summaries, two branch summaries, and three review actions. An unchanged later run produces five Results: the agency summary, two client summaries, and two fresh branch summaries.

### First-run behavior

- `emitAll` returns all reviews found inside the lookback period. Use this to validate the first client report.
- `baselineOnly` stores the current review fingerprints without emitting historical review actions. Use this when a client wants alerts only for reviews arriving after onboarding.

An eight-day lookback works well for a weekly schedule because the overlap reduces the chance of missing late or reordered reviews. Fingerprint-based deduplication prevents the overlap from producing the same action item repeatedly.

### AI is optional

The default `aiProvider: "none"` mode needs no external AI account or API key. It uses deterministic rating, keyword-theme, urgency, ranking, and response-SLA rules.

For richer summaries or response drafts, customers can bring their own credentials:

- `openrouter`: supply `openRouterApiKey`, or use a developer-configured `OPENROUTER_API_KEY` secret.
- `vertex`: supply the Vertex project and service-account inputs, or use developer-configured GCP secrets.

Secret inputs are masked by Apify. AI enrichment is capped by `maxAiReviews`, and positive reviews are excluded unless `aiAnalyzeAllRatings` is enabled. The core report remains available if AI is disabled or an AI request fails.

### Connecting agency workflows

Dataset records and the machine-readable summary can be routed through Apify webhooks and integrations to Slack, email, Make, Zapier, n8n, a CRM, or an agency dashboard. The Actor produces the structured action data; delivery destinations are configured in Apify so credentials do not need to be embedded in the Actor input.

### Cost controls

Two controls limit spend:

- `upstreamMaxChargeUsd` caps the nested Google Maps Reviews Scraper run.
- Apify's maximum total run charge caps this Actor's pay-per-event outputs.

The launch events are:

| Event | Launch price |
| --- | ---: |
| Location analyzed | $0.012 each |
| New or updated review action | $0.0015 each |
| Agency report bundle generated | $0.030 per run |
| Actor start (512 MB configuration) | $0.00005 per run |

In multi-client mode, the single report event includes the agency command center and every client-ready report generated in that run. Platform usage and the nested public-review scraper are separate. Actual cost depends on the number of clients, branches, review volume, schedule, and selected fetch limits.

### Limitations and responsible use

- This Actor processes publicly available Google review data; it is not the official Google Business Profile API.
- Google and upstream output formats can change. Stable normalization and automated tests reduce, but cannot eliminate, that dependency risk.
- The trend compares the current lookback-window result with the previous successful run; it is an operational signal, not a formal statistical trend analysis.
- Average ratings, negative rates, and health statuses describe the returned review sample, not the business's all-time Google rating. When the review cap is reached, older reviews in the requested window may not be included.
- Response SLAs are customer-configured targets. A missing publication date produces unknown review SLA status, not a proven breach. No returned reviews produces unknown branch health, not a green health signal.
- Deterministic sentiment and themes are prioritization aids, not human judgments. Review sensitive cases manually.
- The Actor can draft actions and responses but does not post replies to Google.
- Follow applicable privacy, platform, and local legal requirements. Do not use review data to harass, discriminate against, or profile individuals.

### Developer verification

Run the included portfolio fixture locally without calling a paid scraper or AI provider:

```bash
apify run --purge --input-file examples/demo-input.json
```

Run the multi-client agency fixture:

```bash
apify run --purge --input-file examples/agency-demo-input.json
```

Run the business-logic tests and validate the Apify schemas:

```bash
python -m pytest -q
apify validate-schema
```

For local pay-per-event simulation:

```bash
ACTOR_TEST_PAY_PER_EVENT=true apify run --purge --input-file examples/demo-input.json
```

The simulation does not bill money. It writes charge calls to the local `charging-log` Dataset. In Store pricing, remove the synthetic `apify-default-dataset-item` event or set its price to zero because the custom events already meter delivered Dataset records. Keep the low-cost `apify-actor-start` event enabled to cover startup.

# Actor input Schema

## `portfolios` (type: `array`):

Recommended for agencies. Add each client, its account owner, response SLA, and Google Maps branches. Do not combine this with the single-client locations field.

## `locations` (type: `array`):

Compatibility mode for one client. Supply one exact Google Maps place/share URL or Place ID per branch. Do not combine this with client portfolios.

## `allowSearchUrls` (type: `boolean`):

Advanced: search URLs may return multiple or unintended businesses. Keep this off for branch monitoring.

## `inlineReviews` (type: `array`):

Optional review objects. When supplied, the upstream scraper is not called.

## `monitorId` (type: `string`):

Stable internal ID for this agency workspace or client. Reuse it on scheduled runs so the Actor can identify new and changed reviews.

## `firstRunMode` (type: `string`):

Emit all recent reviews for a useful first report, or only save a baseline.

## `lookbackDays` (type: `integer`):

Fetch reviews from this many days in the past. Use an overlap to avoid missing reviews.

## `maxReviewsPerLocation` (type: `integer`):

Safety cap for each location in one run.

## `negativeRatingThreshold` (type: `integer`):

Reviews at or below this rating are treated as negative.

## `responseSlaHours` (type: `integer`):

Default SLA for single-client mode and for portfolios that do not specify their own SLA.

## `upstreamMaxChargeUsd` (type: `number`):

Optional hard cap passed to the Google Maps Reviews Scraper run.

## `aiProvider` (type: `string`):

Choose deterministic-only analysis, OpenRouter, or Vertex AI Gemini.

## `aiModel` (type: `string`):

Leave blank for the provider default.

## `openRouterApiKey` (type: `string`):

Optional when the Actor developer provides an included key. Use a restricted key with a spending limit.

## `vertexProjectId` (type: `string`):

Required for Vertex AI unless configured by the Actor developer.

## `vertexLocation` (type: `string`):

Region used for Gemini requests.

## `vertexServiceAccountJson` (type: `string`):

Optional secret credential for Vertex AI. Prefer a dedicated least-privilege service account.

## `maxAiReviews` (type: `integer`):

Hard limit that protects inference spend.

## `aiAnalyzeAllRatings` (type: `boolean`):

Off by default. Negative and neutral reviews usually contain the most actionable information.

## `industry` (type: `string`):

Used to give the AI relevant operational context.

## `reportTitle` (type: `string`):

White-label title shown at the top of the HTML report.

## `brandName` (type: `string`):

Optional agency or team name shown as the report preparer.

## `clientName` (type: `string`):

Used only with the single-client locations field. Multi-client mode takes client names from client portfolios.

## Actor input object example

```json
{
  "portfolios": [
    {
      "clientName": "Demo portfolio (not a client)",
      "accountManager": "Demo account owner",
      "responseSlaHours": 24,
      "locations": [
        {
          "name": "Starbucks Indiranagar — public-data demo",
          "placeId": "ChIJhRlmCKsXrjsRG3BtPTj8v_U"
        }
      ]
    }
  ],
  "locations": [],
  "allowSearchUrls": false,
  "inlineReviews": [],
  "monitorId": "default-monitor",
  "firstRunMode": "emitAll",
  "lookbackDays": 8,
  "maxReviewsPerLocation": 250,
  "negativeRatingThreshold": 2,
  "responseSlaHours": 48,
  "upstreamMaxChargeUsd": 5,
  "aiProvider": "none",
  "aiModel": "",
  "vertexProjectId": "",
  "vertexLocation": "us-central1",
  "maxAiReviews": 100,
  "aiAnalyzeAllRatings": false,
  "industry": "local business",
  "reportTitle": "Agency Review Portfolio Operations Report",
  "brandName": "",
  "clientName": ""
}
```

# Actor output Schema

## `results` (type: `string`):

Agency summary, ranked clients and branches, plus new or changed review actions.

## `report` (type: `string`):

Agency-wide client risk leaderboard, branch accountability, and review response queue.

## `summary` (type: `string`):

Run totals, portfolio status, and location summaries.

## `reportIndex` (type: `string`):

Lists the separate white-label HTML report generated for each delivered client.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "portfolios": [
        {
            "clientName": "Demo portfolio (not a client)",
            "accountManager": "Demo account owner",
            "responseSlaHours": 24,
            "locations": [
                {
                    "name": "Starbucks Indiranagar — public-data demo",
                    "placeId": "ChIJhRlmCKsXrjsRG3BtPTj8v_U"
                }
            ]
        }
    ],
    "locations": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("versant_nautilus/google-reviews-multi-location-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "portfolios": [{
            "clientName": "Demo portfolio (not a client)",
            "accountManager": "Demo account owner",
            "responseSlaHours": 24,
            "locations": [{
                    "name": "Starbucks Indiranagar — public-data demo",
                    "placeId": "ChIJhRlmCKsXrjsRG3BtPTj8v_U",
                }],
        }],
    "locations": [],
}

# Run the Actor and wait for it to finish
run = client.actor("versant_nautilus/google-reviews-multi-location-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "portfolios": [
    {
      "clientName": "Demo portfolio (not a client)",
      "accountManager": "Demo account owner",
      "responseSlaHours": 24,
      "locations": [
        {
          "name": "Starbucks Indiranagar — public-data demo",
          "placeId": "ChIJhRlmCKsXrjsRG3BtPTj8v_U"
        }
      ]
    }
  ],
  "locations": []
}' |
apify call versant_nautilus/google-reviews-multi-location-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,versant_nautilus/google-reviews-multi-location-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hw2Fwik0f0qiSk7dH/builds/pfrC5iBlNHn5vkXZo/openapi.json
