# Changelog of Threads Scraper — Posts, Profiles, Engagement (`sleek_waveform/threads-scraper`) Actor

- **URL**: https://apify.com/sleek\_waveform/threads-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/sleek\_waveform/threads-scraper.md

## Changelog

All notable changes to this project will be documented in this file.

### \[1.0.3] - 2026-07-12

#### Performance

- **Parallel Cheerio probes for search/hashtag:** When customers run multiple search or hashtag queries with `maxConcurrency=1` (common in automation), Cheerio now probes up to 5 URLs in parallel instead of serializing them. Typical 3-query automation runs finish in ~8–15s instead of ~25s, delivering more posts before scheduled aborts.
- **Deadline-aware Playwright skip:** If fewer than 30s remain in the run budget after Cheerio, the actor skips the Playwright handoff instead of starting a browser session that cannot finish — avoids wasted startup time on short automation windows.

#### Added

- Regression tests for `resolveCheerioMaxConcurrency` and `shouldSkipPlaywrightHandoff` (`tests/run-scheduling.test.ts`).

### \[1.0.2] - 2026-06-10

#### Performance

- Crawlee's initial Playwright navigation now resolves on `commit` (response started) instead of waiting for the `load` event, which Threads' streaming pages frequently delay past the 30 s navigation timeout. Removes up to ~28 s of dead wait per request and fixes search-mode navigation, which lost that 30 s race almost every attempt (`Navigation timed out after 30 seconds`).
- Batched dataset writes and pay-per-event charging: one `pushData` + one `charge({ count })` call per scroll iteration / Cheerio payload instead of two API round-trips per post. Large jobs no longer serialize per-item HTTP latency inside the handler time budget.
- `deepScroll` now waits for the lazy-load GraphQL XHR itself (armed before scrolling) instead of a `networkidle` timeout that always burned its full 3 s per iteration — typical scroll cycle drops from ~4.4 s to ~2 s.
- Profile-header hydration waits tightened (15 s + 15 s worst case → 5 s + 8 s); they still early-exit the moment the header renders, and `postsCount` fallbacks are unchanged.
- Scroll loops now stop when the run's `maxTotalChargeUsd` limit is reached instead of continuing to scrape unbillable items.

#### Fixed

- (2026-06-09) Apify Store QA `TIMED_OUT`: raised default run memory to 2048 MB (QA validates at `defaultMemoryMbytes`, where 1024 MB memory-starved Chrome to concurrency 1) and disabled request retries on short (≤ 10 min) run windows so a retry chain cannot overshoot the wind-down deadline.

### \[1.0.1] - 2026-04-25

#### Fixed

- Added prefill values for `usernames` (`["zuck"]`) and `maxItems` (`5`) so Apify's automated quality assurance test can run the default `profile` mode and produce a non-empty dataset within the 5-minute window. Empty prefills caused input validation to throw, which flagged the Actor as "Under maintenance".

### \[1.0.0] - 2026-04-21

#### Added

- Initial release of Threads Scraper Actor.
- Five scrape modes: profile, posts, hashtag, post\_urls, search.
- Hybrid CheerioCrawler / PlaywrightCrawler architecture with automatic fallback.
- GraphQL response interception for structured data extraction.
- Engagement metrics: rate, velocity, virality score, like-to-follower ratio.
- Anti-detection scripts: stealth Chrome args, canvas fingerprinting, automation flag removal.
- Rate limit handling with exponential backoff and jitter.
- Dataset views for Profiles and Posts tabs.
- Input schema with proxy configuration, request delays, and concurrency controls.
- Unit tests for extractors, metrics, and utilities.
- ESLint and Prettier configuration for code quality.
- Comprehensive README with SEO-optimized headings and usage examples.
