Final coverage check after all parity features: 400 comments from the HONY post in 40 pages, 400 unique ids, 0 duplicates, no throttles.
Comment-id set is identical to the 2026-09-30 baseline: 400 of 400 overlap (Jaccard 100%) — the new sort handling, dedupe plumbing, reaction breakdown, URL extraction, post text and surface detection did not drop a single row.
Field coverage on those 400 rows: post_text 400/400, author_name 400/400, created_at 400/400, reactions_breakdown 163 (exactly where reactions exist), extracted_urls 1.
0.0.23 (surface matrix + post text 2026-10-01)
includePostText — the post caption is copied into every comment row as post_text, parsed from the permalink HTML the run already fetches (no extra requests). Verified: 10 of 10 rows carried the decoded caption, including \u201c escapes.
Verified the input surface matrix in one run: page posts, group permalinks, story.php and /videos/ work; Reels, photo pages and /watch/?v= pages render but serve an empty comment list to logged-out visitors — the same reason crawlerbros documents Reels as login-only.
Such runs are now marked blocked: comment_list_not_served_without_login with a warning naming the surface, instead of returning a silent zero.
Added surfaceOfUrl() (URL classifier) with tests; docs list supported vs unsupported surfaces.
The permalink GET now sends browser-like navigation headers (Accept: text/html..., Sec-Fetch-Dest: document, Sec-Fetch-Mode: navigate). Without them Facebook returned a reduced HTML variant (475 KB vs 788 KB on the same URL), missing the embedded comment payload.
SUMMARY now reports announcedComments — how many comments the post advertises — so coverage is visible before walking pages. Verified: 3215 announced on the HONY post.
On some legacy story.php links the datacenter proxy still receives the reduced page, so the count is absent there while the comment walk itself continues to work.
0.0.21 (competitor parity features 2026-10-01)
commentsSortOrder enum (MOST_RELEVANT / NEWEST / ALL_COMMENTS) picks the Facebook ordering explicitly; unionSorts still works. Verified in cloud: ALL_COMMENTS walks the RANKED_UNFILTERED_CHRONOLOGICAL_REPLIES_INTENT_V1 window.
Output now carries reactions_breakdown (per-type like/love/haha/wow/sad/angry/care) and extracted_urls (links found in the comment text). First cloud run: 48 of 50 rows had a breakdown, one comment shipped an Amazon link.
Incremental monitoring: dedupeStoreName persists delivered comment IDs in a named key-value store between runs; knownCommentIds and knownDatasetId also accepted. Verified: run 1 saved 20 ids, run 2 skipped all 20 and pushed 0 rows (skippedKnown: 20).
failOnEmpty marks the run as failed when nothing was collected, so scheduled runs cannot fail silently.
Note: reading another run's dataset needs permission; the actor logs a clear warning and recommends dedupeStoreName or knownCommentIds instead.
Tests 30/30, npm run check clean.
0.0.20 (auto proxy tier 2026-09-30)
proxyTier input: auto (default) starts on Apify's datacenter pool and switches to residential the moment Facebook blocks it, so success rate is preserved.
Measured on the comments actor: 400 public comments for $0.01097 on datacenter vs $0.04471 on residential; a group permalink walk of 74 comments for $0.00426. Group and public walks both served by datacenter in dedicated runs.
On a mixed 3-post parallel run Facebook blocked the first datacenter permalink (HTTP 400, 1542 bytes), the fallback fired automatically and the run still delivered 274 comments for $0.0219 ($0.080 per 1000).
Per 1000 comments: $0.027-0.058 when datacenter holds, $0.08-0.12 with residential fallback. Market range for comment actors is $0.40-6.80.
Tests 28/28, npm run check clean.
0.0.19 (bulk mode + date filter + storefront 2026-09-30)
Parallel post processing: maxConcurrency 1-20 (default 5). Measured two posts x100 comments in 21.5 s vs 45.7 s sequential, no duplicates, no throttles.
maxPostsPerRun raised 10 -> 100; duplicate URLs are dropped before the walks start.
onlyCommentsNewerThan accepts 2026-04-20, 30 days, 12 hours, 2 weeks; a post stops after two pages without matching comments.
proxyCountry / proxyGroups inputs instead of the hardcoded RESIDENTIAL/US.
Race fix: comment keys are reserved before pushData, so parallel workers can no longer double-push the same comment id.
README rewritten (7.8k chars): features, inputs, output fields, mechanics, honest group limits, measured cost table, FAQ, migration table. Previously the actor card had no readme at all.
Tests 28/28, npm run check clean.
0.0.18 (cookieless depth + fast pacing 2026-09-30)
Rewrote the walk: live CLCPQ (doc 38580553541588665) with cursor paging, reply Depth1 walk (39246134745000506) to the end of each thread, configurable pacing.
feedLocation is now always POST_PERMALINK_DIALOG. Verified: on a group GROUP_PERMALINK returns 3/page, the dialog surface returns 10 on the same post and cursor.
pfbid/share URLs resolve their numeric post id from the page HTML (base64 feedback:<id>), so opaque links no longer return zero rows.
Reply headroom: the top-level walk reserves space so replies still run; the old code filled the cap and never expanded a single thread.
Union sorts (null + RECENT_ACTIVITY_INTENT_V1) with a duplicate-page guard so a second walk of the same window stops after two dry pages.
Cloud measurements (1024 MB, residential US, no cookies): 200 comments = 47 s / $0.0234 at a 200 ms page delay vs 115 s / $0.0386 at 2000 ms. 400 comments = 91 s / $0.0447. Replies: 199 rows (110 top + 73 replies + 16 sub-replies) = $0.0141. Old build: $4.39-5.14 per 1000 comments, new build: $0.11-0.17 per 1000.
Groups stay capped by Facebook at 71-79 of 175 announced comments for logged-out sessions; that tail needs cookies.
Cloud: FRESH_LIST 10/4pp CU 0.24 clean; WITH_REPLIES 14/5pp CU 0.28, window moves past 10 (11-14 new bodies) but replyExpansions=0 — top ate the whole cap.
Third battle hit a silent throttle loop (RUNNING 16+ min, CU 1.06+, no log past Post 1/1) — aborted to save budget. Lesson: 1 battle/hour per IP, 60+ min cooldown, or the server silently hangs up.
0.0.16 (live-template triple 2026-09-29)
Local Playwright intercept on R60 caught the live browser triple: CLCPQ 38580553541588665 + Depth1 39246134745000506 + Depth2 28907335732287199 (9 requests, GROUP_PERMALINK).
Fresh vars rebuilt to the full browser shape: count -1 (server picks), null intent/cursors on page 1, scale 1, four relay-provider flags, GROUP_PERMALINK on group URLs. Depth1 id = base64 feedback:POST_parent, Depth2 id = base64 feedback:POST_comment, null-first then -1+cursor paging.
Stale Go-2026-07 docs retired. Tests 26/26 green (live-template doc + builder shape), npm run check clean. Legacy default untouched.
Next: single cheap cloud battle 1x10 FRESH_LIST on R60 to see if the live template cracks the top-10 window.