# Changelog of X (Twitter) Profile Scraper — Accounts, Activity & Growth (`foxlabs/x-profile-scraper`) Actor

- **URL**: https://apify.com/foxlabs/x-profile-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/foxlabs/x-profile-scraper.md

## Changelog

### 0.1 — 2026-10-19 — first release

- Reads X's own embed (syndication) backend: no login, no API key, no browser. Accounts can be named by handle, profile address or numeric id, mixed in one list.
- One row per account with the 38 fields X states on it: name, bio, location, website, followers, following, posts, likes given, listed count, media count, verification and its type, protected and default-image flags, profile and banner images, join date — plus **account age**, **posts per day over its lifetime** and the **followers-to-following ratio**.
- **Activity figures from the same single read** (`includeActivity`, on by default): posts on the embedded page, the days that page spans, days since the last post, posts per day on the page, posts in the last 7 and 30 days, total, average, median and highest engagement, engagement per 1,000 followers, the top post with its link and text, the languages it posts in, the share of posts with media, links, hashtags and replies, and the accounts it mentions most. X states none of these.
- **Growth between runs** (`trackGrowth`, on by default): the counts last seen per account are kept in a key-value store of your own account, so every later run states the follower change, the change per day, the percentage change, the posts added and the days since the previous read. An account read for the first time says so instead of writing zeros.
- Filters applied before a row is charged: minimum followers, verified only, posted within N days, and a cap for the whole run.
- Handle → numeric id is remembered between runs (`x-account-ids`, the same store the X Account Monitor uses), because X rate-limits handle lookups from datacenter addresses while answering id reads freely.
- Free status rows for every line that cannot be delivered: not an X account, no public record on X, an account the run could not read, or an account an earlier line of the same input had already named. Nothing is charged for them.
- States the source's limits in the run message and in `SOURCE_REPORT`: the activity figures come from one embedded page (20–105 posts, measured 2026-10-19), not from the account's history; follower lists are not available; X states no e-mail address on an account.
- Found in the local verification run and fixed before the first build: an account named twice in one list (once by handle, once by its id) was delivered — and charged — twice, and its "change since the last run" was measured against the same run. Such a line is now a free status row and the account is delivered once.
- Found while verifying the duplicate-line fix: a line that named an account by its numeric id taught the store nothing, so a later line naming the same account by its handle still spent a residential lookup. Every successful read now teaches the handle → id pair the page states, whichever way the line named the account.
- Found on the platform in the first verification runs (invisible locally, where every store opens): a run is refused a named key-value store that **another** Actor created, and the whole run died over it. Two fixes: this Actor's handle cache is now its own store (`x-profile-account-ids`), and a store that cannot be opened is a warning in the log and in the run message, not a failed run — the rows are delivered and the growth columns say "first read".
- Found on the platform (invisible locally, where no proxy pool is involved): ten accounts read eight at a time met fifteen HTTP 429s from X and five of them came back as failed lines, while the same ten read three at a time delivered all ten. Two fixes: the default speed is now three accounts at a time (maximum ten), and an account X rate-limits in the first pass is read again at the end, one at a time, so a refused line is recovered instead of lost. The run message says when the second pass was needed.
- The recovery pass now makes two rounds, after 3 and 8 seconds. Measured on the platform: X's rate budget is shared across everything your account is reading from it at that moment, so a single retry a second and a half later is refused again while another run is in flight; the same run on its own recovered all ten accounts.
