New optional subtitleQc (off by default): each row gets a subtitleQc report of the saved SRT/VTT cues: overlapping cues, cues under 1 s, reading speed over 20 characters per second (11 for Chinese, Japanese, Korean and Thai), lines over 42 characters (16 for those scripts) and estimated cue times, with counts per rule and up to 100 warnings (cue number, start, end, rule, measured value). It is a mechanical check; the wording is not proofread. It says skipped when no subtitle file is saved.
New optional cleanAudio (off by default): for a file, cloud-storage link or podcast episode that this run transcribed, a basic cleaned MP3 (noise reduction and loudness levelling, 96 kbps, files up to 2 hours) linked as cleanedAudioUrl. The transcript is still made from the original audio. YouTube, social/video platform pages and publisher transcripts are not processed. If the MP3 cannot be made or saved, the row keeps its transcript and says why in cleanAudioError.
"transcriptionEngine": "accurate" without the cloud fallback (free plans, or allowWorkersAiFallback: false): when the self-hosted Whisper server cannot transcribe a piece, the free row is now service_busy and says so, with what to do (run again later or use fast). It used to be a failed row with an internal error ("Cannot read properties of undefined").
Charging unchanged: no new events and no price change. Both options are free; warnings and clean-up errors never make a transcript fail, and the same files are charged the same audio minutes as before.
YouTube videos in the transcription queue now let paid runs go first and take turns among runs on the same plan. The run reports its own estimated wait and, after video duration is known, an estimated completion time based on eligible nodes and their measured speeds.
YouTube keeps using local Whisper while the service is busy; if it cannot finish in this run, the video gets a free retryable row. The cloud fallback switch applies only to files and audio URLs, never to YouTube.
Charging: the price and events are unchanged. A completed video is charged its transcribed audio minutes; failed videos are free.
One long file over your maximum cost per run no longer ends the batch: it gets a free limit_reached row and the shorter files after it can still run. New files stop once the limit cannot pay for another minute, or after 5 files were skipped for the maximum cost.
limit_reached rows for the maximum cost now say what the file would cost and what is left of the limit. A page with no media file now says which link to pass instead.
Charging: the price per minute and events are unchanged, and a run never goes over your limit. Files that fit after a skipped one are now transcribed and charged, where before they were not started.
Speaker labels: when speech-to-text fails on any part of a file, the file now ends as a free failed row with retryable: true. It used to be reported as "no speech detected", or delivered with that part missing. A language that speaker labels do not support is now reported as unsupported with what to change, instead of "no speech detected".
Charging: the price per minute and events are unchanged. A file with a failed part is no longer charged; files that transcribe completely are charged as before.
YouTube videos waiting in the transcription queue no longer use up the daily speech-to-text allowance before transcription starts. This reduces premature capacity errors during large batches. Work waiting during a service restart can resume, and failed work has a clearer reason.
Charging: the price per minute and events are unchanged. More videos may now finish successfully and be charged for the minutes actually transcribed; waiting or failed videos are not charged.
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.
An age-restricted YouTube video now fails only that video instead of pausing transcription for every video on the service. The failed video remains free; other videos can continue.
Charging unchanged: no new events or price change; only successfully transcribed minutes are billed.
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.
Apify storage links (api.apify.com key-value store records and dataset links, e.g. another Actor's output) are downloaded with no key first; the run's own token is tried only after Apify refuses that. A record that stays refused is a free blocked row saying what to change.
A YouTube video skipped by the service for the run's max cost or maxTotalMinutes now ends the run like any other limit stop: SUMMARY.limitReached, SUMMARY.remainingInputs and the REMAINING_INPUT record list the files left. limit_reached rows say which limit it was and to run again with only the files left, so finished files are not charged twice.
Charging unchanged: no new events, no price change; only transcribed minutes are billed.
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.
SharePoint / OneDrive for Business "Anyone" links download through the site's download.aspx?share= (the link with download=1 now ends on the sign-in page).
Personal OneDrive links (1drv.ms, onedrive.live.com) are read the way OneDrive's web viewer reads them for a signed-out visitor (the old shares API answers 401); folders, non-audio files and private links are free rows before any download.
A file opened inside a Dropbox shared folder (/scl/fo/.../<file>, ?preview=<file>) downloads; a Box page whose owner turned off downloads, a removed Box link, a Box folder and a non-audio Box file are explained from the page itself.
Failure types of share links: private_link, needs_login, quota_exceeded, not_audio, too_large (replacing drive_not_shared, not_shared, drive_quota, share_quota; a file without an audio track is not_audio), and failure rows get a one-sentence howToFix. SUMMARY.failuresByReason counts them. Charging unchanged: only transcribed minutes are billed.
Keep the last paragraph in sampled chapter prompts and the ending of untimed long transcripts in AI prompts.
Add optional contentPack drafts: chapters, show notes, X and LinkedIn posts, plus one optional translated subtitle language billed through the existing minute event.
Add one content-pack event per successful episode, eligible from 2026-11-06 only after its announced start date; otherwise the text pack is free.
Default input and existing audio, summary and subtitle event behavior remain unchanged.
YouTube batches retry short-lived service busy answers with a short backoff. Videos still busy are retried once more, serially, after the first batch. A video produces only one final row and is charged only if transcription succeeds.
When the YouTube service's daily speech-to-text capacity is used up, the free row says when it resets (00:00 UTC, in about N hours) and points to RETRY_INPUT; those videos are not retried inside the run.
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.
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.
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.
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.