# Local AI Recommendations: Best X in City (`appgild/local-ai-recommendations`) Actor

Ask ChatGPT, Microsoft Copilot and Google AI Overviews "best {category} in {city}" three ways and see which businesses each recommends, how often, and what they cite. AI answers only, no map-listing data. Powered by cloro.

- **URL**: https://apify.com/appgild/local-ai-recommendations.md
- **Developed by:** [AppGild Team](https://apify.com/appgild) (community)
- **Categories:** AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$80.00 / 1,000 city checked on one engine (three phrasings)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Local AI Recommendations: Best X in City

When someone asks ChatGPT, Microsoft Copilot or Google "best dentist in Austin", which businesses come back? This Actor asks each engine three ways, for every city you enter, and reports the businesses each engine recommends, how many of the three answers named each one, its best list position, and the sources the answers cite. A summary per city counts the businesses across all engines.

**Powered by cloro** for ChatGPT and Microsoft Copilot answers, as ChatGPT and Microsoft Copilot answer users, asked from the city's state. Google AI Overviews come from Google search at the city through DataForSEO.

It uses **AI answers only**. No Google Maps, Places or business-listing data is used.

Not affiliated with or endorsed by OpenAI, Microsoft or Google. ChatGPT, Copilot and Google are trademarks of their owners.

### Who it is for

- **Local SEO agencies** showing a client which competitors AI recommends in their city, and whether they are named at all.
- **Multi-location brands** comparing how often each location is recommended across cities.
- **Researchers** studying which sources AI assistants rely on for local recommendations.

### The three phrasings

For category `dentist` and city `Austin, TX`:

1. `best dentist in Austin, TX`
2. `top rated dentist in Austin, TX`
3. `Which dentist in Austin, TX would you recommend?`

### What you get

One row per city and engine (`type: "city-engine"`):

| Field | What it means |
| --- | --- |
| `recommended` | Businesses named, most-named first: `name`, `answersNaming` (of 3), `bestPosition`. |
| `phrasings` | Each of the three answers: the prompt, the businesses it listed in order, the URLs it cited. |
| `citedDomains` | The domains cited, with how many of the three answers cited each. |
| `status` | `ok`, or `partial` when one of the three answers did not come back (not charged). |
| `poweredBy` | `"cloro (https://cloro.dev)"` on every ChatGPT and Copilot row. |

And one free summary row per city (`type: "city-summary"`): `businesses` across all engines, with `answersNaming`, `enginesNaming` and `bestPosition`.

### Example output

One real city-engine row from a test run on 2026-10-20 (lists cut to the first few, one of the three phrasings shown). The businesses here are named as the AI answer named them; AppGild is not affiliated with them.

```json
{
  "type": "city-engine",
  "category": "dentist",
  "city": "Austin, TX",
  "engine": "copilot",
  "status": "ok",
  "checkedAt": "2026-10-20T12:25:29.420Z",
  "recommended": [
    {
      "name": "Tech Ridge Dental",
      "answersNaming": 3,
      "bestPosition": 1
    },
    {
      "name": "ATX Family Dental",
      "answersNaming": 3,
      "bestPosition": 2
    },
    {
      "name": "Austin Dental Works",
      "answersNaming": 3,
      "bestPosition": 3
    },
    {
      "name": "Austin Lifetime Dental",
      "answersNaming": 3,
      "bestPosition": 4
    }
  ],
  "phrasings": [
    {
      "prompt": "best dentist in Austin, TX",
      "status": "ok",
      "listed": [
        "Tech Ridge Dental",
        "38th Street Dental",
        "ATX Family Dental",
        "Austin Dental Works",
        "Toothbar"
      ],
      "citedUrls": []
    }
  ],
  "citedDomains": [
    {
      "domain": "techridgedental.com",
      "answersCiting": 1
    },
    {
      "domain": "atxfamilydental.com",
      "answersCiting": 1
    },
    {
      "domain": "austindentalworks.com",
      "answersCiting": 1
    }
  ],
  "poweredBy": "cloro (https://cloro.dev)"
}
```

### Input

- **Business category** (required), for example "dentist", "med spa", "plumber".
- **Cities** (required), US cities as "City, ST".
- **Engines**: any of ChatGPT, Microsoft Copilot and Google AI Overview (all three by default).

### Use from an AI agent / MCP

Agents can call this Actor as a tool through Apify's MCP server (`https://mcp.apify.com`) or the Apify API, by its ID `appgild/local-ai-recommendations`. Every input except the category and the cities has a default, and every row is plain JSON with the fields above.

```json
{
  "category": "dentist",
  "cities": [
    "Austin, TX",
    "Denver, CO"
  ],
  "engines": [
    "chatgpt",
    "copilot",
    "google_ai_overview"
  ]
}
```

The results are the run's default dataset, one row per city and engine plus a summary row per city. The run's summary (checks made, failed and not made, with its status message) is the `OUTPUT` record in the run's key-value store.

### Pricing

Pay per result: **$0.08 per city checked on one engine** (`city-category-check`), which covers all three phrasings. Ten cities on three engines is 30 checks, $2.40. The city summaries are free. Apify platform usage is billed to you as well.

A city-engine check is charged only when all three answers came back. If one fails at the data source, the row is saved as `partial` and is not charged. Set a maximum charge on the run and the Actor stops before it would go over it.

### Limits

- Up to **50 cities per run**. A longer list is cut, and the run's status message says how many were not checked or charged.
- **Daily capacity**: the Actor has a daily data budget shared by all its users. When it is used up, runs stop cleanly with a status message, charge nothing more, and work again after 00:00 UTC.
- ChatGPT and Copilot answers have their own daily capacity, shared by all users. When it is reached, those rows come back with `status: "capacity_reached"` and a "try again tomorrow" message, are not charged, and Google AI Overview checks carry on.
- Only a few ChatGPT and Copilot answers are asked at once across all users. When every slot stays busy for a few minutes, the remaining ChatGPT and Copilot rows come back with `status: "capacity_reached"` and a "try again later" message, and are not charged.
- ChatGPT answers can take a minute or more, and Google AI Overview checks are queued (usually a few minutes).
- Business names are read from the answers' own lists, tables and cards. Spellings that clearly match are merged ("Tobin Injury Law" and "Tobin Injury Law - Personal Injury Lawyer Atlanta", "&" and "and"); others may still appear as two rows.
- AI answers change from day to day and from person to person. One run is a sample, not a permanent ranking.

### Terms of use

By running this Actor you agree to the following.

- **As is.** The data is provided as is, without any warranty of accuracy, completeness or availability. AI answers and search results change constantly, and nothing here is advice or an endorsement of any business.
- **No competing search engine.** You may not use the data, or any part of it, to build or train a search engine, a search index, or any service that substitutes for one.
- **Your use is your responsibility.** You must comply with all laws that apply to you and with the terms of the platforms involved, including Apify and the services whose answers are checked.
- **No affiliation.** Not affiliated with or endorsed by OpenAI, Microsoft or Google. ChatGPT, Copilot and Google are trademarks of their owners. Businesses named in the examples and in the results are reported as the AI answers named them, with no affiliation or endorsement.
- **Limitation of liability.** To the extent the law allows, AppGild's total liability for any claim is limited to the amount you paid for the runs involved.
- **Indemnity.** You agree to hold Meridian Data LLC (AppGild) harmless from claims that arise from your use of the data in breach of these terms.
- **Support:** support@appgild.ai

Published by AppGild. AppGild is a brand of Meridian Data LLC, Washington, USA.

# Actor input Schema

## `category` (type: `string`):

The kind of business, as a customer would ask (for example "dentist", "med spa", "plumber").

## `cities` (type: `array`):

One city per line, US cities as "City, ST" (for example "Austin, TX"). Up to 50 per run. Each city is asked three ways on every engine you choose.

## `engines` (type: `array`):

Which AI answers to check. ChatGPT and Copilot answers come from the live apps (via cloro), asked from the city's state; Google AI Overviews from Google at the city (via DataForSEO). One charged check per city per engine.

## Actor input object example

```json
{
  "category": "dentist",
  "cities": [
    "Austin, TX"
  ],
  "engines": [
    "google_ai_overview"
  ]
}
```

# Actor output Schema

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

One row per city and engine (the businesses recommended, with counts and cited sources) and a free summary row per city.

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

Counts for the run (requested, checked, failed, not checked) and its status message.

# 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 = {
    "category": "dentist",
    "cities": [
        "Austin, TX"
    ],
    "engines": [
        "google_ai_overview"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("appgild/local-ai-recommendations").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 = {
    "category": "dentist",
    "cities": ["Austin, TX"],
    "engines": ["google_ai_overview"],
}

# Run the Actor and wait for it to finish
run = client.actor("appgild/local-ai-recommendations").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 '{
  "category": "dentist",
  "cities": [
    "Austin, TX"
  ],
  "engines": [
    "google_ai_overview"
  ]
}' |
apify call appgild/local-ai-recommendations --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,appgild/local-ai-recommendations"
        }
    }
}
```

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/wX4zrrqILzyrHLvst/builds/gIa9FbPyQzTUDPv4N/openapi.json
