Get clean Tripadvisor review data for research. This actor collects comments, star ratings, reviewer details, timestamps, and listing info. Ideal for hospitality insights, market evaluation, and customer experience analysis.
Fixed — actor was returning 0 reviews on every run (DataDome TLS fingerprint block)
Root cause:src/helper.py hardcoded IMPERSONATE = 'safari17_0' for every
curl_cffi request (the initial hotel/restaurant/attraction page fetch, the JS
bundle download, and every GraphQL POST). Live testing on 2026-08-30 showed
TripAdvisor's DataDome protection now fingerprints and blocks that specific
TLS/JA3 impersonation profile: 6 separate attempts against a real Hotel_Review
page, each through a fresh residential-proxy IP (via Apify Proxy, group
RESIDENTIAL), all returned HTTP 403 with a captcha-delivery.com DataDome
interstitial body (778 bytes) — 100% block rate, independent of IP. This is
consistent with safari17_0 having become a widely-fingerprinted signature
(popular curl_cffi impersonation profiles get identified and blocklisted by
anti-bot vendors over time as more scrapers adopt them).
Investigation: swept every Chrome/Firefox/Edge/Safari impersonation
profile available in curl_cffi 0.14 against the same URL through fresh
residential-proxy sessions. chrome*, firefox133, edge101, safari15_3,
safari155, safari17_0, safari18_0, and safari180 were all 403'd on
every attempt. safari184 (Safari 18.4) passed with a real ~1MB page body on
3/3 attempts, and was reconfirmed on a second, independent 3-run sweep
(3/3 again). safari260 was flaky (2/3). safari184 was the only profile
that passed reliably.
Fix:src/helper.py — IMPERSONATE changed from 'safari17_0' to
'safari184'. This single constant is imported by src/main.py and used for
every outbound curl_cffi request (page fetch, bundle download, GraphQL
POST), so no other call sites needed changes.
Verification: ran the actor's full bootstrap → GraphQL → transform
pipeline locally against
https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html
through a real Apify residential-proxy session with IMPERSONATE = 'safari184':
page fetch succeeded (200, ~1MB body with the JS bundle + JSON-LD), the
persisted GraphQL query ID was extracted live from the bundle
(ef3cb4f569f27e43), the review-list GraphQL call returned 200 with a real
total count (7,979 reviews) and 10 real review rows, and transform_review()
produced a fully populated row (real review text, rating, subratings, owner
response, and hotel metadata). Confirmed clean on the live Apify platform via
apify call after push (see build/run details in the deployment record).
Also updated
FALLBACK_REVIEW_QUERY_ID (used only if the live bundle-walk parser fails
after a future TripAdvisor frontend deploy) refreshed to the ID harvested
during this session's live verification (ef3cb4f569f27e43), replacing the
stale 2026-08-19 value. This is a last-resort fallback only — the real fix
for query-ID rot is the live bundle walk in extract_query_ids(), which is
unchanged and still works correctly.
Docstring comments in src/helper.py and src/main.py referencing the old
safari17_0 profile updated to describe the current safari184 profile and
the live evidence for the switch, so a future maintainer knows to re-run the
same impersonation-profile sweep first if this breaks again (rather than
assuming the GraphQL schema or selectors changed).
[0.1] - prior
Initial version (persisted-GraphQL-query hotel/restaurant/attraction review
scraper with photo/visual-content filters, live bundle-walk query-ID
discovery, JSON-LD + DOM metadata parsing).