Disclosure: I'm Ben, and I built the Apify Actor mentioned at the end. I charge per review for it. The how-it-works part applies whatever tool you use.
I wanted competitor reviews in a spreadsheet: star rating, the four sub-scores, pros, cons, the reviewer's job title, and the date. Capterra has all of that on public pages, but getting it out cleanly took a few tries. Here's what I found.
The reviews are in the Next.js page data
Capterra's review pages (/p/<id>/<Product>/reviews/) are a Next.js app. You don't have to parse the layout. The page ships its data in self.__next_f.push([...]) script calls, and if you join the string parts you get the React Server Components payload. Search it for "hybridReviewPage":[ and bracket-match the array. Each of the 25 entries looks roughly like this:
{ "kind": "primary", "publishedAt": "2026-11-02T05:27:06Z", "value": { "title": "...", "overallRating": 5, "ratingDetails": { "easeOfUse": 5, "functionality": 5, "qualityOfSupport": null, "valueForMoney": null, "recommendation": 9 }, "pros": "...", "cons": "...", "generalComments": "...", "reviewer": { "fullName": "Hannah M.", "jobTitle": "Creative arts coordinator", "timeUsedProduct": "3-5 years" } } } Next to it there's a reviewSummary object with the product's overall rating, total review count and the four average sub-scores. For Slack on Nov 2, 2026 that was 4.7 overall from 24,177 reviews.
Ask for the data, not the page
Once you have a browser session, you can request the next page with the header RSC: 1 and Next.js sends back just the server components payload instead of the full HTML. For a Slack reviews page that came to about 217 KB of data. When you pay for residential proxy by the GB, skipping the HTML, scripts and images around it adds up fast.
const r = await fetch(`${url}?page=${n}`, { credentials: 'include', headers: { RSC: '1' } }); const payload = await r.text(); // same "hybridReviewPage" array, no HTML around it Cloudflare
A plain request from a server gets Cloudflare's "Just a moment..." page with a 403. What worked:
- A stealth-patched Firefox via Playwright on a US residential proxy.
- Open the first reviews page and wait until the title is the real page title. Careful: while the check runs, the title can be "Loading https://www.capterra.com/...", which contains "capterra". My first version matched on that, thought it was through, and every fetch after it failed.
- After that, fetch the other pages from inside the same tab with
RSC: 1, one at a time with a short gap. - Block images, fonts, ads and trackers, but let Cloudflare's own challenge files through.
- If the check doesn't clear, throw the session away and start again with a new IP.
The 375-review wall
This one surprised me. ?page=N works, but only up to page 15. Page 16 comes back with an empty review list, even for Slack with its 24,177 reviews. And if you ask for a page way past the end, like ?page=99999, you get page 1 again, so check for repeated review IDs or you'll loop.
So a logged-out visitor sees 15 pages of 25, which is 375 reviews per product in Capterra's default order. Most products have fewer than that, so you get everything. For the big ones you get the first 375. I didn't try to get around it, and I stay out of /search and the sort parameters, which Capterra's robots.txt disallows.
Real numbers
From my test runs on Nov 2, 2026:
- 50 Slack reviews (2 pages): about $0.056 in platform cost, most of it the browser start and the Cloudflare check.
- All 15 pages of Discord (375 reviews scanned) with a 2-star filter: about $0.031 in total, under 48 seconds.
- Filtering helps: in those 375 Discord reviews, 7 had 2 stars or fewer and 5 had 1 star.
If you don't want to build it
I packaged this as an Apify Actor: Capterra Reviews Scraper. Paste product URLs, optionally set a star range or a "reviewed after" date, and download JSON, CSV or Excel. It's $1 per 1,000 reviews plus a $0.005 start fee per run, proxy included. Reviews your filters drop aren't charged.
If Capterra changes something and it breaks, open an issue on the Actor page and I'll take a look.


