# Capterra Scraper - Software Ratings & Pricing (`s-r/capterra-scraper`) Actor

Read a Capterra software profile as structured data: overall rating and review count, all four rating dimensions with the number of reviews behind each, starting price, pricing model, payment frequency, free-trial and free-version flags. Paste product URLs, get one row per product.

- **URL**: https://apify.com/s-r/capterra-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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 Scraper - Software Ratings & Pricing

Turn a Capterra product page into a row of structured data. Paste the URLs of
the software products you care about and get back the overall rating, the four
rating dimensions with the number of reviews behind each one, the published
starting price and how it is charged, free-trial and free-version flags, the
category, and the vendor's own description.

One row per product. No API key, no login.

### What you get per product

**Identity** — `name`, `product_id`, `slug`, `url`, `logo_url`, `description`,
`category` and `breadcrumbs` (the category path the product sits under, such as
Home › Project Management Software › monday.com).

**Ratings** — `rating` and `review_count` for the headline score, then each
dimension separately:

- `ease_of_use_rating` and `ease_of_use_reviews`
- `customer_support_rating` and `customer_support_reviews`
- `value_for_money_rating` and `value_for_money_reviews`
- `functionality_rating` and `functionality_reviews`
- `recommend_percent`

**Pricing** — `starting_price`, `starting_plan` (the plan that price belongs
to, such as Pro or Plus), `pricing_model` (what the price is charged per, for
example Per User), `payment_frequency` (Per Month, Per Year), `has_free_trial`
and `has_free_version`.

### Every dimension carries its own review count, and that matters

This is the detail most comparisons drop. On Slack's profile the overall score
rests on 24,194 reviews, but the dimensions are not evenly evidenced:

| Dimension | Rating | Reviews behind it |
|---|---|---|
| Ease of use | 4.6 | 22,749 |
| Functionality | 4.6 | 22,130 |
| Value for money | 4.5 | 15,307 |
| Customer support | 4.4 | 13,566 |

A support score built on 13,566 reviews and an ease-of-use score built on 22,749
are not equally settled, and averaging the four dimensions as though they were
gives every product a number that is quietly wrong. Both halves are returned so
you can weight them yourself, or discard a dimension whose sample is too thin to
carry an argument.

### Paste URLs, not id numbers

The input takes the address of the product page. Bare id numbers are refused on
purpose, and the reason is worth stating plainly: **a Capterra id cannot be
guessed or inferred**. While building this, id 189442 looked like a plausible
guess for a well-known design tool. It is a portfolio-management product called
Pinnakl. A typed id does not fail, it returns a different company, and nothing
in the output tells you that happened. Copying the URL from the page you are
actually looking at removes the whole class of mistake.

`capterra.com` and the country domains such as `capterra.co.uk` are both
accepted, and query strings are ignored.

### The mistake this was built around

A Capterra product page does not only describe its product. It also carries the
alternatives Capterra recommends alongside it: up to eight products and three
separate rating blocks on a single page.

An early version of this scraper took the richest block on the page and
**returned Slack's ratings under Notion's name**. The row looked perfect. It had
a plausible score, a large review count, a name, a price. Nothing about it
suggested it was describing a different company.

So every field is read from the block that matches the product id in the URL you
supplied, and every neighbouring block is ignored. If the page carries no block
for the id you asked for, you get an error naming that product rather than a row
that quietly belongs to somebody else.

One field was dropped for the same reason instead of shipped. The page carries
what reads as a sentiment split, and it is tempting: a clean positive and
negative percentage, right there. Measured across six products with ratings from
4.19 to 4.72, it read **85/15 every single time**. It is part of the page
furniture rather than a measurement of anything, so publishing it would have
handed six different products the same confident, meaningless number. It is not
in the output.

The ratings come from a block that carries no name of its own, so it is only
used once it has been tied to the product you asked for. The structured data at
the top of every page states which product the page describes, and its review
count is an exact integer; the block is accepted only when the two agree. On a
disagreement the rating fields come back empty rather than borrowed.

