# Local SEO Audit – Google Business Profile (`sfoln/local-business-audit`)

Audit a local business by name and city, place ID or Maps link: Google Business Profile completeness, review stats, local rank for up to 3 keywords with top competitors, website SEO, speed, mobile and NAP match, a 0–100 score and fixes. $35 per 1,000 audits.

- Family: Local & maps
- Categories: SEO tools, Lead generation, Automation
- Availability: on request (private on Apify). Email contact@sfoln.com with subject "Access request: Local SEO Audit – Google Business Profile (sfoln/local-business-audit)" before calling; calls fail until it is public.
- JSON: https://www.sfoln.com/actors/local-business-audit.json
- MCP: https://mcp.apify.com?tools=sfoln/local-business-audit
- REST (sync): POST https://api.apify.com/v2/actors/sfoln~local-business-audit/run-sync-get-dataset-items
- REST (async): POST https://api.apify.com/v2/actors/sfoln~local-business-audit/runs

Run a local SEO audit of any business on Google Maps: give a business name and city, a Google place ID, a CID or a Google Maps link, and the Actor reads its Google Business Profile, checks where it ranks in Google's local results for up to 3 keywords, audits the website linked from the profile and returns one scored JSON record: profile completeness (claimed, categories, hours, photos, description, attributes), review count, rating and star distribution, local rank with the 3 best-placed competitors, website SEO, speed, mobile setup, HTTPS, LocalBusiness structured data and NAP consistency (does the website show the profile's name, address and phone?), booking and chat widgets, ad pixels, domain age and e-mail authentication, plus an overall 0–100 score, a letter grade and a list of issues with a recommendation each. Built for local SEO and web-design agencies prospecting and reporting, franchise managers checking locations, and AI agents asked "how is this business doing on Google?".

## Price per delivered record

| Event | Price | Per 1,000 | Charged for |
| --- | --- | --- | --- |
| Local business audit (`local-audit`) | $0.035 | $35 / 1,000 | Charged once per business whose Google Business Profile was found: profile completeness, review stats, local rank for up to 3 keywords with competitors, website SEO / speed / mobile / NAP audit, domain and e-mail setup, scores and recommended fixes. |

Pay-per-event, USD, billed by Apify; no platform usage charge. Only records with status `ok` are charged. Cap a run with `maxTotalChargeUsd`. Apify free plan: up to 5 per run.

## Run

```bash
curl -X POST "https://api.apify.com/v2/actors/sfoln~local-business-audit/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"businesses":["cid:2946633002421908862"],"location":"New York,New York,United States"}'
```

MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/local-business-audit"
    }
  }
}
```

Example prompt: Audit the local SEO of Katz's Delicatessen in New York: how complete is its Google Business Profile, where does it rank for "deli", is its website consistent with the profile, and what should it fix first?

## Input

List businesses by name and city, Google place ID, CID or Google Maps link. Each business produces one audit record.

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `businesses` (required) | array | — | Businesses: One per line: a business name ("Joe's Pizza Broadway"), a Google Maps link of the place, a place ID ("ChIJ…" or "place_id:…") or a CID ("cid:2946633002421908862" or the bare number of 15+ digits, always as a string: JSON numbers that large lose digits). Override the location per line with "name \| location". Objects may also set per-business keywords: {"name": "…", "location": "…", "keywords": ["…"]}. Accounts on the Apify free plan can process up to 5 businesses per run. |
| `location` | string | — | Location: Where to look up business names: a DataForSEO location name ("New York,New York,United States") or numeric location code (2840 = United States). For place IDs, CIDs and Maps links it only sets the regional context. |
| `keywords` | array | — | Rank keywords: Up to 3 searches to check the business's local rank for, e.g. "emergency plumber". Each is searched as "<keyword> in <city of the business>" on Google's local results. Empty: the profile's primary category (one search). |
| `checkRankings` | boolean | `true` | Check local rank: Search Google's local results for each keyword and report the business's position and the top 3 competitors. |
| `checkWebsite` | boolean | `true` | Audit the website: Read the website linked from the profile (homepage and contact page): SEO, speed, mobile, HTTPS, LocalBusiness data, NAP consistency with the profile, booking and chat widgets, ad pixels, domain age and e-mail authentication. |
| `languageCode` | string | `"en"` | Language code: Language of the profile data and of the local-rank searches (ISO code such as en, de, es). |
| `maxItems` | integer | `1000` | Max businesses: Safety cap on the number of businesses audited in this run. |
| `concurrency` | integer | `3` | Concurrency: How many businesses are audited in parallel. |
| `includeRaw` | boolean | `false` | Include raw upstream response: Attach the unmodified business profile and local results to each record (larger output). |

Example input:

```json
{
  "businesses": [
    "cid:2946633002421908862"
  ],
  "location": "New York,New York,United States"
}
```

## Output

One record per input item with `status` (`ok` is charged; `not_found`, `error`, `skipped_*` are free) and `charged`. The run stores an `OUTPUT` summary record.

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | object | Input: { lookup, location?, keywords? }: the business as given (name, cid:…, place_id:… or Google Maps link). |
| `status` | string | Status: ok \| not_found \| error \| skipped_invalid \| skipped_budget \| skipped_free_plan \| skipped_unmetered |
| `charged` | boolean | Charged: Whether this record incurred a local-audit charge. |
| `chargedEvent` | string | Charged event: local-audit (present only when charged). |
| `chargedCount` | integer | Events charged: Events actually charged when the charge came back short (present only then). |
| `source` | string | Source: Upstream data sources. |
| `fetchedAt` | string | Fetched at: ISO timestamp. |
| `error` | object | Error: { code, message, provider?, status? } when status is not ok: not_found (no Google Business Profile for the name / id), invalid_input (unreadable Maps link), plus the runtime codes (budget_exhausted, free_plan_limit, unmetered, aborted, charge_failed, record_too_large, invalid_record, dataset_push_failed) and upstream codes (auth, insufficient_credits, rate_limit, timeout, network, server, client, invalid_response). |
| `warnings` | array | Warnings: Parts that failed or were skipped: rank searches, a website that refused the request, RDAP. |
| `lookupKind` | string | Lookup kind: cid, place_id or keyword (business name). |
| `location` | string | Location: Location used for the lookup. |
| `found` | boolean | Found: A Google Business Profile was found. |
| `businessName` | string | null | Business name: Name on the Google Business Profile. |
| `category` | string | null | Category: Primary category. |
| `additionalCategories` | array | Secondary categories: Further categories of the profile. |
| `address` | string | null | Address: Formatted address. |
| `city` | string | null | City: City of the address. |
| `postalCode` | string | null | Postal code: Postal code of the address. |
| `region` | string | null | Region: State or region. |
| `countryCode` | string | null | Country: ISO 3166-1 alpha-2 country code. |
| `phone` | string | null | Phone: Phone number as shown on the profile. |
| `phoneE164` | string | null | Phone (E.164): The profile's phone in E.164 (+12175550142). |
| `website` | string | null | Website: Website linked from the profile. |
| `domain` | string | null | Domain: Host of the website (without www.). |
| `cid` | string | null | CID: Google customer id of the place. |
| `placeId` | string | null | Place ID: Google place id. |
| `googleMapsUrl` | string | null | Google Maps: Link to the place on Google Maps. |
| `latitude` | number | null | Latitude: Latitude of the place. |
| `longitude` | number | null | Longitude: Longitude of the place. |
| `isClaimed` | boolean | null | Claimed: The owner has claimed the profile. |
| `currentStatus` | string | null | Status on Google: open, closed (right now), temporarily_closed or closed_forever. |
| `rating` | number | null | Rating: Average star rating. |
| `reviewCount` | integer | Reviews: Number of Google reviews. |
| `auditScore` | integer | Audit score: Overall score 0–100: 35% profile completeness, 30% website, 20% reviews, 15% local rank (sections not assessed are left out). |
| `grade` | string | Grade: A (90+), B (75+), C (60+), D (45+), E (25+), F. |
| `scores` | object | Scores: { overall, profile, reviews, visibility, website } 0–100 (visibility / website null when not assessed; website 0 without a website or with a social / directory page as the website). |
| `profile` | object | Profile: { completeness, checks[{ check, label, ok, points, maxPoints }], description, workHours, workHoursSummary, totalPhotos, logo, mainImage, attributes[], services, bookOnlineUrl, priceLevel, peopleAlsoSearch[] }. |
| `reviews` | object | Reviews: { rating, count, distribution { 1…5 }, positiveShare, negativeShare, topics, score }: counts and distribution only, no review texts. |
| `visibility` | object | null | Local rank: { keywords[{ keyword, query, rank, resultsCount, competitors[{ rank, name, rating, reviewCount, category, domain, cid }], error }], bestRank, score }. |
| `websiteAudit` | object | null | Website audit: { url, finalUrl, status, https, sslValid, sslIssuer, sslDaysLeft, mobileFriendly, title, metaDescription, h1, cms, technologies[], bookingWidgets[], chatWidgets[], adPixels[], analytics[], runsAds, localBusinessSchema, phonesOnSite[], hasClickToCall, emailsOnSite[], socials, copyrightYear, staleSite, lastModified, performance, scores { seo, performance, local }, pagesRead[] }. |
| `nap` | object | null | NAP consistency: { name { gbp, site, score, match }, phone { gbp, site[], match }, address { gbp, postalCodeFound, streetFound, cityFound, match }, consistent, score }: the profile's name, address and phone compared with the website. |
| `presence` | object | null | Domain and e-mail: { domain, domainCreatedAt, domainAgeDays, registrar, mailProvider, hasMailServer, spf, dmarcPolicy, spfDmarcLookup }: spfDmarcLookup failed = the SPF / DMARC lookup failed (spf null, dmarcPolicy unknown); null for a website on a shared platform domain (wixsite.com, myshopify.com …) or without a website of its own. |
| `issues` | array | Issues: { severity (high \| medium \| low), area (profile \| reviews \| visibility \| nap \| website \| presence), code, finding, recommendation }, most severe first. |
| `issueCounts` | object | Issue counts: { high, medium, low }. |
| `sections` | object | Sections: State of each part: profile ok; visibility ok \| partial \| error \| skipped \| off; website ok \| none \| social (a social or directory page as the website, not audited) \| blocked \| error \| off; presence ok \| partial \| skipped \| off. |

Example record:

```json
{
  "input": {
    "lookup": "cid:1234567890123456789",
    "location": "Springfield,Illinois,United States",
    "keywords": [
      "dentist",
      "emergency dentist"
    ]
  },
  "lookupKind": "cid",
  "location": "Springfield,Illinois,United States",
  "found": true,
  "businessName": "Maple Street Dental",
  "category": "Dentist",
  "additionalCategories": [
    "Cosmetic dentist"
  ],
  "address": "1200 S Maple St, Springfield, IL 62704",
  "city": "Springfield",
  "postalCode": "62704",
  "region": "Illinois",
  "countryCode": "US",
  "phone": "+1217-555-0142",
  "phoneE164": "+12175550142",
  "website": "https://www.maplestreetdental.example/",
  "domain": "maplestreetdental.example",
  "cid": "1234567890123456789",
  "placeId": "ChIJmapleStreetDental0001",
  "googleMapsUrl": "https://www.google.com/maps?cid=1234567890123456789",
  "latitude": 39.7817,
  "longitude": -89.6501,
  "isClaimed": false,
  "currentStatus": "open",
  "rating": 4.1,
  "reviewCount": 23,
  "auditScore": 69,
  "grade": "C",
  "scores": {
    "overall": 69,
    "profile": 60,
    "reviews": 57,
    "visibility": 50,
    "website": 96
  },
  "profile": {
    "completeness": 60,
    "checks": [
      {
        "check": "claimed",
        "label": "Profile claimed by the owner",
        "ok": false,
        "points": 0,
        "maxPoints": 15
      },
      {
        "check": "primaryCategory",
        "label": "Primary category",
        "ok": true,
        "points": 10,
        "maxPoints": 10
      },
      {
        "check": "photos",
        "label": "10 or more photos",
        "ok": false,
        "points": 5,
        "maxPoints": 10
      }
    ],
    "description": "Family dentist in Springfield.",
    "workHours": {
      "monday": [
        "08:00-17:00"
      ],
      "tuesday": [
        "08:00-17:00"
      ]
    },
    "workHoursSummary": "Mon 08:00-17:00; Tue 08:00-17:00; Wed 08:00-17:00; Thu 08:00-17:00; Fri 08:00-13:00; Sat closed; Sun closed",
    "totalPhotos": 6,
    "logo": null,
    "mainImage": "https://lh5.googleusercontent.com/p/maple-street-dental-main=w648-h240-k-no",
    "attributes": [
      "has_wheelchair_accessible_entrance",
      "accepts_new_patients"
    ],
    "services": 0,
    "bookOnlineUrl": null,
    "priceLevel": null,
    "peopleAlsoSearch": [
      "Lincoln Park Dental Care"
    ]
  },
  "reviews": {
    "rating": 4.1,
    "count": 23,
    "distribution": {
      "1": 3,
      "2": 1,
      "3": 1,
      "4": 4,
      "5": 14
    },
    "positiveShare": 0.78,
    "negativeShare": 0.17,
    "topics": {
      "cleaning": 12,
      "front desk": 5
    },
    "score": 57
  },
  "visibility": {
    "keywords": [
      {
        "keyword": "dentist",
        "query": "dentist in Springfield, Illinois",
        "rank": 2,
        "resultsCount": 20,
        "competitors": [
          {
            "rank": 1,
            "name": "Lincoln Park Dental Care",
            "rating": 4.8,
            "reviewCount": 412,
            "category": "Dentist",
            "domain": "lincolnparkdental.example",
            "cid": "9876543210987654321"
          },
          {
            "rank": 3,
            "name": "Capitol City Smiles",
            "rating": 4.6,
            "reviewCount": 158,
            "category": "Cosmetic dentist",
            "domain": "capitolcitysmiles.example",
            "cid": "1111111111111111111"
          },
          {
            "rank": 4,
            "name": "Prairie Family Dentistry",
            "rating": 4.9,
            "reviewCount": 87,
            "category": "Dentist",
            "domain": null,
            "cid": "2222222222222222222"
          }
        ],
        "error": null
      },
      {
        "keyword": "emergency dentist",
        "query": "emergency dentist in Springfield, Illinois",
        "rank": null,
        "resultsCount": 20,
        "competitors": [
          {
            "rank": 1,
            "name": "Capitol City Smiles",
            "rating": 4.6,
            "reviewCount": 158,
            "category": "Cosmetic dentist",
            "domain": "capitolcitysmiles.example",
            "cid": "1111111111111111111"
          },
          {
            "rank": 2,
            "name": "Springfield Emergency Dental",
            "rating": 4.3,
            "reviewCount": 64,
            "category": "Emergency dental service",
            "domain": "springfieldemergencydental.example",
            "cid": "3333333333333333333"
          }
        ],
        "error": null
      }
    ],
    "bestRank": 2,
    "score": 50
  },
  "websiteAudit": {
    "url": "https://www.maplestreetdental.example/",
    "finalUrl": "https://www.maplestreetdental.example/",
    "status": 200,
    "https": true,
    "sslValid": true,
    "sslIssuer": "Let's Encrypt",
    "sslDaysLeft": 75,
    "mobileFriendly": true,
    "title": "Maple Street Dental | Family Dentist in Springfield, IL",
    "metaDescription": "Gentle family and cosmetic dentistry in Springfield, Illinois. New patients welcome, same-week appointments and evening hours. Book online today.",
    "h1": "Family dentistry in Springfield",
    "cms": null,
    "technologies": [
      "Facebook Pixel",
      "Google Tag Manager",
      "Let's Encrypt",
      "Open Graph"
    ],
    "bookingWidgets": [
      "Zocdoc"
    ],
    "chatWidgets": [],
    "adPixels": [
      "Meta Pixel"
    ],
    "analytics": [
      "Google Tag Manager"
    ],
    "runsAds": true,
    "localBusinessSchema": {
      "present": true,
      "types": [
        "Dentist"
      ],
      "name": "Maple Street Dental",
      "telephone": "+1-217-555-0142",
      "address": "1200 South Maple Street, 62704 Springfield, IL, US",
      "hasOpeningHours": true,
      "hasGeo": false
    },
    "phonesOnSite": [
      "+12175550142"
    ],
    "hasClickToCall": true,
    "emailsOnSite": [
      "maplestreetdental.frontdesk@gmail.com"
    ],
    "socials": {
      "facebook": "https://www.facebook.com/maplestreetdental",
      "instagram": "https://www.instagram.com/maplestreetdental"
    },
    "copyrightYear": 2021,
    "staleSite": true,
    "lastModified": null,
    "performance": {
      "ttfbMs": 420,
      "htmlKb": 38.2,
      "compressed": true,
      "requestEstimate": 31,
      "renderBlockingScripts": 0
    },
    "scores": {
      "seo": 97,
      "performance": 100,
      "local": 90
    },
    "pagesRead": [
      "https://www.maplestreetdental.example/",
      "https://www.maplestreetdental.example/contact/"
    ]
  },
  "nap": {
    "name": {
      "gbp": "Maple Street Dental",
      "site": "Maple Street Dental",
      "score": 1,
      "match": true
    },
    "phone": {
      "gbp": "+12175550142",
      "site": [
        "+12175550142"
      ],
      "match": true
    },
    "address": {
      "gbp": "1200 S Maple St, Springfield, IL 62704",
      "postalCodeFound": true,
      "streetFound": true,
      "cityFound": true,
      "match": true
    },
    "consistent": true,
    "score": 100
  },
  "presence": {
    "domain": "maplestreetdental.example",
    "domainCreatedAt": "2014-03-02T10:00:00Z",
    "domainAgeDays": 4609,
    "registrar": "Example Registrar LLC",
    "mailProvider": "Google Workspace",
    "hasMailServer": true,
    "spf": true,
    "dmarcPolicy": null,
    "spfDmarcLookup": "ok"
  },
  "issues": [
    {
      "severity": "high",
      "area": "profile",
      "code": "profile_unclaimed",
      "finding": "The profile is not claimed by the business (anyone can suggest edits and the owner cannot reply to reviews).",
      "recommendation": "Claim and verify the profile in Google Business Profile Manager so the owner controls its details, posts and review replies."
    },
    {
      "severity": "high",
      "area": "visibility",
      "code": "visibility_not_ranking",
      "finding": "Not among Google's top 20 local results for \"emergency dentist in Springfield, Illinois\".",
      "recommendation": "Build relevance for \"emergency dentist\": use it in the categories, description and services of the profile and in the website's homepage title and text, and collect reviews that mention it."
    },
    {
      "severity": "medium",
      "area": "profile",
      "code": "profile_short_description",
      "finding": "The business description is only 30 characters.",
      "recommendation": "Add a 250–750 character description naming the main services and the area served."
    },
    {
      "severity": "medium",
      "area": "profile",
      "code": "profile_few_photos",
      "finding": "The profile has 6 photos; profiles with 10+ get more clicks.",
      "recommendation": "Upload at least 10 recent photos (outside, inside, team, work) and add new ones every month."
    }
  ],
  "issueCounts": {
    "high": 2,
    "medium": 3,
    "low": 5
  },
  "sections": {
    "profile": "ok",
    "visibility": "ok",
    "website": "ok",
    "presence": "ok"
  },
  "status": "ok",
  "charged": true,
  "chargedEvent": "local-audit",
  "source": "dataforseo+serper+website",
  "fetchedAt": "2026-10-15T12:00:00.000Z"
}
```

## FAQ

**What does one audit check?**

The Google Business Profile (claimed status, categories, phone, website, hours, description, photos, attributes, services), review counts and the star distribution, the business's position in Google's local results for up to 3 keywords with the 3 best-placed competitors, and the website linked from the profile: HTTPS and certificate, mobile viewport, title, description and H1, speed proxies, LocalBusiness structured data, tap-to-call, freshness, booking and chat widgets, ad pixels, and whether its name, address and phone match the profile. Every gap becomes an issue with a recommendation.

**How are the scores calculated?**

Profile completeness is a 100-point checklist; reviews combine the rating (60%) and the review volume (40%); local rank gives 100 for the top 3, 80 for 4–5, 60 for 6–10 and 40 below; the website score is 45% SEO, 25% speed and 30% local signals (HTTPS, LocalBusiness data, tap-to-call, freshness, NAP). The overall score weighs the profile 35%, the website 30%, reviews 20% and local rank 15%, leaving out sections that could not be assessed.

**What if the business is not found?**

Nothing is charged. Names work best with the city ("Joe's Pizza Broadway New York") or a location; place IDs, CIDs and Google Maps links of the place are exact.


## Related

- [Google Business Profile Scraper](https://www.sfoln.com/actors/google-business-profile.md) (`sfoln/google-business-profile`)
- [Google Maps Leads Scraper + Emails](https://www.sfoln.com/actors/google-maps-business-leads.md) (`sfoln/google-maps-business-leads`)
- [Google Maps Places Scraper](https://www.sfoln.com/actors/google-maps-search.md) (`sfoln/google-maps-search`)
- [Website Audit – SEO, Security, SSL & DNS](https://www.sfoln.com/actors/website-audit.md) (`sfoln/website-audit`)
- [SEO Audit API – On-Page Checks for Any URL](https://www.sfoln.com/actors/onpage-seo-audit.md) (`sfoln/onpage-seo-audit`)
- [Company Enrichment – Firmographics by Domain](https://www.sfoln.com/actors/company-enrichment.md) (`sfoln/company-enrichment`)
- [Tech Stack Detector – Website Technologies](https://www.sfoln.com/actors/tech-stack-detector.md) (`sfoln/tech-stack-detector`)

Publisher: SFOLN LLC, contact@sfoln.com. Catalogue: https://www.sfoln.com/catalog.json. Agent guide: https://www.sfoln.com/agents.md.
