# Local AI Presence Monitor — Changes & Alerts (`travelmonitorlab/local-ai-presence-monitor`) Actor

Monitor a local business over time. Detect new Google reviews, rating changes and website AI-readiness changes, keep persistent history and send webhook alerts. API, MCP and x402/USDC ready.

- **URL**: https://apify.com/travelmonitorlab/local-ai-presence-monitor.md
- **Developed by:** [Travel Monitor Lab](https://apify.com/travelmonitorlab) (community)
- **Categories:** AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $212.50 / 1,000 business monitoreds

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

## Local AI Presence Monitor — Changes & Alerts

[![Local AI Presence Monitor status](https://apify.com/actor-badge?actor=travelmonitorlab/local-ai-presence-monitor)](https://apify.com/travelmonitorlab/local-ai-presence-monitor)

Monitor a local business over time instead of repeating a one-off audit. This Actor compares each new snapshot with persistent state, detects new public Google reviews, rating and review-count changes, website AI-readiness changes, and score drops. It can also benchmark the target against up to three competitors with the same Google/review scoring method. It returns structured JSON, retains up to 50 snapshots and can send high-severity alerts to your webhook.

### Use this tool when

- You already know which business, store, hotel, restaurant or agency client you want to monitor.
- You need a durable baseline and a clear answer to “what changed since the last run?”
- You want new-review detection without receiving the same review as new on every run.
- You want an automation webhook only for important changes, while keeping every observation in JSON.
- You need a scheduled monitoring step that an AI agent, CRM or reporting workflow can call through API or MCP.
- You want to compare a business with up to three competitors using an explicit, comparable Google-profile and recent-review score.

Use [Local AI Presence Audit](https://apify.com/travelmonitorlab/local-ai-presence-audit) instead when you need a one-time full audit with an action plan, llms.txt and LocalBusiness JSON-LD deliverables. Use [Review Radar](https://apify.com/travelmonitorlab/review-radar) when your primary workflow is Slack alerting for Google reviews.

### What changes are detected

The first successful run creates a baseline. It does not mark all existing reviews as new. Subsequent runs can detect:

- New review IDs in the recent Google review window, with Bayesian urgency classification.
- Google rating and total review-count changes.
- Presence-score changes and configurable score-drop alerts.
- Loss or addition of LocalBusiness, FAQ and other JSON-LD signals.
- Meta description, H1 and Open Graph changes.
- `/llms.txt` availability changes.
- `robots.txt` AI-crawler rule changes.

The website scan measures technical AI-readiness signals. It does not claim that a business is cited by ChatGPT, Gemini or Perplexity.

### Quick start

1. Enter a business name and city in `query`, a public `websiteUrl`, or both.
2. Keep `dryRun` enabled for the first integration test. Dry-run skips billing events and webhook delivery; platform compute and proxy usage can still apply.
3. Run the Actor once to create the baseline, then run the same input again.
4. Read `verdict`, `changes`, `newReviews` and `alertDeliveryStatus` in the dataset.
5. Add a schedule in Apify only after the two test runs produce the expected stateful behavior.

For a website-only monitor, leave `query` empty. This avoids browser and Google proxy usage. For Google Maps monitoring, the low-cost default uses datacenter proxy. If Google blocks the request, select the `RESIDENTIAL` proxy group and account for separate residential-traffic costs.

### Input

| Field | Purpose |
|---|---|
| `query` | Optional business name and city used to resolve the Google Maps profile. |
| `websiteUrl` | Public website scanned for technical AI-readiness signals. |
| `maxReviews` | Recent reviews inspected per run, from 1 to 30. |
| `competitorQueries` | Optional list of up to three competitor names with city. Produces comparable scores and a target rank. |
| `scoreDropThreshold` | Point drop that makes a score change high severity. Default: 5. |
| `ratingDropThreshold` | Star-rating drop that triggers high severity. Default: 0.2. |
| `webhookUrl` | Optional secret URL receiving a JSON POST for high-severity alerts. |
| `slackConnector` / `slackChannel` | Optional MCP connector and channel for high-severity Slack alerts outside dry-run. Credentials stay in the connector proxy. |
| `language` | Google Maps interface language, such as `fr`, `en` or `de`. |
| `dryRun` | Skips event charges, webhook and Slack delivery. |
| `proxyConfiguration` | Apify proxy settings used only when `query` is present. |

### Output

Each run writes one main dataset item:

- `verdict`: `baseline`, `unchanged`, `changes-detected` or `error`.
- `presenceScore` and `scoreComponents`: transparent scoring, not a third-party ranking promise.
- `rating`, `reviewCount` and `reviewsAnalyzed`.
- `newReviewCount` and `newReviews`.
- `changeCount`, `changes` and `alertCount`.
- `alertDeliveryStatus`: `no-alerts`, `not-configured`, `delivered`, `failed` or `dry-run-skipped`.
- `websiteAudit` and `googleProfile` for the current observation.
- `historySize` and a stable `monitorStateKey` derived from the target.
- `competitors` with one comparable result per successful competitor.
- `competitorComparison` with target score, average competitor score, difference, rank and the exact comparison method.

The default key-value store also contains `SUMMARY`, `HISTORY` and `ALERTS`. Persistent named storage keeps state between runs; `HISTORY` retains the newest 50 snapshots.

### Webhook payload

When alerts exist, dry-run is disabled and `webhookUrl` is configured, the Actor sends a JSON POST containing `text`, `business`, `capturedAt`, `alerts` and `newReviews`. Use your own authorized automation endpoint. A delivery failure is reported in the dataset; the monitoring snapshot is still retained.

### Pricing

Pay-per-event pricing:

| Event | Price | When |
|---|---:|---|
| `run-started` | $0.25 | Once per run, outside dry-run. |
| `business-monitored` | $0.25 | When at least one source is successfully analyzed. |
| `competitor-compared` | $0.10 | Per competitor successfully analyzed outside dry-run. |
| `alert-delivered` | $0.10 | Only after successful webhook delivery. |

Apify compute and proxy usage are separate. A website-only run avoids Google browser/proxy work. The public prefilled scenario is website-only and uses dry-run for inexpensive QA.

### API and AI agents

Run by name through the Apify API, or use the shared MCP server at `https://mcp.apify.com`. An agent should read the input schema, preserve the same target between runs and use the returned change objects rather than inferring changes from prose.

Example input:

```json
{
  "query": "restaurant Esch-sur-Alzette",
  "websiteUrl": "https://example.lu",
  "maxReviews": 5,
  "scoreDropThreshold": 5,
  "ratingDropThreshold": 0.2,
  "dryRun": true,
  "proxyConfiguration": {"useApifyProxy": true}
}
```

This Actor supports Apify agentic payments through x402/USDC when called through the enabled payment flow. Standard authenticated API and MCP calls remain available.

### Scheduling and limits

Schedule the same saved task daily or weekly. Changing `query` or `websiteUrl` creates a different target state key. Keep the input stable for meaningful comparisons. A recent-review window can miss a review if it disappears from that window between two infrequent runs; use a frequency appropriate for the business. Public web data and third-party availability can vary. Only collect data you are authorized to process and review applicable privacy and platform terms.

### Related Actors

- [Local AI Presence Audit](https://apify.com/travelmonitorlab/local-ai-presence-audit) — one-time audit and ready-to-publish fixes.
- [Review Radar](https://apify.com/travelmonitorlab/review-radar) — Google review monitoring and Slack workflows.
- [AEO AI Visibility Checker](https://apify.com/travelmonitorlab/aeo-ai-visibility-checker) — website-only technical AI visibility checks.

Built by [Adaga solutions](https://adagasolutions.lu). For support, open an issue on the Actor page with the run ID, input and expected behavior. Include enough detail for an honest review of the problem; do not include webhook secrets or personal credentials.

# Actor input Schema

## `query` (type: `string`):

Optional business name and city used to find the Google Maps profile, for example 'Boulangerie Paul Mersch'. Leave empty for a website-only monitor with no Google proxy usage.

## `websiteUrl` (type: `string`):

Public website URL to monitor for JSON-LD, LocalBusiness and FAQ schema, metadata, llms.txt and AI-crawler robots.txt signals. The default is a small website-only QA scenario.

## `maxReviews` (type: `integer`):

Number of recent public Google reviews to compare with persistent state. Higher values can increase run time and proxy usage.

## `competitorQueries` (type: `array`):

Optional list of up to three competing businesses with city. Each successful profile receives the same Google-profile and recent-review score as the target for a fair comparison. Website AEO is excluded from this comparison.

## `scoreDropThreshold` (type: `integer`):

Create a high-severity alert when the transparent presence score falls by at least this many points since the previous run.

## `ratingDropThreshold` (type: `number`):

Create a high-severity alert when the public Google rating falls by at least this amount, for example 0.2 stars.

## `webhookUrl` (type: `string`):

Optional HTTPS endpoint receiving a JSON POST when high-severity changes are detected. Compatible with generic automation webhooks. Dry-run never calls this URL.

## `slackConnector` (type: `string`):

Authorized MCP connector used to post high-severity alerts outside dry-run. The Actor receives only a connector ID; Slack credentials stay in the proxy.

## `slackChannel` (type: `string`):

Channel receiving high-severity local-presence alerts.

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

Two-letter interface language used when resolving and reading Google Maps, such as fr, en or de.

## `dryRun` (type: `boolean`):

Run the complete monitoring workflow but skip pay-per-event charges and webhook delivery. Apify compute and proxy usage can still apply.

## `proxyConfiguration` (type: `object`):

Apify proxy used only when query is set. Datacenter is the low-cost default. Select the RESIDENTIAL group if Google Maps blocks the run; residential traffic is billed separately.

## Actor input object example

```json
{
  "query": "",
  "websiteUrl": "https://adagasolutions.lu",
  "maxReviews": 5,
  "competitorQueries": [],
  "scoreDropThreshold": 5,
  "ratingDropThreshold": 0.2,
  "slackChannel": "#general",
  "language": "fr",
  "dryRun": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `monitoringReport` (type: `string`):

No description

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

No description

## `history` (type: `string`):

No description

## `alerts` (type: `string`):

No description

# 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 = {
    "query": "",
    "websiteUrl": "https://adagasolutions.lu",
    "maxReviews": 5,
    "competitorQueries": [],
    "scoreDropThreshold": 5,
    "ratingDropThreshold": 0.2,
    "language": "fr",
    "dryRun": true,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("travelmonitorlab/local-ai-presence-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 = {
    "query": "",
    "websiteUrl": "https://adagasolutions.lu",
    "maxReviews": 5,
    "competitorQueries": [],
    "scoreDropThreshold": 5,
    "ratingDropThreshold": 0.2,
    "language": "fr",
    "dryRun": True,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("travelmonitorlab/local-ai-presence-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 '{
  "query": "",
  "websiteUrl": "https://adagasolutions.lu",
  "maxReviews": 5,
  "competitorQueries": [],
  "scoreDropThreshold": 5,
  "ratingDropThreshold": 0.2,
  "language": "fr",
  "dryRun": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call travelmonitorlab/local-ai-presence-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,travelmonitorlab/local-ai-presence-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/KEUskSh3RYsI1akeT/builds/xmNQiYgbZn57gPeQi/openapi.json