The alternatives are worth seeing to understand why that matters. They are not
just different numbers, they are incoherent ones: monday.com appears on Slack's
page with 11,125 ease-of-use reviews and on Notion's page with 22,418, against
the same 6,103 total in both. Reading the nearest block gets you a confident
figure that belongs to another company and does not even hold together.

### Numbers as the site means them

`recommend_percent` is published as a fraction, `0.9024`. Left alone in a column
headed "recommend", that invites being read as nine out of ten. It is returned as
`90.2`, the percentage the site itself displays.

Ratings are published to fourteen decimal places (`4.66390427378689`) and are
rounded to two. Prices arrive with a doubled currency glyph (`$$15`) which is
collapsed to `$15`. A vendor that publishes no price gets an empty
`starting_price`, never a zero, because a zero in a price column means free.

### Run summary

Every run writes a summary record: products requested and returned, how many
carried a rating and a price, how many offer a free trial, the total number of
reviews the run covers, and how many pages did not come through.

That last count is the one to watch. It is not a failure of the product id and
not an empty result, it is a page worth requesting again. Raising **Attempts per
product** is the fix; three is usually enough, and across nineteen products in
testing the count was zero.

### What people use this for

**Competitive tracking.** Run a set of competitors on a schedule and keep the
rows. Rating movement is slow and mostly noise, but review counts and published
prices change in ways that are worth knowing about the week they happen.

**Pricing research.** `starting_price` together with `pricing_model` and
`payment_frequency` is the comparable form of a number that every vendor
presents differently on its own site.

**Category landscape.** Feed in every product in a category and you have the
whole field in one table: who has volume behind their score, who has a free
tier, who publishes a price at all.

**Vendor due diligence.** The gap between a product's ease-of-use score and its
customer-support score, weighted by how many reviews sit behind each, tells you
more about what buying it feels like than the headline rating does.

### Scale and cost

Each product is one request. Eight products took **19 seconds** end to end in
testing, and the Actor runs in 256 MB because there is no browser involved. Set
**Maximum products** to cap a run: it is applied after duplicate URLs are
removed, so it is a real ceiling on both time and cost.

A product that cannot be read never becomes a silently missing row. It becomes
an entry in the errors record with a code and a message naming the URL, so a
run of fifty tells you exactly which two need another attempt.

# Actor input Schema

## `products` (type: `array`):

Paste the address of each Capterra product page, one per line, for example https://www.capterra.com/p/135003/Slack/. Bare id numbers are deliberately not accepted: Capterra ids are not guessable, so a typo would quietly return a different product rather than an error.

## `max_products` (type: `integer`):

Stop after this many products, counted after duplicate URLs are removed. Each product is one rendered page, so this is also the cost ceiling for the run.

## `retries` (type: `integer`):

How often to re-render a product page that came back challenged. The check is intermittent rather than permanent, so a second or third attempt usually succeeds; raise this if a run reports challenged pages.

## Actor input object example

```json
{
  "products": [
    "https://www.capterra.com/p/168956/Canva/"
  ],
  "max_products": 25,
  "retries": 3
}
```

# Actor output Schema

## `products` (type: `string`):

One row per product profile.

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

Products requested and returned, how many carried a rating and a price, total reviews covered, and how many pages were challenged.

## `errors` (type: `string`):

Products that could not be read, with a code and a redacted message.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "products": [
        "https://www.capterra.com/p/135003/Slack/",
        "https://www.capterra.com/p/186596/Notion/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/capterra-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 = { "products": [
        "https://www.capterra.com/p/135003/Slack/",
        "https://www.capterra.com/p/186596/Notion/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("s-r/capterra-scraper").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 '{
  "products": [
    "https://www.capterra.com/p/135003/Slack/",
    "https://www.capterra.com/p/186596/Notion/"
  ]
}' |
apify call s-r/capterra-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/capterra-scraper"
        }
    }
}
```

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/yTCPvFjRgBmXVL602/builds/icnoLccIAUGyqu5Xv/openapi.json
