# Changelog of Website Email Extractor for Google Maps Leads & Domain Lists (`tidytools/website-contact-extractor`) Actor

- **URL**: https://apify.com/tidytools/website-contact-extractor/changelog.md
- **Full Actor documentation**: https://apify.com/tidytools/website-contact-extractor.md

## Changelog

### 2026-11-02

- Free `errorType: "network"` rows now say whether another run is worth it: a new `networkFailure` field (`dns_not_found`, `dns_temporary`, `timeout`, `tls`, `connection_reset`, `other`) and matching advice in `error`. Only a domain that public DNS confirms has no address is called gone. A DNS failure public DNS does not confirm is no longer final: it has `retryable: true` and is in `RETRY`. `errorType` values, charges and success rows are unchanged.

### 2026-10-27

- PDF links (exhibitor directories, member lists, catalogs) can be pasted with the websites: a link ending in `.pdf`, or a given page that answers with a PDF, is read as a document (text layer; scanned pages by OCR, `maxPdfOcrPages`, default 3). Its row has the usual contact columns plus `sourceType: "pdf"`, `pdfPage` and page counts; every website row now has `sourceType: "website"`. A PDF is charged like one website (`site-processed`, only when a contact is found); encrypted, over-15 MB, unreadable and contact-free PDFs are free. No new event, prices unchanged. `SUMMARY.processed`, `charged` and `failed` include PDFs, `SUMMARY.pdfs` has their own counts, and `SUMMARY.websites` and `SUMMARY.enrichment.websites*` stay websites only.
- PDF emails are also read from the PDF's `mailto:` links, and addresses the converted text breaks over two lines are joined again: an exhibitor list whose text gave 9 of its 21 addresses now gives all 21. Charges unchanged (one PDF is still one `site-processed` event).
- PDF fixes: an address printed on its own is kept even when a linked address on the same domain ends with it (`support@` beside `techsupport@`); compressed link data is read up to 2 MiB per stream and 8 MiB per PDF, past that the text-layer addresses are used. Charges unchanged.
- A PDF whose text conversion fails for now (backend timeout) and whose pages OCR does not all cover is a free failed row (`errorType: "pdf_convert_failed"`, run it again) instead of a free "no contact" row read from its first pages only; the conversion is tried in shorter attempts within the same total time. Charges unchanged.

### 2026-10-25

- Every website read gets a free `leadScore` (0–100) and `scoreReasons`. Without input it reflects how complete the contact data is; with the optional `icp` input (`preferredRoles`, `keywords`, `countries`, `requireEmail`, `requirePhone`) it is 60% fit and 40% completeness. Only data already read is used: no extra pages, no new event, prices and charges unchanged.

### 2026-10-23

- Near the run's timeout no new website is started: the run ends normally with the rows read so far, `SUMMARY` and `RETRY` (status `PARTIAL_RESULTS`, `SUMMARY.runTimeLimitReached: true`) instead of being stopped by Apify as TIMED-OUT. Websites not started are free and listed in `SUMMARY.notProcessed` (new `reason`: `runTimeout` or `maxChargeReached`) and in `RETRY`. A website still being read near the run's timeout is stopped in time for these final writes, even when a request does not respect the website's time limit.
- Proxy settings Apify refuses no longer fail the run: the websites are read without the proxy and `SUMMARY.proxyWarning` says so.
- A website whose result cannot be saved gets a free `failed` row and a `RETRY` entry instead of disappearing from the output (if that row cannot be saved either, the website has no row, is free and is listed in `SUMMARY.notSaved` and `RETRY`); a passing error writing `CONTACT_REPORT` is tried again before the run is marked failed. Prices and charge events are unchanged; a website is still charged at most once.

### 2026-10-22

- A website stopped by its time limit ("site time limit reached") is now reported as `errorType: timeout` instead of `failed` (error text unchanged) and is read once more at the end of the run when time is left, like other temporary failures. The end-of-run retry reads half as many websites in parallel as the first pass. A website is still charged at most once; prices and charge events are unchanged.

### 2026-10-20

- A home page refused with HTTP 403 or a refusal of automated clients (not a CAPTCHA or bot-check page) is retried once through our Cloudflare WARP network with a standard browser User-Agent that still ends with `TidyToolsContacts/1.0` (input `warpRetry`, default on; Auto and Our servers only). Recovered websites are charged like any other; a second refusal or a bot-check page keeps the free `blocked` row. Prices and charge events are unchanged.

### 2026-10-15

- Company website lookup can use a places listing's city, street, postcode, or phone as evidence when the listed website's home page is unreadable or has no usable name. The listing must match the input row's location or phone; a matching name in the domain alone is insufficient.
- Website names can contain the full multiword business name as consecutive whole words alongside additional words.
- Tab-separated business rows without a header can be read as name, city, and street address; an unmatched row includes a hint to add a header.
- Company lookup results include `websiteFromName.websiteVerifiedBy` and `websiteFromName.websiteConfidence` (`high` or `medium`) when a website is verified.
- The README now reflects defaults of eight pages per website and ten parallel websites.
- The first `SUMMARY` line says the run finished when no more than 15% of websites failed, while retaining the failed website counts.

### 2026-10-13

- Company names without a verified website produce an uncharged result row with a hint on how to find the website.

### 2026-10-09

- The run summary groups refused and unreachable websites as free failed rows and reports their counts.
