# Google Business Profile Audit: Competitors & Fixes (`zaiq/google-business-profile-audit`) Actor

Audit a Google Maps business against nearby competitors. Get an evidence-based score, review insights, category gaps, website NAP checks, ranked fixes, local rankings and an agency-branded HTML report. Track changes with a named store.

- **URL**: https://apify.com/zaiq/google-business-profile-audit.md
- **Developed by:** [Zaiq](https://apify.com/zaiq) (community)
- **Categories:** SEO tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $360.00 / 1,000 business audits

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Business Profile Audit: competitor benchmarks, ranked fixes and a client report

![Google Business Profile Audit: Competitors & Fixes](https://api.apify.com/v2/key-value-stores/4VJNANhwKgqPpXtAi/records/hero-google-business-profile-audit.jpg)

**$0.45 per business audit.** A complete optional 3 × 3 rank grid adds **$0.08**. Competitor lookups, website checks, ranked fixes and a standalone **REPORT.html** are included.

**Example verdict from a real anonymised run:** `85/100 · 87% evidence · 4★ (6,225) vs peers’ 4.9★ median · 80% reply rate in 5 sampled reviews · #1 at centre`.

**Smallest input:** `{"businesses":["ChIJ1aeB6b8EdkgRHsIAVITqUlw"],"primaryKeyword":"plumber"}`. Replace the place ID with yours, or paste a Maps URL. The report can carry your agency name and logo. No source-site account, AI key or separate scraper purchase is needed.

**Review coverage is explicit.** Signed-out Maps responses often expose only a few most-relevant reviews. The requested default is 100; this is a ceiling, not a promise. If recent-first pagination is unavailable, the output labels the preview sample and leaves complete 30/90-day totals unknown.

### What you get

| Field | What it holds |
|---|---|
| Verdict first | Score, evidence coverage, rating versus the peer median, sample reply rate and observed local rank. |
| Profile and activity | Public categories, merchant description, hours, contact details, attributes, action links, photo count, visible post dates and closure status. Unavailable fields are marked unknown. |
| Review evidence | Visible review text and dates, owner responses and timestamps, sample response rate, median sample response time, descriptive rating trend and recurring English keyword themes. |
| Competitor table | Five peers by default, up to ten: rank, rating, review count, categories, photos, website, phone, hours and latest exposed post. |
| Website checks | Name, address and phone comparison with source URLs; LocalBusiness schema in a bounded homepage/contact/about crawl. |
| Rank snapshot | Included centre point, optional nine-point grid, observed depth and failed-point notes. |
| Ranked fixes | What to change, evidence, why it matters, expected qualitative effect and confidence. |
| Agency report and monitoring | Standalone HTML, an embedded raster logo and differences against the previous successful audit in a named store. |

### What people use it for

- **Prospect audits:** Show observed profile and website weaknesses with a sourced fix list.
- **Monthly client reporting:** Track review-count, rating and comparable rank changes without rebuilding the report.
- **Local competitor research:** Inspect category and reputation differences among businesses visible nearby.

### How to use it

1. Add a Maps URL, place ID, or exact business name and city. Place IDs avoid ambiguous matches.
2. Set the primary keyword. Leave competitors empty for local discovery.
3. Keep the included single-point rank check, or request a 3 × 3 grid.
4. Optionally enter your agency name, a direct raster-logo URL and a comparison-store name.
5. Start the Actor. Open the audit dataset and download REPORT.html from the run’s output.

### Input

| Field | Example | Notes |
|---|---|---|
| businesses | \["PLACE_ID"] | Up to 200. An empty input uses a working sample place ID. |
| primaryKeyword | "plumber" | Empty uses the displayed primary category. |
| competitors | \[] | Optional exact identities; otherwise nearby peers are discovered. |
| competitorLimit | 5 | 1–10 automatic peers. |
| rankCheck | "point" | off, point or grid. Off still allows local competitor discovery. |
| rankCenter | "51.50,-0.12" | Optional customer location, useful for service-area businesses. |
| gridSpacingKm | 1 | 0.1–10 km between points. |
| reviewsToRead | 100 | 0–100 requested; source coverage may be much smaller. |
| checkWebsite / websitePages | true / 3 | 1–5 content pages; robots and redirects also count towards request limits. |
| country / language | "us" / "en" | Initial lookup country and response language. Review themes support English. |
| agencyName / agencyLogoUrl | "Example Local Agency" / "" | Direct PNG, JPEG, GIF or WebP under 512 KB; no SVG. |
| comparisonStore | "example-monthly-audits" | Reuse the same store for monthly comparison. Avoid overlapping writers. |

### Output

Each result is one row in the run's dataset (download it as JSON, CSV, Excel, XML or HTML, or read it through the API). An example row (values shortened):

```json
{
  "verdict": "85/100 · 87% evidence · 4★ (6,225) vs peers’ 4.9★ median · 80% reply rate in 5 sampled reviews · #1 at centre",
  "score": 85,
  "coveragePercent": 87,
  "rating": 4,
  "reviewsCount": 6225,
  "localRank": 1,
  "status": "partial",
  "name": "Example Plumbing",
  "mapsUrl": "https://www.google.com/maps/place/?q=place_id:EXAMPLE_PLACE_ID",
  "primaryKeyword": "plumber",
  "benchmark": {
    "competitorsChecked": 5,
    "medianRating": 4.9,
    "medianReviews": 72,
    "medianPhotos": 42
  },
  "reviewAnalysis": {
    "sampleSize": 5,
    "ownerResponseRatePercent": 80.0,
    "medianResponseDays": 3.59,
    "reviewsLast30Days": null,
    "reviewsLast90Days": null
  },
  "websiteCheck": {
    "pagesRead": 3,
    "localBusinessSchema": false,
    "nameMatch": "match",
    "phoneMatch": "match"
  }
}
```

Example from a real direct test on 26 October 2026. Business names, Maps identifiers and site addresses are replaced; the numeric values and unknown fields are unchanged. SUMMARY records the input outcomes, requests, bytes, route escalations, timing and charged events. REPORT.html contains the full audit, evidence coverage, formula and priorities.

### Pricing

- **$0.45 per audited business**, event `audit`, the same price on every Apify plan.
- **$0.08 per complete 3 × 3 rank grid**, event `rank-grid`, only when requested. Incomplete grids have no grid charge; usable points remain in the audit.
- Competitor lookups, sampled review analysis, website checks, monitoring and the HTML report are included. There is no AI-model charge or sub-Actor bill.
- Unresolved businesses and invalid inputs produce free notes. A resolved profile with partial review or website evidence is a paid audit; its limits are shown before the recommendations.
- Apify’s $0.00005 start charge counts towards the buyer’s Maximum cost per run. The Actor checks the remaining budget before each business; if only the base audit fits, a requested grid falls back to a centre-point audit.

What typical jobs cost at the list price:

| Job | Cost |
|---|---|
| One audit, point rank and report | $0.45005 including the start charge |
| One audit with a complete grid | $0.53005 including the start charge |
| 25 audits without grids | $11.25005 including the start charge |
| 200 audits without grids | $90.00005 including the start charge |

On Apify's Scale and Business plans the per-event prices are lower (Store discounts). Set **Maximum cost per run** and the Actor stops cleanly when it is reached: you never pay more than that.

### Tips

- Use exact place IDs for multi-location businesses.
- Use the same keyword, language, centre and spacing when comparing rank over time.
- Review source coverage and the cited evidence before sending the report to a client.

### Use it through the API

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("zaiq/google-business-profile-audit").call(run_input={"businesses": ["ChIJ1aeB6b8EdkgRHsIAVITqUlw"], "primaryKeyword": "plumber"})
for row in client.dataset(run.default_dataset_id).iterate_items():
    print(row)
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('zaiq/google-business-profile-audit').call({"businesses": ["ChIJ1aeB6b8EdkgRHsIAVITqUlw"], "primaryKeyword": "plumber"});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**HTTP (one call, results back)**

```bash
curl -X POST 'https://api.apify.com/v2/acts/zaiq~google-business-profile-audit/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"businesses": ["ChIJ1aeB6b8EdkgRHsIAVITqUlw"], "primaryKeyword": "plumber"}'
```

### Integrations and schedules

- **Schedules:** run it every hour, day or week from the Apify Console (Schedules) and keep a history of results.
- **Make, Zapier, n8n, Google Sheets, Slack, Airtable:** connect it through Apify's integrations, or send each finished run to a **webhook**.
- **Datasets:** results stay in the run's dataset; export them or read them by API whenever you need them.

### Use it with AI agents (MCP)

Add Apify's MCP server (`https://mcp.apify.com`) to Claude, ChatGPT, Cursor, VS Code or any MCP client. The agent can find this Actor and run it for you: ask it for "audit these business profiles against nearby competitors and rank the most useful fixes". AI agents can also pay for runs directly through Apify's agentic payments.

### Limits

- The score is a disclosed editorial rubric, not Google’s ranking algorithm. Overall score = 100 × earned points / assessed weight. Unknown and inapplicable checks are excluded; coverage shows the assessed share of the full 100-point rubric.
- Subscore weights: profile 25, reviews 25, relevance 15, website 20, activity 5 and local visibility 10. Every row and report shows the exact formula and evidence for each check. Scores with different evidence coverage are not directly comparable.
- Complete newest-first review pagination was unavailable in the direct tests. The visible preview is selected by Google for relevance, then reordered by date. Response rates, response times, themes and rating trends describe that sample only. Counts for the last 30 and 90 days are null unless all reviews were read.
- Special hours, declared service-area names, products/services and the owner/customer photo split are not reliably exposed. They remain unknown. Missing exposed posts do not prove inactivity. The first displayed category is labelled primary; owner-dashboard categories can differ.
- A service-area business is not penalised for hiding its street address. Its public pin may approximate its operating area; set a customer location for more useful rankings.
- Category gaps require at least two observed winners sharing a category. Category suggestions are conditional on the business actually providing that service. A keyword-stuffing flag is a heuristic for review, not a policy verdict.
- Website checks use static public HTML and respect robots rules. JavaScript-only content, login walls and checks can make website evidence unavailable. Different phone numbers or legal names require human review.
- Rank is position in the observed Maps list, usually up to 20 places, at zoom 14. Absence from that list is not an exact rank. Results vary by location, language, time and source response.
- Theme rules match English keywords within low- or high-star reviews. They do not fully understand negation, sarcasm or mixed opinions.
- Audit rows have kind `audit`; unresolved inputs have kind `note`. A complete grid adds a billing receipt row with kind `grid-receipt`, linked to its audit. Stable keys prevent duplicate delivery on a migration restart.
- Monitoring retains the latest 2,000 business snapshots in one named store. Review gains are net count changes. Rank comparison requires the same search settings, and competitor-post changes require visible dates on both runs.

### FAQ

**Can I get every review?**

No. This audit uses the reviews available publicly without login or challenge solving and reports exactly how many it read. It is not an all-reviews scraper.

**Are the fixes guaranteed to improve rankings?**

No. They explain observed gaps and likely customer benefits. Google’s undisclosed ranking formula and distance are outside this rubric.

**What is included in the price?**

The target profile, competitor lookups, bounded website checks, deterministic analysis, report and optional monitoring. Only a complete requested grid is an extra event.

**What happens when the website is blocked?**

The resolved profile can still receive a paid audit. Website checks remain unknown and the report explains the gap.

**Can I send the report to a client?**

Yes. Download REPORT.html. It has no remote scripts, fonts or styles; an accepted logo is embedded. Browser printing is supported.

**Do repeat monthly runs incur a new charge?**

Yes, each new run delivers a fresh audit. A migration restart of the same run skips already delivered audit and grid keys.

### Related Actors from Zaiq

- [google-maps-leads-scraper](https://apify.com/zaiq/google-maps-leads-scraper): public place lists and sourced business contacts
- [google-maps-rank-grid](https://apify.com/zaiq/google-maps-rank-grid): larger dedicated local-rank grids
- [seo-site-audit](https://apify.com/zaiq/seo-site-audit): deeper technical website audits

### Support

Questions, a site that changed, or a field you need? Open an issue on this Actor's **Issues** tab: we answer there, usually within a day.

***

Also found as: google business profile audit, local SEO audit, Google Maps competitors, business profile optimisation, Google Business Profile report, local SEO agency report.

# Actor input Schema

## `businesses` (type: `array`):

Maps URLs, place IDs, or exact business names with cities. Up to 200; ambiguous names produce a free note. Empty input uses the sample profile.

## `primaryKeyword` (type: `string`):

The service customers search for. Empty uses the displayed primary category.

## `competitors` (type: `array`):

Exact Maps URLs, IDs, or names with cities. Empty discovers nearby competitors; at most 10.

## `competitorLimit` (type: `integer`):

Number of automatically discovered peers to inspect. Competitor lookups are included.

## `rankCheck` (type: `string`):

Off still permits a local search for competitor discovery. Point reads the centre. Grid adds 8 points and a separate fee only for a complete grid.

## `rankCenter` (type: `string`):

Latitude,longitude of the customer location. Empty uses the public profile pin; service-area pins can be approximate.

## `gridSpacingKm` (type: `number`):

Distance between neighbouring grid points. A 3 × 3 grid covers twice this distance from edge to edge.

## `reviewsToRead` (type: `integer`):

Requested maximum. Signed-out access often exposes only a most-relevant preview. The Actor reports sample coverage and never treats a partial sample as complete 30/90-day totals.

## `checkWebsite` (type: `boolean`):

Read the linked public website for name, address, phone and LocalBusiness schema. Uses static HTML and respects robots rules.

## `websitePages` (type: `integer`):

Bounded homepage and contact/about/location crawl. No browser; at most 15 requests including redirects and robots per site.

## `country` (type: `string`):

Two-letter country for the initial lookup. Local searches then use the country shown on the resolved business.

## `language` (type: `string`):

Language code for public Maps responses. Theme rules support English review text only.

## `agencyName` (type: `string`):

Agency name printed in the standalone HTML report.

## `agencyLogoUrl` (type: `string`):

Optional direct public PNG, JPEG, GIF or WebP under 512 KB. Embedded into the report; SVG and redirects are not used.

## `comparisonStore` (type: `string`):

Optional named key-value store for repeat audits. Use the same name monthly. Keeps up to 2,000 latest business snapshots. Avoid concurrent runs writing the same store.

## Actor input object example

```json
{
  "businesses": [
    "ChIJ1aeB6b8EdkgRHsIAVITqUlw"
  ],
  "primaryKeyword": "plumber",
  "competitors": [],
  "competitorLimit": 5,
  "rankCheck": "point",
  "rankCenter": "",
  "gridSpacingKm": 1,
  "reviewsToRead": 100,
  "checkWebsite": true,
  "websitePages": 3,
  "country": "us",
  "language": "en",
  "agencyName": "Example Local Agency",
  "agencyLogoUrl": "",
  "comparisonStore": ""
}
```

# Actor output Schema

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

Dataset: the results.

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

What each input returned, and notes.

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

A one-page view of the results to open in a browser.

# 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 = {
    "businesses": [
        "ChIJ1aeB6b8EdkgRHsIAVITqUlw"
    ],
    "primaryKeyword": "plumber",
    "agencyName": "Example Local Agency"
};

// Run the Actor and wait for it to finish
const run = await client.actor("zaiq/google-business-profile-audit").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 = {
    "businesses": ["ChIJ1aeB6b8EdkgRHsIAVITqUlw"],
    "primaryKeyword": "plumber",
    "agencyName": "Example Local Agency",
}

# Run the Actor and wait for it to finish
run = client.actor("zaiq/google-business-profile-audit").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 '{
  "businesses": [
    "ChIJ1aeB6b8EdkgRHsIAVITqUlw"
  ],
  "primaryKeyword": "plumber",
  "agencyName": "Example Local Agency"
}' |
apify call zaiq/google-business-profile-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zaiq/google-business-profile-audit"
        }
    }
}
```

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/JWD99owMYIKabBXv5/builds/FkjWeEUg1rCCbyfd5/openapi.json
