How to Scrape G2 Reviews in 2026 (Python + a No-Code Shortcut)
What a G2 Review Actually Contains
One G2 review holds more than it looks. Per review you can pull:
- Overall rating (1 to 5) plus six sub-ratings (ease of use, ease of setup, quality of support, meets requirements, and more)
- Structured pros, cons, and "problems solved" as separate fields, not one text blob
- Switching data: the competitor the reviewer came from, and why they left (the field most people are actually after)
- Reviewer context: industry, role, company size, country
- Dates, verification, and the incentivized flag
The sub-ratings and switching fields are the reason to scrape G2 instead of skimming it by hand.
Why Scraping G2 Is Hard: DataDome
G2 runs DataDome bot protection behind a Cloudflare CDN. In practice:
- A plain
requestsorhttpxGET comes back403almost immediately. - Swapping the User-Agent does nothing. DataDome fingerprints TLS, headers, and behavior.
- Datacenter IPs get flagged fast. You need residential proxies plus a real browser fingerprint, or a scraping API that brings both.
You can absolutely scrape G2 yourself. The hard part is doing it reliably, at scale, without babysitting proxies. That maintenance tax is bigger than the parsing.
Three Ways to Get G2 Review Data
| DIY Python | G2 Reviews Scraper (actor) | G2 Official API | |
|---|---|---|---|
| Setup time | Hours to days | ~30 seconds | Weeks (sales + contract) |
| Anti-bot handled | You (proxies + browser) | Built in | n/a |
| Structured fields | You parse them | 27, incl. switching data | Limited |
| Sub-ratings + "switched from" | Hard to parse | Yes, resolved to product names | No |
| Cost | Proxies + eng time | $0.004/row, ~1,250 free | Enterprise contract |
| Best for | One-off, few pages | Scheduled, at scale | Large enterprises |
Option A: DIY in Python
See the wall for yourself first:
import httpx
url = "https://www.g2.com/products/slack/reviews"
r = httpx.get(url, headers={"User-Agent": "Mozilla/5.0"})
print(r.status_code) # 403 (DataDome)
Getting past it needs a residential proxy and a browser-grade fingerprint (a stealth headless browser, or a scraping API). Once you have the HTML, parsing review cards with BeautifulSoup looks roughly like this:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
for card in soup.select("[itemprop='review']"):
rating = card.select_one("[itemprop='ratingValue']")
title = card.select_one("[itemprop='name']")
body = card.select_one("[itemprop='reviewBody']")
print(
rating.get("content") if rating else None,
title.get_text(strip=True) if title else None,
(body.get_text(strip=True) if body else "")[:120],
)
Two things that will cost you time:
- Selectors drift. G2 changes its markup, so re-check against the live page.
- Sub-ratings and switching data sit in nested markup that is fiddly to parse consistently.
DIY is fine for a one-off across a handful of pages. For hundreds of products on a schedule, the proxy and anti-bot upkeep usually costs more than it saves.
Option B: The No-Code / API Shortcut
When you just want clean rows, the G2 Reviews Scraper on Apify handles the DataDome, proxy, and parsing layer and hands back structured JSON. No login, no proxy setup.
From Python, using the Apify client:
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("factden/g2-reviews-scraper").call(run_input={
"mode": "reviews",
"startUrls": ["https://www.g2.com/products/slack/reviews", "notion"],
"maxReviewsPerProduct": 200,
"sortReviews": "helpful",
})
for review in client.dataset(run["defaultDatasetId"]).iterate_items():
print(review["overallRating"], review["reviewTitle"], review.get("previousCompetitors"))
Pass full product URLs or bare slugs (notion, slack). There is also a Products mode that finds competitor products by keyword before you pull their reviews.
What Comes Back: 27 Structured Fields
| Group | Fields |
|---|---|
| Ratings | overallRating, subRatings (ease of use, setup, support, meets requirements) |
| Structured text | pros, cons, problemsSolved, recommendations, reviewText |
| Switching / battlecard | didSwitchFromCompetitor, previousCompetitors, whySwitched |
| Reviewer | reviewerIndustry, reviewerRole, companySize, reviewerCountry, reviewerName |
| Meta | isIncentivized, helpfulVotes, submittedAt, reviewUrl, productSlug, productName |
| AI-ready | markdownContent (a self-contained markdown block per review, for RAG / vector DBs) |
A trimmed sample row, so you can see the shape:
{
"productName": "Slack",
"overallRating": 5,
"subRatings": {
"easeOfUse": 6,
"easeOfSetup": 6,
"qualityOfSupport": 5,
"meetsRequirements": 6
},
"reviewTitle": "Runs our whole company",
"pros": "Channels keep every project in one place.",
"cons": "Notifications get noisy at scale.",
"didSwitchFromCompetitor": true,
"previousCompetitors": ["Microsoft Teams"],
"whySwitched": "Better threads and a faster mobile app.",
"companySize": "Mid-Market",
"reviewerRole": "IT Administrator",
"isIncentivized": false
}
The two fields most scrapers drop - previousCompetitors + whySwitched (resolved to real product names) and the per-dimension subRatings - are what make this useful for battlecards. Full field list and copy-paste snippets are in the GitHub repo.
Grab a Free Sample Dataset
Want to see the data before running anything? There is a free G2 review sample (CSV/JSON) here: factden.com/sample (also mirrored on HuggingFace and Kaggle). Load it into pandas and the sub-ratings and switching fields show up straight away.
FAQ
Is scraping G2 reviews legal?
The reviews are publicly available. As with any scraping, check G2's Terms of Service and your local rules (GDPR and similar for personal data), and use the data responsibly.
Does G2 have an API?
Yes, but it is enterprise-tier: a sales call, a contract, and procurement. For most teams, scraping the public pages, or using a ready-made actor, is the faster route to the same public data.
How do I stop getting blocked?
Residential proxies, a real browser fingerprint, and human-like pacing, or a tool that bundles all three. Datacenter IPs and plain requests will not survive DataDome.
How much does it cost?
DIY costs proxies plus your time. The actor is pay-per-result at $0.004 per row, with about 1,250 rows free on Apify's $5 new-account credit.
Can I get the "switched from" competitor data?
Yes. That is the previousCompetitors and whySwitched fields, resolved to product names. It is the reason most people scrape G2 in the first place.
Can I filter out incentivized (gift-card) reviews?
Yes. Every row carries an isIncentivized flag, so you can recompute a rating on organic reviews only. G2's own UI will not let you do that.
Related
I mapped switching and sub-ratings across 25 tools in the 2026 SaaS Battlecard Atlas (50,000 reviews). Other FactDen scrapers: Indeed jobs and salary data and Trip.com and Ctrip hotel reviews. Questions, or a field you wish it extracted? Drop a comment.
Comments
No comments yet. Start the discussion.