Scrapers

G2 reviews

The G2 scraper targets product, reviews, and category pages on g2.com. It uses an anti-fingerprint Firefox engine to defeat DataDome, parses the JSON-LD that G2 emits per product, then paginates reviews. One dataset row per product, one per review.

Updated today

Overview

At a glance
Worker
ultron-g2-reviews
Runtime
Python, anti-fingerprint Firefox engine, headless by default
Targets
g2.com product, reviews, category pages
Proxy
Residential US (mandatory)
Defaults
25 reviews per product, 4000 ms per request
Webhook target
scraper-webhook.51ultron.com/apify

G2 is the dominant B2B SaaS review source. Pulled by competitive teardown skills, by buyer-intent enrichment, and by the discovery aggregator when a workspace lists a vendor in its brain. Output shape matches the Capterra reviews scraper so the two can be merged on product identity.

Input schema

One required field, three knobs.

.actor/INPUT_SCHEMA.jsonjson
1{
2 "productSlugs": ["hubspot-marketing-hub", "linear", "notion"], // required
3 "maxReviewsPerProduct": 25, // 1 to 500
4 "headless": true,
5 "proxyConfiguration": {
6 "useApifyProxy": true,
7 "apifyProxyGroups": ["RESIDENTIAL"],
8 "apifyProxyCountry": "US"
9 },
10 "requestDelayMs": 4000 // 1000 to 30000, +50% jitter
11}

Crawl flow

Three URL patterns per slug.

src/__main__.pypy
1# Per productSlug:
2# product_url = f"https://g2.com/products/{slug}"
3# reviews_url = f"https://g2.com/products/{slug}/reviews"
4#
5# 1. Open product_url. Parse JSON-LD aggregateRating, reviewCount,
6# description, vendor, screenshots. Push kind="product".
7# 2. Open reviews_url. Parse first page's review cards into kind="review" rows.
8# 3. Paginate /reviews?page=N until maxReviewsPerProduct or no more cards.
9# 4. Sleep requestDelayMs + 50% jitter between every page load.
10# 5. Push category links observed on the product page as kind="category" rows
11# for downstream discovery.

Output shape

Discriminated union by kind.

dataset-row.jsonjson
1// kind === "product"
2{
3 "kind": "product",
4 "productSlug": "linear",
5 "productName": "Linear",
6 "vendor": "Linear Orbit, Inc.",
7 "rating": 4.7,
8 "reviewCount": 1842,
9 "categories": ["Project Management", "Bug Tracking"],
10 "scrapedAt": "2026-05-19T12:00:00Z"
11}
12
13// kind === "review"
14{
15 "kind": "review",
16 "productSlug": "linear",
17 "reviewId": "review-184782",
18 "rating": 5,
19 "title": "Fastest issue tracker we have used",
20 "body": "Linear is genuinely the first PM tool that...",
21 "likeBest": "Keyboard-first navigation",
22 "dislike": "Mobile app trails the desktop",
23 "useCase": "Engineering ops",
24 "reviewerRole": "Engineering Manager",
25 "industry": "Computer Software",
26 "publishedAt": "2026-04-12T00:00:00Z"
27}
28
29// kind === "category"
30{
31 "kind": "category",
32 "productSlug": "linear",
33 "categoryName": "Project Management",
34 "categoryUrl": "https://g2.com/categories/project-management"
35}

Anti-bot strategy

DataDome is the primary defense. Datacenter IPs hit it instantly.

DefenseCounter
DataDome JS challengeAnti-fingerprint Firefox runtime carries enough DOM signal to clear the challenge first try.
IP rotation defenseResidential US proxy. Empirically the only stable choice.
Rate limit per IP4000 ms minimum, jitter prevents pattern detection.
Soft 429 with empty bodyTreated as the abort signal. The actor aborts at the per-IP threshold rather than burning more attempts.

Webhook contract

Same shape as every other scraper in the fleet.

actor.json (webhook block)json
1{
2 "eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED", "ACTOR.RUN.TIMED_OUT", "ACTOR.RUN.ABORTED"],
3 "requestUrl": "https://scraper-webhook.51ultron.com/apify",
4 "payload": {
5 "actorName": "g2-reviews",
6 "source": "g2",
7 "datasetId": "<dataset-id>",
8 "status": "SUCCEEDED|FAILED|TIMED_OUT|ABORTED"
9 }
10}

How to trigger it

From chat: the user names a vendor or a competitive set. The reviews-capture skill resolves to G2 slugs via a small lookup table and fires a single run.

From the discovery aggregator: the worker checks for new reviews against the workspace's competitor list daily and posts diffs to the brain.

File map

actors/g2-reviews
.actor
actor.jsonmanifest + webhook config
INPUT_SCHEMA.jsonfour-field input
src
__main__.pyentry, product + review + category parsers
Dockerfile
requirements.txt
README.md