# Capterra Reviews Scraper (`reviewly/capterra-reviews-scraper`) Actor

Scrapes verified reviews from any Capterra product page. Extracts ratings, pros/cons, reviewer profiles, sub-scores, and product metadata

- **URL**: https://apify.com/reviewly/capterra-reviews-scraper.md
- **Developed by:** [Reviewly](https://apify.com/reviewly) (community)
- **Categories:** Automation, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 record scrapeds

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

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.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.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/platform/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

## Capterra Reviews Scraper — Extract Verified Software Reviews at Scale

> Pull thousands of structured, verified reviews from any Capterra product page. Ratings, pros/cons, reviewer profiles, sub-scores — all delivered as clean JSON, automatically bypassing Cloudflare protection.

**The fastest way to get Capterra review data without writing a line of scraping code.**

- Automatically solves Cloudflare challenges — zero manual setup
- Extracts full review content: body text, pros, cons, 5 sub-ratings, likelihood to recommend
- Supports multiple products per run with proxy rotation
- Free tier included — start scraping in under 2 minutes

---

### 📌 What This Actor Does

Capterra is one of the most authoritative B2B software review platforms on the internet, hosting millions of verified user reviews across thousands of products and categories. Getting that data programmatically has always been difficult — Capterra uses Cloudflare, which blocks most scrapers instantly.

This Actor solves that. It uses a headless browser with stealth fingerprinting to pass Cloudflare's bot detection, then switches to a fast HTTP client for all subsequent page fetches — giving you the reliability of a full browser with the speed of direct requests.

**Who is this for?**

- **SaaS companies** monitoring competitor sentiment and feature perception
- **Marketing agencies** building review-backed content for clients
- **Product teams** benchmarking their software against alternatives
- **Market researchers** analyzing buyer language, pain points, and trends
- **Sales teams** identifying objections and positioning opportunities

---

### ✨ Key Features

- **Cloudflare bypass built-in** —
- **Complete review data** — Title, body, date, overall rating, 5 sub-ratings, likelihood to recommend (0–10), pros, and cons
- **Rich reviewer profiles** — Name, job title, industry, and how long they've used the product
- **Product metadata** — Name, logo URL, aggregate rating, total review count, category, and description
- **Pagination handled automatically** — Up to 100 pages (2,500 reviews) per product
- **Date-based cutoff** — Stop scraping once reviews are older than a target date; ideal for monitoring new reviews
- **Review cap** — Set a `maxReviews` limit to control cost and run time precisely
- **Multi-product runs** — Pass a list of URLs and scrape multiple products in one run
- **Proxy-ready** — Works with Apify Residential or any proxy configuration you provide
- **Retry logic** — Exponential backoff on failed page fetches; up to 5 retries per page

---

### 🧠 Why This Actor Is Different

Most Capterra scrapers break within days because they rely on CSS class names that Capterra rotates frequently. This Actor uses **semantic selectors tied to `data-testid` attributes and structural patterns** — the same attributes Capterra's own test suite uses — making it significantly more resilient to layout changes.

**Data quality highlights:**

- Sub-ratings (`Ease of Use`, `Features`, `Value for Money`, `Customer Service`) are extracted individually — not just the headline score
- `likelihoodToRecommend` is a numeric 0–10 value (direct from Capterra's progress element), not a string
- Review dates are extracted as displayed (e.g. `"June 11, 2026"`) — parse them with your preferred date library
- Pros and cons are extracted as raw text exactly as reviewers wrote them

---

### ⚙️ Input Configuration

Configure the Actor using the Apify Console UI or by passing a JSON input directly.

#### Input fields

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | `array` | required | One or more Capterra product or review URLs |
| `maxReviews` | `number` | `0` (all) | Maximum reviews to collect across all URLs. `0` means no limit |
| `targetDate` | `string` | `null` | ISO 8601 date (`YYYY-MM-DD`). Stop when reviews are older than this date |
| `proxyConfiguration` | `object` | `{}` | Apify proxy settings. Recommended for production runs |

#### Accepted URL formats

Both product URLs and review URLs are accepted:

````

https://www.capterra.com/p/211559/Trello/
https://www.capterra.com/p/211559/Trello/reviews/

````

#### Example input

```json
{
  "startUrls": [
    { "url": "https://www.capterra.com/p/211559/Trello/reviews/" },
    { "url": "https://www.capterra.com/p/52553/Asana/reviews/" }
  ],
  "maxReviews": 500,
  "targetDate": "2024-01-01",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
````

#### Tips

- **For monitoring**: set `targetDate` to the date of your last run to collect only new reviews
- **For large datasets**: use `maxReviews` to cap costs on your first test run, then remove the limit once you've validated the output
- **Proxy**: Residential proxies are recommended for sustained runs. Without a proxy, the Actor still works but may be slower if Cloudflare becomes stricter
- **Free tier**: free users are limited to 100 reviews per day across all runs. This resets at midnight UTC

***

### 📤 Output Format

Each Capterra product URL produces one record in the Apify dataset. The record contains product-level metadata alongside a `reviews` array.

#### Sample output

```json
{
  "name": "Trello",
  "productUrl": "https://www.capterra.com/p/211559/Trello/reviews/",
  "logoUrl": "https://gdm-catalog-fmapi-prod.imgix.net/ProductLogo/415abb34-...",
  "rating": 4.5,
  "reviewCount": 23551,
  "category": "Collaboration Software",
  "description": "Trello is a project management software that helps teams capture, organize, and tackle their to-dos from anywhere...",
  "reviews": [
    {
      "reviewerName": "Gabby W.",
      "reviewerJob": "Founder",
      "reviewerIndustry": "E-Learning",
      "usageDuration": "1-2 years",
      "title": "Great for project management",
      "date": "May 25, 2026",
      "rating": 5,
      "Overall Rating": 5,
      "Ease of Use": 5,
      "Features": 5,
      "Value for Money": 5,
      "likelihoodToRecommend": 10,
      "reviewBody": "I've had a very positive experience with Trello overall. It's a simple and effective project management tool that makes it easy to organize tasks, content, and workflows visually.",
      "pros": "Very easy to learn and use, even for beginners\nClean visual layout with boards, lists, and cards\nGreat for task management, content planning, and team collaboration",
      "cons": "Can feel limited for larger or more complex project management needs\nSome useful features are locked behind paid plans"
    },
    {
      "reviewerName": "Sean M.",
      "reviewerJob": "Chief Editor at deBanked",
      "reviewerIndustry": "Financial Services",
      "usageDuration": "2+ years",
      "title": "The magical visual simplicity for my straightforward workflows",
      "date": "June 11, 2026",
      "rating": 5,
      "Overall Rating": 5,
      "Ease of Use": 5,
      "Customer Service": 5,
      "Features": 4,
      "Value for Money": 5,
      "likelihoodToRecommend": 10,
      "reviewBody": "Immediate visual satisfaction and a fluid workflow. The almost playful nature of Trello's interface disguises a surprisingly powerful system.",
      "pros": "Trello is, in my opinion, the most accessible and refreshing project management tool I have used.",
      "cons": "This simplicity, which is its strength, is also its main limitation when projects grow complex."
    }
  ]
}
```

#### Field reference

**Product-level fields**

| Field | Type | Description |
|---|---|---|
| `name` | `string` | Product name |
| `productUrl` | `string` | Canonical reviews URL |
| `logoUrl` | `string` | Product logo image URL |
| `rating` | `number` | Aggregate rating (e.g. `4.5`) |
| `reviewCount` | `number` | Total review count shown on Capterra |
| `category` | `string` | Primary software category |
| `description` | `string` | Product description from Capterra |

**Per-review fields**

| Field | Type | Description |
|---|---|---|
| `reviewerName` | `string` | Reviewer's display name |
| `reviewerJob` | `string` | Reviewer's job title |
| `reviewerIndustry` | `string` | Reviewer's industry |
| `usageDuration` | `string` | How long they've used the product (e.g. `"1-2 years"`) |
| `title` | `string` | Review headline |
| `date` | `string` | Review date as displayed (e.g. `"May 25, 2026"`) |
| `rating` | `number` | Overall star rating (1.0–5.0) |
| `Overall Rating` | `number` | Overall sub-rating |
| `Ease of Use` | `number` | Ease of use sub-rating |
| `Features` | `number` | Features sub-rating |
| `Value for Money` | `number` | Value for money sub-rating |
| `Customer Service` | `number` | Customer service sub-rating (when present) |
| `likelihoodToRecommend` | `number` | Likelihood to recommend (0–10) |
| `reviewBody` | `string` | Full review text |
| `pros` | `string` | Reviewer's stated pros |
| `cons` | `string` | Reviewer's stated cons |

> **Note:** Sub-rating fields (`Overall Rating`, `Ease of Use`, etc.) are only present when the reviewer provided them. Not all reviews include all sub-ratings.

***

### ▶️ How to Use

#### Option 1 — Apify Console (recommended for beginners)

1. Open the Actor on the [Apify Store](https://apify.com/store)
2. Click **Try for free**
3. In the **Input** tab, paste your Capterra URL(s) into the `startUrls` field
4. Click **Start**
5. When the run finishes, open the **Dataset** tab to view or export your data (JSON, CSV, Excel)

#### Option 2 — Apify API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
    "startUrls": [
      { "url": "https://www.capterra.com/p/211559/Trello/reviews/" }
    ],
    "maxReviews": 100
  }'
```

#### Option 3 — Schedule recurring runs

1. Go to your Actor run → **Schedules**
2. Set a daily or weekly interval
3. Use `targetDate` set to yesterday's date to collect only new reviews since the last run

#### Finding the right URL

1. Go to [capterra.com](https://www.capterra.com) and search for any software product
2. Open the product page and click the **Reviews** tab
3. Copy the URL — it will look like `https://www.capterra.com/p/XXXXX/ProductName/reviews/`
4. Paste it into `startUrls`

***

### 📈 Use Cases

#### 1. Competitive intelligence for SaaS companies

Compare your product's reviews against 3–5 competitors. Analyze what customers praise in rival products (their strengths you need to close), what they criticize (positioning opportunities), and how your `likelihoodToRecommend` scores stack up over time.

#### 2. Voice-of-customer content for marketing

Extract verbatim customer language from hundreds of reviews. Use the vocabulary in ad copy, landing pages, and email campaigns — words real customers use convert better than anything a copywriter invents.

#### 3. Product roadmap signals

Feed review `pros` and `cons` text into a simple text-analysis pipeline to surface the most frequently mentioned feature gaps and pain points across a category. Data from 1,000+ reviews surfaces patterns no amount of user interviews can match.

#### 4. Review monitoring and alerting

Run the Actor on a schedule with a `targetDate` cutoff. New negative reviews (rating ≤ 2) can trigger Slack alerts or CRM tasks for your customer success team to follow up.

#### 5. Agency reporting and benchmarking

Build automated monthly competitive reports for clients by scraping their product page and their top 3 competitors. Combine rating trends, review volume, and NPS-equivalent (`likelihoodToRecommend`) into a single benchmark dashboard.

***

### 🛠️ Advanced Tips

#### Using proxies for production runs

Capterra is protected by Cloudflare. While the Actor handles bot detection automatically, using **Residential proxies** improves reliability for large runs:

```json
{
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

Datacenter proxies may work for small runs but can trigger additional Cloudflare challenges at scale.

#### Incremental scraping with `targetDate`

To collect only reviews published after your last run, set `targetDate` to the date of that run:

```json
{
  "startUrls": [{ "url": "https://www.capterra.com/p/211559/Trello/reviews/" }],
  "targetDate": "2025-01-01"
}
```

The Actor stops paginating as soon as it encounters a review older than this date, making incremental runs fast and cheap.

#### Scraping multiple products efficiently

Pass all your URLs in a single `startUrls` array. The Actor processes them sequentially with a shared review budget:

```json
{
  "startUrls": [
    { "url": "https://www.capterra.com/p/211559/Trello/reviews/" },
    { "url": "https://www.capterra.com/p/52553/Asana/reviews/" },
    { "url": "https://www.capterra.com/p/150855/monday-com/reviews/" }
  ],
  "maxReviews": 1500
}
```

#### How many reviews can I get?

Capterra's pagination is publicly accessible up to **100 pages × 25 reviews = 2,500 reviews per product**. Reviews beyond page 100 are not accessible via public URLs. For products with more reviews (like Trello with 23,000+), the 2,500 most helpful reviews are returned.

***

### ❓ FAQ & Troubleshooting

**Q: Why did my run return 0 reviews?**

A: Check that your URL points to a valid Capterra product page with reviews. The URL must match the pattern `capterra.com/p/XXXXX/ProductName/`. If the URL includes filters (e.g. `?overallRating=5`), the Actor will ignore query parameters and scrape all reviews.

***

**Q: I'm getting HTTP 403 or 429 errors in the logs.**

A: Cloudflare is blocking the request. This usually means the proxy IP has been flagged. Switch to Residential proxies (`RESIDENTIAL` group in Apify Proxy) and try again. If you're on a free plan without proxy access, wait a few minutes between runs.

***

**Q: The run stopped before collecting all reviews. Why?**

A: Three possible reasons:

1. You hit the `maxReviews` cap — increase it or set it to `0`
2. You hit the free-tier daily limit (100 reviews/day) — upgrade or wait until midnight UTC
3. A page consistently failed to load after 5 retries — check the Actor log for `Failed to fetch page` messages, which usually indicate a Cloudflare block

***

**Q: Some reviews are missing `Customer Service` rating. Is that a bug?**

A: No. Not all reviewers fill in every sub-rating on Capterra. The fields are only present in the output when the reviewer provided them.

***

**Q: Can I scrape reviews filtered by rating or date on Capterra?**

A: The Actor always scrapes the default "Most Helpful" sort order. Capterra's filter URLs (e.g. `?overallRating=5`) are not supported — but you can filter the output dataset after the fact using the Apify dataset filter tools or your own code.

***

**Q: How often does Capterra change its HTML structure?**

A: Capterra occasionally updates its frontend. This Actor uses stable `data-testid` attributes rather than CSS class names, making it more resilient than most scrapers. If a structural change does break the Actor, fixes are typically released within 48 hours. Watch the Actor changelog for updates.

***

**Q: Is web scraping Capterra legal?**

A: This Actor collects only **publicly available data** — the same information anyone can read in a browser without logging in. Always ensure your use of the data complies with Capterra's Terms of Service and applicable laws (GDPR, CCPA, etc.) in your jurisdiction.

***

### 📞 Support

- **Bug reports & feature requests:** Open an issue in the Actor's GitHub repository or contact via the Apify Store page
- **Email:** [me](mailto:me@ahmedhrid.com)
- **Apify Community:** [community.apify.com](https://community.apify.com)

Response time is typically within 24 hours on business days.

# Actor input Schema

## `startUrls` (type: `array`):

Capterra product URLs to scrape. Accepts both the product page (e.g. /p/211559/Trello/) and the reviews page (e.g. /p/211559/Trello/reviews/).

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

Maximum number of reviews to scrape per product URL. 0 means no limit (up to 2,500 per product — Capterra's pagination cap).

## `targetDate` (type: `string`):

Stop scraping reviews older than this date (ISO 8601, e.g. 2025-01-01). Useful for incremental runs — set to the date of your last run to collect only new reviews.

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

Residential proxy is recommended for sustained runs — the same session is shared between the Cloudflare bypass browser and all subsequent fetch requests.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.capterra.com/p/195793/Quixy/reviews/"
    }
  ],
  "maxReviews": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Each record contains product info (name, rating, reviewCount, category, logoUrl, description) and a reviews array with title, date, rating, sub-ratings (Ease of Use, Features, Value for Money, Customer Service), likelihoodToRecommend, reviewBody, pros, cons, and reviewer details (name, job, industry, usageDuration).

# 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 = {
    "startUrls": [
        {
            "url": "https://www.capterra.com/p/195793/Quixy/reviews/"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reviewly/capterra-reviews-scraper").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 = {
    "startUrls": [{ "url": "https://www.capterra.com/p/195793/Quixy/reviews/" }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("reviewly/capterra-reviews-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.capterra.com/p/195793/Quixy/reviews/"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call reviewly/capterra-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=reviewly/capterra-reviews-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Capterra Reviews Scraper",
        "description": "Scrapes verified reviews from any Capterra product page. Extracts ratings, pros/cons, reviewer profiles, sub-scores, and product metadata",
        "version": "0.0",
        "x-build-id": "RLGN8FK5ZytkWmNui"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/reviewly~capterra-reviews-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-reviewly-capterra-reviews-scraper",
                "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/reviewly~capterra-reviews-scraper/runs": {
            "post": {
                "operationId": "runs-sync-reviewly-capterra-reviews-scraper",
                "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/reviewly~capterra-reviews-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-reviewly-capterra-reviews-scraper",
                "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",
                "required": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Capterra product URLs to scrape. Accepts both the product page (e.g. /p/211559/Trello/) and the reviews page (e.g. /p/211559/Trello/reviews/).",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxReviews": {
                        "title": "Max reviews per product",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of reviews to scrape per product URL. 0 means no limit (up to 2,500 per product — Capterra's pagination cap).",
                        "default": 0
                    },
                    "targetDate": {
                        "title": "Target date",
                        "type": "string",
                        "description": "Stop scraping reviews older than this date (ISO 8601, e.g. 2025-01-01). Useful for incremental runs — set to the date of your last run to collect only new reviews."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Residential proxy is recommended for sustained runs — the same session is shared between the Cloudflare bypass browser and all subsequent fetch requests."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
