# Brand Monitor Lite — Track brand mentions across the web (`perryay/brand-monitor-lite`) Actor

Monitor brand mentions, keywords, and phrases across multiple web pages. Get frequency counts, context snippets, and sentiment analysis. Ideal for PR monitoring, competitor tracking, and social listening — scan up to 20 URLs with customizable keyword lists.

- **URL**: https://apify.com/perryay/brand-monitor-lite.md
- **Developed by:** [Perry AY](https://apify.com/perryay) (community)
- **Categories:** Developer tools, Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / actor start

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Brand Monitor Lite 📡

**Track brand mentions, keywords, and sentiment across multiple web pages**

Knowing what the internet says about your brand is critical for PR, marketing, and competitive intelligence. Manually monitoring dozens of URLs for specific keywords is tedious, error-prone, and impossible to scale. **Brand Monitor Lite** automates the entire process — it scans any set of web pages for your specified keywords, returns frequency counts and surrounding context for every match, and optionally performs keyword-based sentiment analysis to gauge whether mentions are positive, negative, or neutral.

Scan up to 20 URLs per request with unlimited keywords, and use batch mode to process multiple independent scan configurations in a single execution. The actor works with any publicly accessible URL — news articles, blog posts, forum threads, review pages, or social media feeds.

---

### ✨ Features

- **Multi-URL scanning** — Scan up to 20 URLs per request with customizable keyword lists; ideal for monitoring multiple news outlets, forums, review sites, or social pages simultaneously

- **Flexible keyword matching** — Specify any number of brand names, product names, campaign tags, or industry keywords; full case-insensitive matching with regex-compatible pattern support

- **Context snippets** — For every keyword match, extracts surrounding text (up to 200 characters) so you can understand the conversational context without visiting the page

- **Frequency analysis** — Counts matches per URL per keyword for trend tracking, mention volume comparison, and spike detection

- **Keyword-based sentiment analysis** — Optional mode (premium) that scores each mention's tone as positive, negative, or neutral based on a curated dictionary of 60+ sentiment indicator words

- **Flexible output** — JSON for API and programmatic integration, plain text for human review, or CSV for spreadsheet analysis and dashboard import

- **Batch mode** — Process multiple independent URL-and-keyword sets sequentially in a single run, each with its own mode and output format

- **Automatic error handling** — Individual URL failures do not block the remaining scans; each result includes an error field describing the failure

- **Summary statistics** — Every run appends a summary row with total URLs scanned, total keywords matched, total mention count, error count, and whether sentiment analysis was used

### 🚀 Quick Start

#### Single URL — Basic Keyword Match

```json
{
  "urls": ["https://news.example.com"],
  "keywords": ["brand-name", "product-name"],
  "mode": "basic"
}
````

**Response example (basic):**

```json
{
  "url": "https://news.example.com",
  "keyword": "brand-name",
  "count": 3,
  "context": "...launched their new brand-name product line which received...",
  "sentiment": "",
  "error": ""
}
```

#### Single URL — With Sentiment Analysis

```json
{
  "urls": ["https://news.example.com/article"],
  "keywords": ["YourBrand"],
  "mode": "sentiment"
}
```

**Response example (sentiment mode):**

```json
{
  "url": "https://news.example.com/article",
  "keyword": "YourBrand",
  "count": 5,
  "context": "...YourBrand has been an excellent solution for...",
  "sentiment": "positive",
  "error": ""
}
```

#### Batch Mode — Multiple Independent Scans

```json
{
  "batchMode": true,
  "batchData": [
    {
      "urls": ["https://site1.com"],
      "keywords": ["brand-alpha"],
      "mode": "basic"
    },
    {
      "urls": ["https://site2.com", "https://site3.com"],
      "keywords": ["brand-beta"],
      "mode": "sentiment"
    }
  ]
}
```

#### Multiple URLs with Shared Keywords

```json
{
  "urls": [
    "https://news.example.com",
    "https://blog.example.com",
    "https://forum.example.com"
  ],
  "keywords": ["brand-name", "product-name", "CEO-name"],
  "mode": "sentiment"
}
```

### 📋 Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `urls` | array | `[]` | List of URLs to scan for mentions. Each URL must start with `http://` or `https://`. Maximum 20 URLs per job. |
| `keywords` | array | `[]` | Keywords or brand names to search for. Case-insensitive matching. Supports any number of keywords. |
| `mode` | string | `"basic"` | Analysis mode: `basic` (frequency + context only) or `sentiment` (adds positive/negative/neutral tone analysis via premium charge event) |
| `outputFormat` | string | `"json"` | Output format: `json` for structured data, `plain` for human-readable text, or `csv` for spreadsheet import |
| `batchMode` | boolean | `false` | Enable batch processing for multiple independent scan configurations in a single run |
| `batchData` | array | `[]` | Array of per-scan input objects, each with its own `urls`, `keywords`, `mode`, and `outputFormat` |

### 📤 Output Format

Each keyword match produces one result row pushed to the default dataset:

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Source URL where the keyword was found |
| `keyword` | string | The matched keyword |
| `count` | integer | How many times the keyword appeared in the page text |
| `context` | string | Surrounding text snippet around the first match (up to 200 characters); empty if no match |
| `sentiment` | string | Sentiment classification: `positive`, `negative`, or `neutral` (only populated in `sentiment` mode); empty string in `basic` mode |
| `error` | string | Error description if the URL could not be fetched, timed out, or failed to parse; empty string on success |

#### Summary Row

A `_summary` row is appended at the end with aggregate statistics:

| Field | Type | Description |
|-------|------|-------------|
| `_summary` | boolean | Always `true` for the summary row |
| `total_urls_scanned` | integer | Number of unique URLs that were successfully fetched |
| `total_keywords_matched` | integer | Number of keyword-URL pairs that had at least one match |
| `total_mentions` | integer | Sum of all keyword matches across all URLs |
| `total_results` | integer | Total number of result rows pushed to dataset |
| `error_count` | integer | Number of URLs that failed to fetch or parse |
| `mode` | string | Analysis mode used for the run |
| `sentiment_used` | boolean | Whether sentiment analysis was enabled |

### 🎯 Use Cases

- **PR monitoring** — Track media mentions and brand sentiment across news outlets, blogs, and review sites in near-real time; detect positive coverage and identify emerging narratives

- **Competitive intelligence** — Monitor competitor product names, campaign keywords, and industry positioning across multiple industry sources simultaneously

- **Content verification** — Verify that sponsored content, press releases, partner mentions, and syndicated articles correctly include your brand name, messaging, and required attribution

- **Crisis detection** — Get early signals of negative sentiment spikes by monitoring keywords across high-traffic URLs and news sources; respond before sentiment spreads

- **Campaign measurement** — Measure the reach of marketing campaigns by tracking campaign-specific keywords and hashtags across target publications

- **Market research** — Gather signals on industry trends, emerging topics, and shifting consumer sentiment by monitoring relevant keywords across sector-specific publications

- **Customer service monitoring** — Track how frequently your brand name appears alongside support-related terms (help, support, refund, complaint) on customer forums and review sites; sentiment mode can distinguish positive testimonials from negative experiences at a glance

- **Campaign performance measurement** — Monitor the reach and reception of marketing campaigns by tracking campaign-specific hashtags, slogans, and product names across news outlets, blogs, and influencer content. Frequency counting reveals which keywords generate the most coverage

### ⚙️ Technical Details

#### How Keyword Matching Works

The actor processes each URL through a five-stage pipeline:

1. **URL fetch:** The actor fetches each URL with an async HTTP client (httpx) with a 30-second timeout and automatic redirect following. Requests include a custom User-Agent header to ensure broad server compatibility.

2. **HTML parsing:** The response HTML is parsed with BeautifulSoup. Script tags, style blocks, noscript elements, and iframes are decomposed to isolate the readable text content from the page.

3. **Keyword matching:** Keywords are matched against the extracted text using case-insensitive regex (`re.IGNORECASE`) with `re.escape()` applied to prevent regex injection from user-provided keywords containing special regex characters like `.`, `*`, or `+`.

4. **Context extraction:** For the first occurrence of each keyword in each URL, the actor extracts a centered snippet of up to 200 characters. If the match is near the document boundary, ellipsis markers (`...`) indicate truncation on both sides.

5. **Frequency counting:** All occurrences of each keyword are counted across the full extracted text, not just the context snippet. This gives an accurate total mention count even if only a subset is shown in the context preview.

#### Sentiment Analysis Engine

Sentiment analysis uses a curated keyword-dictionary approach with 60+ indicator words split into positive and negative categories:

**Positive indicators (30 words):** good, great, excellent, amazing, wonderful, fantastic, outstanding, superb, brilliant, love, beautiful, happy, delighted, perfect, best, impressive, innovative, reliable, efficient, powerful, useful, helpful, recommend, top, quality, fast, easy, awesome, incredible, favorite

**Negative indicators (30 words):** bad, terrible, awful, horrible, poor, worst, hate, ugly, broken, failure, fail, wrong, slow, expensive, useless, disappointing, frustrating, annoying, problem, issue, bug, crash, error, complaint, waste, mediocre, outdated, unstable, difficult, horrendous, pathetic

The algorithm operates in three steps:

1. Tokenizes the context snippet (and surrounding text up to 500 characters if context is empty) into lowercase words
2. Counts the intersection between the extracted word set and each sentiment category
3. Classifies as `positive` if positive count > negative count, `negative` if negative count > positive count, `neutral` if equal or both zero

#### Error Handling Strategy

- **Per-URL isolation:** If one URL fails (timeout, DNS resolution error, connection refused, HTTP 4xx/5xx), the actor logs the error and continues processing remaining URLs. No single URL failure blocks the entire run.

- **Error reporting:** Each failed URL produces a result row with a descriptive `error` message explaining the failure type.

- **Input validation:** URLs missing a scheme (`http://`/`https://`) are silently skipped. Empty URLs in the array are also skipped.

- **Batch isolation:** In batch mode, each job is processed independently. A failure in one batch job does not affect subsequent jobs.

- **Summary transparency:** The summary row includes `error_count` so you can quickly assess result quality without scanning individual rows.

#### Performance Considerations

- Each URL is fetched sequentially to avoid overwhelming target servers
- Request timeout is set to 30 seconds per URL; pages that do not respond within this window are recorded as errors
- Large pages (100,000+ characters of extracted text) may increase processing time per URL due to regex matching across the full document
- For sentiment mode, the dictionary-based analysis adds negligible overhead (~1 ms per keyword per URL)
- Using fewer keywords per URL reduces processing time — batch separate keyword sets into independent jobs for large keyword lists

#### Understanding Your Results

When reviewing scan output, consider the following patterns:

- **High mention count + positive sentiment** — Strong brand visibility with favorable reception; good indicator of marketing campaign success
- **High mention count + negative sentiment** — Potential PR issue or product problem; investigate the context snippets for specific complaints
- **Low mention count** — Brand may be underrepresented in those sources; consider expanding URL coverage or SEO efforts
- **Error rows** — Check if the target URLs are accessible; scheduled re-scans can help distinguish temporary outages from permanent link rot

The summary row provides an at-a-glance health overview. Compare summary statistics across scheduled runs to track how brand visibility and sentiment evolve over time.

### ❓ FAQ & Troubleshooting

**Q: What happens if a URL is unreachable?**
A: The actor returns a result row with an error description and continues scanning the remaining URLs. The error field explains the failure (timeout, DNS error, connection refused, etc.).

**Q: How many keywords can I specify?**
A: There is no hard limit on keyword count. Performance depends on keyword length and page size; very long keyword lists may increase processing time.

**Q: Does sentiment analysis work on non-English text?**
A: The sentiment dictionary is English-only. For non-English pages, sentiment analysis is less reliable and may default to `neutral`. Basic keyword matching works correctly on any language.

**Q: Can I monitor the same URLs repeatedly over time?**
A: Yes. Run the actor on a schedule (via Apify scheduler) to track mention volume trends and sentiment changes over time. Deterministic keyword matching ensures consistent results across runs.

**Q: What is the difference between `basic` and `sentiment` mode?**
A: `basic` mode returns keyword frequency counts and context snippets. `sentiment` mode adds tone classification (positive/negative/neutral) and is a premium feature with an additional charge event.

**Q: How are context snippets generated?**
A: When a keyword match is found, the actor extracts 100 characters before and 100 characters after the match (up to 200 total) from the extracted page text. If the match is near the beginning or end of the document, the snippet is truncated with ellipsis markers.

**Q: Can I search for phrases with spaces?**
A: Yes. Keywords containing spaces (e.g., `"brand name"`) are matched as exact phrases using case-insensitive regex. The space is preserved in the pattern.

**Q: Does the actor handle JavaScript-rendered content?**
A: No. The actor fetches raw HTML only. Content rendered by JavaScript after page load is not captured. For JS-rendered content, consider using a headless browser scraper as a preprocessing step.

**Q: What HTTP client does the actor use internally?**
A: The actor uses `httpx` (async HTTP client) with a 30-second timeout and automatic redirect following. Requests include a custom User-Agent header (`BrandMonitorLite/1.0`).

**Q: How does the actor handle redirects on the source URLs?**
A: The HTTP client is configured with `follow_redirects=True`, so URLs that redirect to a final page are followed and the final page's HTML is analyzed.

**Q: Can I search for multiple keywords in a single run?**
A: Yes. Pass all keywords in the `keywords` array. Each keyword is matched independently, and each keyword-URL pair produces a separate result row.

**Q: What happens if a keyword contains special regex characters?**
A: Keywords are escaped with `re.escape()` before matching, so characters like `.`, `*`, `+`, `?`, `[`, `]`, `(`, `)`, `{`, `}`, `|`, `^`, `$` are treated as literal text.

**Q: Is there a limit on the total number of results?**
A: No explicit limit beyond the 20-URL cap. Each URL produces one result per keyword, so 20 URLs × 10 keywords = up to 200 result rows per job.

**Q: Does the actor support authentication for private pages?**
A: No. The actor fetches publicly accessible URLs only. Private pages, login-protected content, and API endpoints are not supported.

**Q: How does the HTML parsing handle different encodings?**
A: httpx automatically handles content encoding negotiation. The extracted text is decoded using the charset specified in the response headers.

**Q: What happens if a keyword is very long (e.g., a full sentence)?**
A: Long keywords work correctly — they are matched as literal strings (escaped) within the extracted page text. Context snippets may be truncated to the first occurrence within the 200-character window.

**Q: Can I use the actor for social media monitoring?**
A: The actor works with any publicly accessible URL, including social media pages, public Twitter/X profiles, Reddit threads, and YouTube pages. Note that content behind login walls or requiring JavaScript rendering is not accessible.

**Q: How does sentiment mode handle mixed sentiment?**
A: The sentiment classifier compares the count of positive words vs negative words. If both categories have matches, the classification reflects which count is higher. If counts are equal or both zero, the result is `neutral`.

**Q: Is there a difference between "no match" (count=0) and "URL fetch error"?**
A: Yes. A keyword with `count: 0` means the page was successfully fetched but the keyword was not found. An error row means the page could not be fetched at all and no content analysis was performed. The `error` field distinguishes these cases.

**Q: How can I track mention volume over time?**
A: Schedule the actor to run at regular intervals (daily, weekly) via Apify scheduler. Compare the `total_mentions` value in the summary row across runs to identify trends, spikes, and seasonal patterns in brand coverage.

**Q: Does the actor normalize whitespace in extracted text?**
A: Yes. BeautifulSoup's `get_text(separator=" ", strip=True)` collapses whitespace and joins text blocks with single spaces, producing clean, normalized text for keyword matching and context extraction.

**Q: What happens when a URL returns a non-200 status code?**
A: Non-200 HTTP responses (301, 302, 403, 404, 500, etc.) are treated as fetch failures. The actor logs the status code in the error message and returns an error row for each keyword.

***

### 🔗 Related Tools

Check out other developer utilities by [perryay](https://apify.com/perryay):

| Tool | Description |
|------|-------------|
| [JSON Studio](https://apify.com/perryay/json-studio) | Format, validate, transform, and diff JSON data with 8 operation modes |
| [QR Craft](https://apify.com/perryay/qr-craft) | Generate high-quality QR codes in PNG or SVG, batch up to 50 |
| [UUID Lab](https://apify.com/perryay/uuid-lab) | Generate UUID v4/v7, NanoID, Short ID, and ULID identifiers |
| [Domain Intel](https://apify.com/perryay/domain-intel) | WHOIS, DNS, and SSL lookup for domain intelligence |
| [Meta Mate](https://apify.com/perryay/meta-mate) | Extract Open Graph, Twitter Cards, and JSON-LD metadata |
| [IP Geo](https://apify.com/perryay/ip-geo) | Multi-provider IP geolocation with ISP detection |
| [URL Health](https://apify.com/perryay/url-health) | Check URL accessibility, redirects, and SSL health |
| [PW Forge](https://apify.com/perryay/pw-forge) | Generate secure passwords with entropy calculation |
| [TZ Mate](https://apify.com/perryay/tz-mate) | Convert timezones and check DST offsets |
| [Regex Lab](https://apify.com/perryay/regex-lab) | Test and debug regular expressions online |
| [Brand Monitor Lite](https://apify.com/perryay/brand-monitor-lite) | Track brand mentions across multiple URLs |
| [Link Quality Analyzer](https://apify.com/perryay/link-quality-analyzer) | Detect broken links and audit link quality |
| [Mock Data Generator](https://apify.com/perryay/mock-data-generator) | Generate realistic test data for development |
| [HTML to Markdown](https://apify.com/perryay/html-to-markdown) | Convert web pages or HTML to clean Markdown |
| [SSL Cert Inspector](https://apify.com/perryay/ssl-cert-inspector) | Deep SSL/TLS certificate analysis with scoring |

# Actor input Schema

## `urls` (type: `array`):

List of URLs to scan for brand/keyword mentions (max 20)

## `keywords` (type: `array`):

Keywords or brand names to search for in the page content

## `mode` (type: `string`):

Select analysis mode — 'basic' for keyword matching only, 'sentiment' for keyword matching plus sentiment analysis on mentions

## `outputFormat` (type: `string`):

Output format: json, plain, or csv

## `batchMode` (type: `boolean`):

Enable batch processing to run multiple independent jobs in one actor run

## `batchData` (type: `array`):

Array of input objects for batch processing. Each object can have urls, keywords, mode, and outputFormat.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "keywords": [
    "brand-name",
    "product"
  ],
  "mode": "basic",
  "outputFormat": "json",
  "batchMode": false
}
```

# Actor output Schema

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

Per-keyword mention results in the default dataset

# 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 = {
    "urls": [
        "https://example.com"
    ],
    "keywords": [
        "brand-name",
        "product"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("perryay/brand-monitor-lite").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 = {
    "urls": ["https://example.com"],
    "keywords": [
        "brand-name",
        "product",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("perryay/brand-monitor-lite").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "urls": [
    "https://example.com"
  ],
  "keywords": [
    "brand-name",
    "product"
  ]
}' |
apify call perryay/brand-monitor-lite --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=perryay/brand-monitor-lite",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Brand Monitor Lite — Track brand mentions across the web",
        "description": "Monitor brand mentions, keywords, and phrases across multiple web pages. Get frequency counts, context snippets, and sentiment analysis. Ideal for PR monitoring, competitor tracking, and social listening — scan up to 20 URLs with customizable keyword lists.",
        "version": "1.0",
        "x-build-id": "CFZ5j8PcKlhJlNOdn"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/perryay~brand-monitor-lite/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-perryay-brand-monitor-lite",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/perryay~brand-monitor-lite/runs": {
            "post": {
                "operationId": "runs-sync-perryay-brand-monitor-lite",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/perryay~brand-monitor-lite/run-sync": {
            "post": {
                "operationId": "run-sync-perryay-brand-monitor-lite",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "urls": {
                        "title": "URLs",
                        "maxItems": 20,
                        "type": "array",
                        "description": "List of URLs to scan for brand/keyword mentions (max 20)",
                        "items": {
                            "type": "string"
                        }
                    },
                    "keywords": {
                        "title": "Keywords",
                        "type": "array",
                        "description": "Keywords or brand names to search for in the page content",
                        "items": {
                            "type": "string"
                        }
                    },
                    "mode": {
                        "title": "Analysis Mode",
                        "enum": [
                            "basic",
                            "sentiment"
                        ],
                        "type": "string",
                        "description": "Select analysis mode — 'basic' for keyword matching only, 'sentiment' for keyword matching plus sentiment analysis on mentions",
                        "default": "basic"
                    },
                    "outputFormat": {
                        "title": "Output Format",
                        "enum": [
                            "json",
                            "plain",
                            "csv"
                        ],
                        "type": "string",
                        "description": "Output format: json, plain, or csv",
                        "default": "json"
                    },
                    "batchMode": {
                        "title": "Batch Mode",
                        "type": "boolean",
                        "description": "Enable batch processing to run multiple independent jobs in one actor run",
                        "default": false
                    },
                    "batchData": {
                        "title": "Batch Data",
                        "type": "array",
                        "description": "Array of input objects for batch processing. Each object can have urls, keywords, mode, and outputFormat."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
