<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Web Scraping Club]]></title><description><![CDATA[News, solutions and interviews about web scraping.
In this substack you will find weekly content about:
- Web Scraping techniques
- Interviews with key people in the industry
- Anti bot infos and counter measures
- Real world examples and code]]></description><link>https://substack.thewebscraping.club</link><image><url>https://substackcdn.com/image/fetch/$s_!gJt2!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1e343ec9-7946-4440-8c00-57209a1d99a1_1024x1024.png</url><title>The Web Scraping Club</title><link>https://substack.thewebscraping.club</link></image><generator>Substack</generator><lastBuildDate>Fri, 14 Aug 2026 10:00:43 GMT</lastBuildDate><atom:link href="https://substack.thewebscraping.club/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[The Web Scraping Club SRL]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[pier@thewebscraping.club]]></webMaster><itunes:owner><itunes:email><![CDATA[pier@thewebscraping.club]]></itunes:email><itunes:name><![CDATA[Pierluigi Vinciguerra]]></itunes:name></itunes:owner><itunes:author><![CDATA[Pierluigi Vinciguerra]]></itunes:author><googleplay:owner><![CDATA[pier@thewebscraping.club]]></googleplay:owner><googleplay:email><![CDATA[pier@thewebscraping.club]]></googleplay:email><googleplay:author><![CDATA[Pierluigi Vinciguerra]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Prepare Web Content and Documents for LLM Ingestion Using MarkItDown]]></title><description><![CDATA[Markdown is the language of AI. Learn how to convert different data formats into it!]]></description><link>https://substack.thewebscraping.club/p/markitdown-ai-markdown</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/markitdown-ai-markdown</guid><dc:creator><![CDATA[Antonello Zanini]]></dc:creator><pubDate>Sun, 09 Aug 2026 21:27:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a95436ad-6ed8-4d30-871c-528ebaed6dd4_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most LLMs understand Markdown exceptionally well. Consequently, when building AI-powered data pipelines, it makes sense to convert all input data into Markdown first. This way, scraped web pages, documents, and other content can then be processed in a consistent format.</p><p>That&#8217;s where the MarkItDown Python library comes into play!</p><p>Here, I&#8217;ll show you everything you need to know about MarkItDown, from installation to practical examples, so you can convert HTML pages, PDFs, Word documents, Excel spreadsheets, and many other data sources into LLM-ready Markdown.</p><h2>Why the Markdown Data Format Is More Relevant Than Ever</h2><p>As I covered <a href="https://substack.thewebscraping.club/p/why-scraping-return-markdown-llm-ai">in a recent post</a>, AI-ready web scrapers, RAG pipelines, and agent frameworks all have one thing in common: they rely heavily on Markdown!</p><p>That&#8217;s no coincidence... Mainstream LLMs (including OpenAI&#8217;s latest models) natively &#8220;speak&#8221; Markdown and often generate Markdown-formatted responses without being prompted.</p><p>Why? Because Markdown strikes the perfect balance between plain text and structured documents. It preserves headings, lists, tables, links, code blocks, and other semantic elements without the overhead and noise of HTML.</p><p>As a result, LLMs can understand and process Markdown efficiently while consuming far fewer tokens. This translates directly into lower inference costs and leaves more of the context window available for meaningful content.</p><p>In my experience (and as I demonstrated in <a href="https://www.kaggle.com/code/brightdataml/benchmarking-ai-on-different-data-formats">a benchmark I conducted for Bright Data</a>), Markdown has become the natural format for feeding documents, especially content extracted from the web, into LLMs.</p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/WyQ3mA" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="521" height="293.0625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:521,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p><div><hr></div></blockquote><h2>Why Markdown Conversion Matters in Web Scraping Pipelines</h2><p>Web data is rarely the final destination. Quite the opposite, scraped content generally represents the starting point of a larger data analysis pipeline, where the goal is to extract insights, enrich datasets, or power downstream applications.</p><p>In these workflows, the information you need tends to go beyond traditional web pages. PDFs, Word documents, videos, presentations, and other files can provide additional context required for accurate analysis and processing. These resources may come from the web and be collected during scraping, or they may be added later.</p><p>Regardless of the original format, data is increasingly processed by AI systems. Since LLMs naturally work well with Markdown, converting different sources into a clean, structured Markdown representation can greatly simplify your data pipelines.</p><p>That&#8217;s why you need a multi-format Markdown conversion library in your toolkit, such as MarkItDown!</p><div><hr></div><blockquote><p><em><strong>The new anti-bot solution</strong> - Toughest walls, lowest price. Claim your free 10 000 requests with coupon code <strong>WSCLUB</strong></em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0jGM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 424w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 848w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png" width="612" height="306" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/baf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:612,&quot;bytes&quot;:493234,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208113514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!0jGM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 424w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 848w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k&quot;,&quot;text&quot;:&quot;Claim your credits&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k"><span>Claim your credits</span></a></p></blockquote><div><hr></div><h2>MarkItDown: A Complete Overview</h2><p>Let me now introduce you to MarkItDown, one of the most popular libraries for converting multiple input formats into Markdown.</p><h3>What Is MarkItDown?</h3><p><a href="https://github.com/microsoft/markitdown">MarkItDown</a> is an open-source Python library for converting a wide range of documents and other data sources into Markdown. The project is developed and maintained by Microsoft.</p><p>It&#8217;s quickly become one of the most popular tools in its category (more on this later in the post), with over 165k GitHub stars, over <a href="https://pypistats.org/packages/markitdown">12 million monthly downloads</a>, and a thriving community.</p><p>MarkItDown supports dozens of input formats, ranging from Office documents and PDFs to images, audio files, web pages, YouTube videos, and structured data formats such as JSON, XML, and CSV.</p><h3>Key Features</h3><p>The main capabilities supported by MarkItDown are:</p><ul><li><p><strong>Broad format support</strong>: Converts dozens of input formats, including PDFs, Office documents, HTML, images, audio, EPUBs, ZIP archives, YouTube URLs, and structured data files.</p></li><li><p><strong>Python API</strong>: Offers a clean, developer-friendly API for integrating document conversion into Python applications.</p></li><li><p><strong>Native CLI</strong>: Includes a rich CLI for converting files directly from the terminal, making it ideal for scripting, batch processing, and DevOps workflows.</p></li><li><p><strong>Plugin architecture</strong>: Supports third-party plugins, allowing the community to extend the library with custom converters and additional processing features.</p></li><li><p><strong>AI-powered processing</strong>: Integrates with LLMs to generate image descriptions, perform OCR, and transcribe audio, enriching the resulting Markdown.</p></li><li><p><strong>Flexible dependency management</strong>: Lets you install only the converters you need, reducing dependencies and keeping deployments lightweight.</p></li><li><p><strong>MCP server support:</strong> Provides a lightweight Model Context Protocol server that allows AI agents to call MarkItDown as a tool.</p></li><li><p><strong>Azure AI integration</strong>: Works with <em><a href="https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/overview">Azure Document Intelligence</a></em> and <em><a href="https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/">Azure Content Understanding</a></em> for higher-quality OCR, layout analysis, and structured field extraction.</p></li></ul><h3>Supported Input Formats</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mphI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mphI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 424w, https://substackcdn.com/image/fetch/$s_!mphI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 848w, https://substackcdn.com/image/fetch/$s_!mphI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 1272w, https://substackcdn.com/image/fetch/$s_!mphI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mphI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png" width="1456" height="1747" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1747,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MarkItDown: Input > Output table&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MarkItDown: Input > Output table" title="MarkItDown: Input > Output table" srcset="https://substackcdn.com/image/fetch/$s_!mphI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 424w, https://substackcdn.com/image/fetch/$s_!mphI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 848w, https://substackcdn.com/image/fetch/$s_!mphI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 1272w, https://substackcdn.com/image/fetch/$s_!mphI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2109c0d2-263e-4e69-ad00-6f6aa7b59549_1490x1788.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">MarkItDown: Input &gt; Output table</figcaption></figure></div><h3>Installation and Setup</h3><p>Follow the steps below to add MarkItDown to your system.</p><h3>Prerequisites</h3><p>MarkItDown requires Python 3.10 or higher. It&#8217;s also recommended to install it inside a <a href="https://docs.python.org/3/library/venv.html">Python virtual environment</a>.</p><h3>Installation via pip</h3><p>The easiest way to install MarkItDown is through the <a href="https://pypi.org/project/markitdown/">PyPI </a><em><a href="https://pypi.org/project/markitdown/">markitdown</a></em><a href="https://pypi.org/project/markitdown/"> package</a> with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">pip install 'markitdown[all]'</code></pre></div><p>Note that <em>[all]</em> option adds all optional dependencies required to support every available input format.</p><p>If you only need support for specific file types, you can install the specific dependencies individually for more control. For example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">pip install 'markitdown[pdf, docx]'</code></pre></div><p>This adds only the extra dependencies required for PDF and Word file conversion.</p><p>Available optional dependencies include:</p><ul><li><p><em>[all]</em>: Installs all optional dependencies.</p></li><li><p><em>[pptx]</em>: Adds support for PowerPoint files.</p></li><li><p><em>[docx]</em>: Adds support for Word documents.</p></li><li><p><em>[xlsx]</em>: Adds support for Excel files.</p></li><li><p><em>[xls]</em>: Adds support for older Excel files.</p></li><li><p><em>[pdf]</em>: Adds support for PDF documents.</p></li><li><p><em>[outlook]</em>: Adds support for Outlook messages.</p></li><li><p><em>[audio-transcription]</em>: Adds support for WAV and MP3 audio transcription.</p></li><li><p><em>[youtube-transcription]</em>: Adds support for YouTube video transcription.</p></li><li><p><em>[az-doc-intel]</em>: Enables integration with <em>Azure Document Intelligence</em>.</p></li><li><p><em>[az-content-understanding]</em>: Enables integration with <em>Azure Content Understanding</em>.</p></li></ul><p><strong>Note</strong>: For installation from source or Docker-based usage, <a href="https://github.com/microsoft/markitdown">refer to the official MarkItDown docs</a>.</p><h2>MarkItDown in Action: Full Examples</h2><p>Time to explore some practical examples of converting different input data formats into Markdown.</p><h3>HTML Document to Markdown</h3><p>Suppose you have an HTML page stored locally (e.g., as part of an <a href="https://substack.thewebscraping.club/p/offline-web-scraping">offline web scraping procedure</a>). You can convert it to Markdown using the MarkItDown CLI:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown example.html -o example.md</code></pre></div><p>Alternatively, you can achieve the same result via the Python API:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("example.html")

with open("example.md", "w", encoding="utf-8") as f:
    f.write(result.text_content)</code></pre></div><p>Now, assume the input is the following HTML page (i.e., the homepage from <em>example.com</em>):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gzz9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gzz9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 424w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 848w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 1272w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gzz9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png" width="1456" height="1105" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1105,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The input example.html page&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The input example.html page" title="The input example.html page" srcset="https://substackcdn.com/image/fetch/$s_!gzz9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 424w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 848w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 1272w, https://substackcdn.com/image/fetch/$s_!gzz9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a78396f-044b-432b-a892-6c0bb17307e1_2242x1702.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The input example.html page</figcaption></figure></div><p>The resulting <em>example.md</em> file will contain:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Uuo0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Uuo0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 424w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 848w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 1272w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Uuo0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png" width="1456" height="249" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:249,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Uuo0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 424w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 848w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 1272w, https://substackcdn.com/image/fetch/$s_!Uuo0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F525c452d-95c8-42ce-89cf-32152c90fb00_2246x384.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The resulting example.md Markdown document</figcaption></figure></div><p>Notice how MarkItDown focuses on the meaningful HTML content, ignoring tags like <em><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/style">&lt;style&gt;</a></em>.</p><p>The library extracts the relevant elements and converts them into a structured Markdown representation, keeping important information such as headings, links, and text formatting while removing unnecessary HTML overhead.</p><h3>Web Page to Markdown</h3><p>A particularly useful feature for web scraping workflows is that MarkItDown can also fetch and convert web pages directly from their URLs, eliminating the need to manually save the HTML first.</p><p>Just pass the URL of the target page directly to the MarkItDown CLI:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown 'https://example.com' -o example.md</code></pre></div><p>Or to its Python API:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("https://example.com")

with open("example.md", "w", encoding="utf-8") as f:
    f.write(result.text_content)</code></pre></div><p>Under the hood, MarkItDown performs an HTTP GET request to the specified URL using <em><a href="https://requests.readthedocs.io/">Requests</a></em>, retrieves the page HTML, and converts the resulting content into Markdown. As usual, keep in mind that the request may fail if the target website uses anti-bot protections.</p><p>The output will be the same <span>example.md</span> Markdown file shown in the previous example.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3><br>PDF to Markdown</h3><p>Many websites store valuable information in downloadable PDF files (e.g., shopping flyers, business reports, whitepapers, product documentation, etc.).</p><p>While you can send these files directly to an AI model, doing so often consumes unnecessary context and tokens because PDFs may contain complex layouts and additional formatting overhead.</p><p>MarkItDown converts PDFs into clean Markdown while preserving important elements such as headings, document structure, lists, and tables, making the content easier for LLMs to process.</p><p>Assume your input is the sample PDF below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ULY3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ULY3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 424w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 848w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 1272w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ULY3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png" width="1456" height="1038" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1038,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The input sample.pdf&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The input sample.pdf" title="The input sample.pdf" srcset="https://substackcdn.com/image/fetch/$s_!ULY3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 424w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 848w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 1272w, https://substackcdn.com/image/fetch/$s_!ULY3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6af0c9e3-ab35-4033-a065-bcbb6becc3c7_2248x1602.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The input sample.pdf</figcaption></figure></div><p>Convert it to Markdown with the MarkItDown CLI:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown sample.pdf -o sample.md</code></pre></div><p>Or in Python:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("sample.pdf")

with open("sample.md", "w", encoding="utf-8") as f:
    f.write(result.text_content)</code></pre></div><p>The result will be this <em>sample.md</em> file:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0raX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0raX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 424w, https://substackcdn.com/image/fetch/$s_!0raX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 848w, https://substackcdn.com/image/fetch/$s_!0raX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 1272w, https://substackcdn.com/image/fetch/$s_!0raX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0raX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png" width="1456" height="1074" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1074,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The output sample.md file&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The output sample.md file" title="The output sample.md file" srcset="https://substackcdn.com/image/fetch/$s_!0raX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 424w, https://substackcdn.com/image/fetch/$s_!0raX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 848w, https://substackcdn.com/image/fetch/$s_!0raX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 1272w, https://substackcdn.com/image/fetch/$s_!0raX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F586e977e-cb92-45ec-989e-e1cfd055fbf3_2248x1658.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The output sample.md file</figcaption></figure></div><p>As you can see, MarkItDown preserves all the meaningful content from the PDF.</p><h3>Excel to Markdown</h3><p>Now, suppose you have relevant internal data stored in an Excel spreadsheet and want to pass it to an LLM for analysis or processing:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Zce6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zce6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 424w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 848w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 1272w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zce6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png" width="1456" height="772" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:772,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The input spreadsheet.xls file&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The input spreadsheet.xls file" title="The input spreadsheet.xls file" srcset="https://substackcdn.com/image/fetch/$s_!Zce6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 424w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 848w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 1272w, https://substackcdn.com/image/fetch/$s_!Zce6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7705eeb-d5e1-4505-b1ca-a69cf2c9c7ad_3072x1628.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The input spreadsheet.xls file</figcaption></figure></div><p>Convert it to Markdown through the MarkItDown CLI:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown spreadsheet.xls -o spreadsheet.md</code></pre></div><p>Or use the Python API:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("spreadsheet.xls")

with open("spreadsheet.md", "w", encoding="utf-8") as f:
    f.write(result.text_content)</code></pre></div><p>The result will be a Markdown file containing a table with the same data as the original spreadsheet:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I5hf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I5hf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 424w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 848w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I5hf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png" width="1456" height="1103" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/adcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1103,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The output spreadsheet.md file&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The output spreadsheet.md file" title="The output spreadsheet.md file" srcset="https://substackcdn.com/image/fetch/$s_!I5hf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 424w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 848w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!I5hf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadcad2c7-0e99-4cd9-a393-7a858eed5588_2238x1696.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The output spreadsheet.md file</figcaption></figure></div><p>Or, for a better visual representation, through the Markdown viewer:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mnHs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mnHs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 424w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 848w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mnHs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png" width="1456" height="1101" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1101,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the table in the spreadsheet.md Markdown file&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the table in the spreadsheet.md Markdown file" title="Note the table in the spreadsheet.md Markdown file" srcset="https://substackcdn.com/image/fetch/$s_!mnHs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 424w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 848w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!mnHs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d73a619-d1ef-4b8a-b9a3-c3561a9aedfb_2242x1696.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the table in the spreadsheet.md Markdown file</figcaption></figure></div><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>MarkItDown Plugins</h3><p>MarkItDown also supports third-party plugins that extend its built-in capabilities with additional converters and processing features. You can discover available plugins by searching GitHub for the <em>#markitdown-plugin</em> hashtag:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C4xg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C4xg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 424w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 848w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C4xg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png" width="1456" height="778" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:778,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The result of a &#8220;#markitdown-plugin&#8221; hashtag search on GitHub&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The result of a &#8220;#markitdown-plugin&#8221; hashtag search on GitHub" title="The result of a &#8220;#markitdown-plugin&#8221; hashtag search on GitHub" srcset="https://substackcdn.com/image/fetch/$s_!C4xg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 424w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 848w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!C4xg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb92fc2e0-b297-4d1b-ba2b-3428430ddb88_3072x1642.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The result of a &#8220;#markitdown-plugin&#8221; hashtag search on GitHub</figcaption></figure></div><p>To list all installed plugins, run:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown --list-plugins</code></pre></div><p>Plugins are disabled by default. To enable them from the CLI, add the <em>--use-plugins</em> flag:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">markitdown --use-plugins &lt;SOURCE_FILE_PATH&gt; -o &lt;OUTPUT_FILE&gt;</code></pre></div><p>If you&#8217;re using the Python API, enable plugins by setting the <em>enable_plugins</em> parameter to <em>True</em>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">
from markitdown import MarkItDown

md = MarkItDown(
  enable_plugins=True,
)</code></pre></div><p>Once enabled, MarkItDown automatically loads all installed plugins.</p><h2>MarkItDown Alternatives: Other Document-to-Markdown Libraries</h2><p>MarkItDown isn&#8217;t the only library for converting documents to Markdown. Other popular libraries for converting different types of data into Markdown include:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A07U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A07U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 424w, https://substackcdn.com/image/fetch/$s_!A07U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 848w, https://substackcdn.com/image/fetch/$s_!A07U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 1272w, https://substackcdn.com/image/fetch/$s_!A07U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A07U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png" width="1456" height="1251" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1251,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;MarkItDown alternatives&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="MarkItDown alternatives" title="MarkItDown alternatives" srcset="https://substackcdn.com/image/fetch/$s_!A07U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 424w, https://substackcdn.com/image/fetch/$s_!A07U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 848w, https://substackcdn.com/image/fetch/$s_!A07U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 1272w, https://substackcdn.com/image/fetch/$s_!A07U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9f0284f-fe4a-46dd-93e9-b4c5fbaebcae_1537x1321.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">MarkItDown alternatives</figcaption></figure></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>Markdown is the language of LLMs and, as a result, the preferred format for AI-powered data processing and analysis pipelines. In this post, I covered how to use MarkItDown to convert web pages, HTML documents, PDFs, Word documents, Excel spreadsheets, PowerPoint presentations, YouTube videos, and many other file formats into clean, AI-friendly Markdown.</p><p>You now know how to get the most out of MarkItDown to prepare data for AI workflows, regardless of whether it comes from web scraping, downloaded files, or local documents.</p><p>I hope you found this guide useful. If you have any questions or comments, feel free to leave them below. Thanks for reading, and see you in the next one!</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/markitdown-ai-markdown?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading The Web Scraping Club! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/markitdown-ai-markdown?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/markitdown-ai-markdown?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h2>FAQ</h2><h3>How to set a proxy in MarkItDown?</h3><p>MarkItDown doesn&#8217;t provide a dedicated proxy configuration option. Still, it relies on the Python <em>requests</em> library internally, which supports <a href="https://requests.readthedocs.io/en/latest/user/advanced/#proxies">proxy configuration through special environment variables</a>. Thus, you can set a proxy in MarkItDown with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">export HTTP_PROXY="http://user:password@your-proxy-server.com:port"
export HTTPS_PROXY="http://user:password@your-proxy-server.com:port"</code></pre></div><p>Or, directly in the Python code with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import os
from markitdown import MarkItDown

# Set your proxy addresses (replace with your proxy details)
os.environ["HTTP_PROXY"] = "http://user:password@your-proxy-server.com:port"
os.environ["HTTPS_PROXY"] = "http://user:password@your-proxy-server.com:port"

md = MarkItDown()
# ...</code></pre></div><h3>How to deal with 429 errors when converting YouTube videos to Markdown with MarkItDown?</h3><p>Try to convert a YouTube video to Markdown, such as with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">markitdown "https://www.youtube.com/watch?v=1wtQAoBZLTg" -o video.md</code></pre></div><p>The request is likely to <a href="https://github.com/microsoft/markitdown/issues/1380">fail with </a><em><a href="https://github.com/microsoft/markitdown/issues/1380">429 Too Many Requests</a></em><a href="https://github.com/microsoft/markitdown/issues/1380"> errors</a> due to YouTube anti-bot protections. This can happen even with a fresh IP address. To improve reliability, try to route MarkItDown requests through a <a href="https://substack.thewebscraping.club/p/evaluating-proxy-providers-ips">high-quality residential proxy</a>.</p><h3>How to use the MarkItDown MCP server?</h3><p>The <a href="https://github.com/microsoft/markitdown/tree/main/packages/markitdown-mcp">MarkItDown MCP server</a> exposes a single tool that allows AI agents and MCP-compatible applications to convert different data sources into Markdown. The tool is <em>convert_to_markdown</em>, which accepts <em>http:</em>, <em>https:</em>, <em>file:</em>, and <em>data:</em> URIs.</p><p>Install the MarkItDown MCP server with:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">pip install markitdown-mcp</code></pre></div><p>Then, connect it to an MCP-compatible client, such as Claude Code, Claude Desktop, Codex, Gemini CLI, etc.</p><p><br><br></p>]]></content:encoded></item><item><title><![CDATA[Tool of the week #1: Bright Data Scraper Studio, From Prompt to Production Scraper in Minutes ]]></title><description><![CDATA[Explore how Bright Data's Scraper Studio bridges the gap between AI-assisted building and full IDE-level control without locking you into either.]]></description><link>https://substack.thewebscraping.club/p/bright-data-scraper-studio</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/bright-data-scraper-studio</guid><dc:creator><![CDATA[Federico Trotta]]></dc:creator><pubDate>Tue, 04 Aug 2026 03:01:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1f585129-6ef1-4c20-8885-181da3fa1486_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you&#8217;ve been building serious scrapers for a while, you know that the real bottleneck is everything around the extraction logic. Especially for production-ready scrapers, you have to spend hours wiring up proxy rotation, managing headless browser sessions, handling rate limits and fingerprinting, and then babysitting the whole system when the target site inevitably changes its DOM structure. The actual scraping part? It&#8217;s maybe 20% of the whole work.</p><p>As AI usage is growing more and more every day, you&#8217;d like an AI-powered tool that can improve your scraping productivity, don&#8217;t you?! Especially when it comes to <a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision">managing selectors, and DOM structure changes</a>&#8230;</p><p>Well, there&#8217;s good news for you: this is the exact gap <a href="https://get.brightdata.com/twsc-scraper-studio">Bright Data Scraper Studio</a> is designed to close!</p><p>This article discusses what Bright Data&#8217;s Scraper Studio is, why it exists, and how to use it with a step-by-step tutorial.</p><p>Let&#8217;s get into it!</p><h2>What Scraper Studio Actually Is</h2><p><a href="https://brightdata.com/products/web-scraper/studio">Scraper Studio</a> is a cloud-hosted, end-to-end scraping environment running entirely on top of Bright Data&#8217;s infrastructure. The tool is designed from the ground up with scraping primitives in mind, as it provides built-in proxy rotation, native JavaScript rendering, anti-bot handling, and direct integrations with data delivery targets like Amazon S3, Snowflake, Google Cloud, and Microsoft Azure.</p><p>The platform offers two build modes that sit on the same underlying scraper runtime:</p><ul><li><p><strong>AI agent mode</strong>: You provide a target URL and a plain-English description of the data you want to extract. The AI agent visits the page, infers a structured output schema, and then generates the full scraper code for you. At the end of this automated process, you review and approve the schema before code generation begins. This gives you a checkpoint to catch misaligned fields before they propagate into your pipeline, allowing you to change them.</p></li><li><p><strong>Full IDE mode</strong>: A full browser-based JavaScript code editor with debugging tools for when you need direct, line-level control over the scraper logic. This is the mode you can use for when you&#8217;re dealing with multi-stage scrapers, custom pagination logic, complex state management between page navigations, or sites with particularly aggressive anti-bot stacks that need fine-tuned handling.</p></li></ul><p>What&#8217;s more important is that both modes produce the same type of scraper. This means that you&#8217;re never locked into one approach: a scraper built in the AI Agent mode can be opened and edited in the IDE at any time, and any scraper can be updated using the <em><a href="https://docs.brightdata.com/datasets/scraper-studio/self-healing-tool">Self-healing tool</a>.</em></p><h2>Scraper Studio Key Features</h2><p>Let&#8217;s take a close look at Scraper Studio&#8217;s features:</p><ul><li><p><strong>Built-in proxy infrastructure</strong>: Scraper Studio runs on Bright Data&#8217;s proxy network which, among other types, provides users with 400+ million residential IPs across 195 countries, with 99.99% uptime. For scraping professionals, this means no proxy pool management and, more importantly, no dealing with burned IPs.</p></li><li><p><strong>Anti-bot bypass, natively integrated</strong>: JavaScript rendering, fingerprinting evasion, and <a href="https://substack.thewebscraping.club/p/managing-proxy-bans-proxy-retries">bot detection bypass are built into the runtime</a>. This is significant because it means your scraper code doesn&#8217;t need to account for these concerns. You write the extraction logic, and the platform handles the unblocking automatically.</p></li><li><p><strong>AI-powered self-healing</strong>: This is arguably the most operationally relevant feature for running scrapers long-term. When a target site changes its structure, and your scraper breaks, the self-healing tool lets you describe the fix in plain English. The AI analyzes the current code, proposes changes with a diff view, and you approve or reject them. This means that you remain in control of the overall process, as changes aren&#8217;t auto-applied unless you explicitly enable auto-approval</p></li><li><p><strong>Scheduled runs and data delivery</strong>: Scraper Studio includes a scheduling layer, so you can configure periodic runs without external orchestration. Combine this with native delivery to S3, Snowflake, GCS, or Azure, and you have a complete data pipeline that starts from scraping and ends with structured output in your data warehouse, with no spaghetti code required.</p></li><li><p><strong>CLI and agent integration</strong>: If you prefer working outside the browser UI, scrapers can be built and triggered via the Bright Data CLI, and the AI Agent mode is accessible programmatically, currently compatible with tools like Claude Code, Cursor, and Codex. This means you can integrate Scraper Studio into existing developer workflows without being locked into the web interface.</p></li><li><p><strong>Wide pricing offer</strong>: The pricing offer may seem like a secondary theme, but it&#8217;s not. First and foremost, Bright Data offers you 5k page loads for free every month, backed by their expert support if you need it. The other pricing options are:</p><ul><li><p>Pay-as-you-go: $1.5 per 1k page loads, and you pay only for successful requests.</p></li><li><p>Scale: $400/Mo that includes about 400k page loads per month and more.</p></li><li><p>Enterprise: A custom pricing tier for enterprises, based on their specific needs.</p></li></ul></li></ul><h2>Scraper Studio Best Use Cases</h2><p>If you&#8217;re already familiar with Bright Data products and offers, you may be asking why use Scraper Studio. Below is a list of practical examples when this is the right tool to use:</p><ul><li><p><strong>No APIs or ready-to-use datasets</strong>: If you need to scrape a site that isn&#8217;t available on Bright Data&#8217;s pre-built Datasets Marketplace or on its web scraping APIs, and you want to own the scraper logic yourself but not the infrastructure, well, Scraper Studio is your best choice.</p></li><li><p><strong>Recurring pipelines</strong>: When you&#8217;re building a recurring data pipeline and don&#8217;t want to manage cron jobs, deployment infrastructure, or <a href="https://substack.thewebscraping.club/p/differences-residential-mobile-proxies">proxy pools</a> separately.</p></li><li><p><strong>Quick prototypes</strong>: The AI Agent mode can go from a single URL to a working scraper in under 10 minutes. This makes it genuinely useful for validating whether a scraping approach is feasible before committing engineering time on a larger scale.</p></li><li><p><strong>You&#8217;re in a team with mixed technical levels</strong>: The AI Agent is accessible to non-engineers, and the IDE gives developers full control. They both produce the same type of scraper, deployable on the same infrastructure, and as it is interchangeable, your team can manage the same project with different technical levels.</p></li></ul><h2>How to Build a Web Scraper With Scraper Studio Using the AI Agent Mode</h2><p>Time to take the theory into practice. In this section, you&#8217;ll learn how to create a web scraper with Scraper Studio using its AI agent mode. The target URL for this tutorial is from the <a href="https://www.kappa.com/products/active-jerseys-man-amirilore-trackhouse-blue-diva-grey-antrachite-neon-yellow-322j6hw-trh-a02">Kappa&#8217;s website</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NfDA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NfDA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 424w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 848w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 1272w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NfDA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png" width="1456" height="656" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c549333-7ede-4b83-8242-917209959f20_1903x858.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:656,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:424073,&quot;alt&quot;:&quot;The target product from Kappa&#8217;s website by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The target product from Kappa&#8217;s website by Federico Trotta" title="The target product from Kappa&#8217;s website by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!NfDA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 424w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 848w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 1272w, https://substackcdn.com/image/fetch/$s_!NfDA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c549333-7ede-4b83-8242-917209959f20_1903x858.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The target product from Kappa&#8217;s website</figcaption></figure></div><p>The scraper will retrieve the data from this target page, using the constraints via the prompt description.</p><p>Follow the next steps to build your scraper!</p><h3>Step #1: Create a New AI Web Scraper Project</h3><p>After creating a new <a href="https://brightdata.com/">Bright Data account</a>, go to the <strong>Scrapers</strong> tab and click on <strong>Develop a web scraper</strong> under <strong>New</strong>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xmDN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xmDN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 424w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 848w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 1272w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xmDN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png" width="1456" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88822,&quot;alt&quot;:&quot;Create a new web scraper in Bright Data&#8217;s dashboard by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Create a new web scraper in Bright Data&#8217;s dashboard by Federico Trotta" title="Create a new web scraper in Bright Data&#8217;s dashboard by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!xmDN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 424w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 848w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 1272w, https://substackcdn.com/image/fetch/$s_!xmDN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87ae1506-f01f-4ffc-af6c-1b210fc64da9_1887x466.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Create a new web scraper in Bright Data&#8217;s dashboard</figcaption></figure></div><p>You&#8217;ll be redirected to a page where you can insert the target URL and the prompt. For this tutorial, the prompt is the following:</p><pre><code><code>Extract the product name, price, available variations / colors, sizes, image URLs, product description, product details.</code></code></pre><p>Below is the visual result:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TESU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TESU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 424w, https://substackcdn.com/image/fetch/$s_!TESU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 848w, https://substackcdn.com/image/fetch/$s_!TESU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 1272w, https://substackcdn.com/image/fetch/$s_!TESU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TESU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png" width="1291" height="683" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:683,&quot;width&quot;:1291,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:183288,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TESU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 424w, https://substackcdn.com/image/fetch/$s_!TESU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 848w, https://substackcdn.com/image/fetch/$s_!TESU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 1272w, https://substackcdn.com/image/fetch/$s_!TESU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ed096d-079e-4814-897b-1e75e51542a9_1291x683.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Starting your AI web scraping project with Scraper Studio</figcaption></figure></div><p>Note that this is also where you can immediately go for the IDE mode by clicking on <strong>Open IDE</strong>.</p><p>When you&#8217;re ready, click on <strong>Start scraping with AI,</strong> and Scraper Studio will make its magic!</p><h3>Step #2: Analyze and Approve the Output Schema</h3><p>The system will automatically produce the output below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wD0G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wD0G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 424w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 848w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 1272w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wD0G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png" width="863" height="721" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:721,&quot;width&quot;:863,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121860,&quot;alt&quot;:&quot;Approve or decline the presented data structure by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Approve or decline the presented data structure by Federico Trotta" title="Approve or decline the presented data structure by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!wD0G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 424w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 848w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 1272w, https://substackcdn.com/image/fetch/$s_!wD0G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80b2354e-7109-49e4-b6a7-501e60fade5d_863x721.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Approve or decline the presented data structure</figcaption></figure></div><p>This is the output schema. It&#8217;s a structured list of data fields the scraper will extract, along with their data types. Compare this with the data in the target page, and click <strong>Approve</strong> if the output matches your expectations.</p><p>After your approval, Scraper Studio will start creating the web scraper. When the process is done, you&#8217;ll receive the following pop-up:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8Fxy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8Fxy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 424w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 848w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 1272w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8Fxy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png" width="861" height="711" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:711,&quot;width&quot;:861,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:106553,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8Fxy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 424w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 848w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 1272w, https://substackcdn.com/image/fetch/$s_!8Fxy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5272e0de-d378-4c27-a3e5-fb9554de0795_861x711.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Your scraper is ready!</figcaption></figure></div><p>You&#8217;ll also get a notification email when the scraper is ready:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jVW7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jVW7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 424w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 848w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 1272w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jVW7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png" width="1456" height="666" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:666,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83143,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jVW7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 424w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 848w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 1272w, https://substackcdn.com/image/fetch/$s_!jVW7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc548cb3-ae09-4358-9f9f-3cdeb873fb45_1531x700.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The email notification you&#8217;ll receive when your scraper is ready</figcaption></figure></div><p>All right, your scraper is ready for data retrieval.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3>Step #3: Manage Preferences and Retrieve The Data</h3><p>When the scraper is ready, this doesn&#8217;t mean the data is scraped. Before scraping the data, you have to manage your preferences.</p><p>First of all, go into your scrapers and navigate to the <strong>Delivery preferences</strong> tab:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sRzP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sRzP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 424w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 848w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 1272w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sRzP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png" width="1456" height="475" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:475,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87023,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sRzP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 424w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 848w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 1272w, https://substackcdn.com/image/fetch/$s_!sRzP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9697b201-60ae-43c7-b758-b8f7b1f47bb9_1690x551.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Manage the delivery preferences</figcaption></figure></div><p>Here is where you can choose among:</p><ul><li><p>Data format for local download, like JSON, NDJSON, CSV, or XLS.</p></li><li><p>Third-party connections like Amazon S3 bucket, AWS, Snowflake, and more.</p></li><li><p>Get notified via email based on the status of the data delivery.</p></li></ul><p>If you want a scraper that starts recurrently, navigate to the <strong>Subscriptions</strong> tab and set your schedule:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JeL8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JeL8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 424w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 848w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 1272w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JeL8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png" width="1456" height="681" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:681,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:95359,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JeL8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 424w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 848w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 1272w, https://substackcdn.com/image/fetch/$s_!JeL8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba20dd9a-253e-4d3f-bc70-fa1c5aa292be_1502x702.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Manage scheduling options</figcaption></figure></div><p>If you just want to test things around or if you need a one-time scraper, the <strong><span>Initiate manually</span></strong> tab is already sufficient. You just need to click on <strong><span>Start,</span></strong> and the scraper will begin retrieving the data:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aEVq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aEVq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 424w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 848w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 1272w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aEVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png" width="1456" height="746" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:746,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:92010,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aEVq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 424w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 848w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 1272w, https://substackcdn.com/image/fetch/$s_!aEVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72ae9e67-4fa5-48f8-92f7-d1e8281ed2c1_1567x803.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Manually start the scrapers</figcaption></figure></div><p>Very well! You made it to retrieve data with your first scraper made with Scraper Studio.</p><h3>Step #4: Check Runs and Go to IDE Mode</h3><p>To check the status of each scraping run, go to the <strong>Runs</strong> section. This will display all the information you need on each data retrieval performed by the scraper:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WMcf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WMcf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 424w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 848w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 1272w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WMcf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png" width="1456" height="548" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:548,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124884,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WMcf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 424w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 848w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 1272w, https://substackcdn.com/image/fetch/$s_!WMcf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40c4290a-3280-43d6-8061-253ecf73e90a_1723x648.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Check runs</figcaption></figure></div><p>The <strong>Actions</strong> section allows you to download the data in different formats. Below is the result in JSON:</p><pre><code><code>[
  {
    "product_name": "Blue Men's Trackhouse Moto GP Team Motorcycle T-Shirt with Contrast Inserts",
    "product_subtitle": "AMIRILORE TRACKHOUSE Blue Diva-Grey Antrachite-NEON Yellow",
    "brand": "KAPPA",
    "price": {
      "value": 67,
      "currency": "USD",
      "symbol": "$"
    },
    "sku": "Style: 322J6HW - Color: A02",
    "available_sizes": [
      "XS",
      "S",
      "M",
      "L",
      "XL",
      "2XL",
      "3XL",
      "4XL",
      "5XL",
      "6XL"
    ],
    "image_urls": [
      "&lt;https://www.kappa.com/cdn/shop/files/UB322J6HWTRHA02_5f5f425b-48d1-4181-af4c-ce863229cbf4.jpg&gt;",
      "&lt;https://www.kappa.com/cdn/shop/files/UB322J6HWTRHA02_aa19b0fa-ca41-4894-ad74-8d408cc31725.jpg&gt;",
      "&lt;https://www.kappa.com/cdn/shop/files/UB322J6HWTRHA02.jpg&gt;",
      "&lt;https://www.kappa.com/cdn/shop/files/UB322J6HWTRHA02_8bd76dc9-0550-48f9-a974-e3c38a4b707e.jpg&gt;"
    ],
    "description": "Product Description GARA. T-shirt for man in polyester fabric. REGULAR FIT. Short sleeve, roundcollar, insert on shoulders in contrast color, sides and shoulders inserts. Omini logo, Team personalizations and sponsors sublimated. TRACKHOUSE.",
    "product_details": "Description Active Jerseys Gender Man Season Spring Composition Main Fabric: Recycled Polyester 100%",
    "input": {
      "url": "&lt;https://www.kappa.com/products/active-jerseys-man-amirilore-trackhouse-blue-diva-grey-antrachite-neon-yellow-322j6hw-trh-a02&gt;"
    }
  }
]</code></code></pre><p>As you can see, the results are exactly how&#8217;d you expect.</p><p>To change the mode to the full IDE one, navigate to the <strong>Code</strong> tab:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FIsG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FIsG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 424w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 848w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 1272w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FIsG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png" width="1456" height="681" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:681,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:150776,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FIsG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 424w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 848w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 1272w, https://substackcdn.com/image/fetch/$s_!FIsG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfee9ac9-9d16-41ae-bb75-85cfd64f4a50_1817x850.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Switch to full IDE mode</figcaption></figure></div><p>This is where you can write your custom JavaScript to modify anything you need.</p><p>Terrific! You completed your first scraping project with Bright Data&#8217;s Scraper Studio.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h2>Comparison Table: Scraping via Custom Code Vs Using Scraper Studio</h2><p>The table below summarizes the differences in scraping the same target using a scraper you coded yourself or using Scraper Studio:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XsLN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XsLN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 424w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 848w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 1272w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XsLN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png" width="725" height="199.67376373626374" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:401,&quot;width&quot;:1456,&quot;resizeWidth&quot;:725,&quot;bytes&quot;:132900,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206983382?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XsLN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 424w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 848w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 1272w, https://substackcdn.com/image/fetch/$s_!XsLN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54f4b6db-c1e0-48d7-9e64-9b70e8807a84_1857x511.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Comparing manually scraping Vs using Scraper Studio on the same target website</figcaption></figure></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>In this article, you discovered what <a href="https://get.brightdata.com/twsc-scraper-studio">Bright Data&#8217;s Scraper Studio</a> is, its features and best use cases, and how easy it is to use it.</p><p>As you&#8217;ve learned, Scraper Studio is an ideal solution for building a web scraper without any infrastructure overhead, but also without managing selectors manually. Thanks to it, you don&#8217;t have to deal with common challenges like infrastructure maintenance, proxy rotation, and anti-bot bypass, but also with DOM changes.</p><p>In a matter of a few minutes, you can go from a prompt written in natural language to a production-ready scraper, with automated data delivery to Amazon S3, Snowflake, and many other destinations, and with the possibility to schedule your scrapers and manage DOM changes without manual overhead.</p><p>So, let us know in the comments: have you ever tried Scraper Studio? What&#8217;s your experience with it?</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/bright-data-scraper-studio?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/bright-data-scraper-studio?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div>]]></content:encoded></item><item><title><![CDATA[Why Your RAG Pipelines Are Only as Good as Your Data Acquisition Layer]]></title><description><![CDATA[A deep dive into what RAG actually requires, where web search integration falls short, and why scraping is the only retrieval layer that scales.]]></description><link>https://substack.thewebscraping.club/p/rag-pipeline-web-scraping</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/rag-pipeline-web-scraping</guid><dc:creator><![CDATA[Federico Trotta]]></dc:creator><pubDate>Sun, 02 Aug 2026 19:28:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9a964356-43bf-4581-99d7-ba6e43bfaf5b_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Large language models have a memory problem, but it&#8217;s not in the conventional sense you may think of. The problem is that the knowledge baked into a model&#8217;s weights is static, bounded by its training cutoff, blind to proprietary data, and structurally incapable of being updated without retraining.</p><p>Retrieval Augmented Generation (RAG) was designed to solve exactly such limitations. By decoupling what the model knows from what it can access at query time, RAG gives LLMs the ability to reason over fresh, domain-specific, and proprietary knowledge without any retraining. In theory, this closes the knowledge gap entirely. In practice, the quality of a RAG system is bound entirely by the quality of its retrieval layer, and this is where most implementations break down.</p><p>Indeed, many teams think that the solution is already offered by web search tools that, nowadays, are integrated in all commercial LLMs. This article makes the case for why that is the wrong call and why web scraping is the right retrieval layer that RAG actually requires.</p><p>Let&#8217;s get into it!</p><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p><div><hr></div></blockquote><h2>What is RAG?</h2><p>Retrieval Augmented Generation (RAG<strong>)</strong> is an architectural pattern in natural language processing that augments the inference pipeline of a generative large language model (LLM). It does so by dynamically injecting externally retrieved, contextually relevant information into the prompt at query time. In simple terms, rather than relying exclusively on knowledge encoded in model weights during training, RAG decouples parametric memory (what the model learned) from non-parametric memory (an external, queryable knowledge store), combining both at runtime. This produces models&#8217; outputs that are accurate and grounded.</p><p>The canonical RAG pipeline operates in two distinct phases:</p><ol><li><p><strong>Retrieval phase</strong>: Given a user query <em>q</em>, a retriever component encodes <em>q</em> into a vector embedding database and performs approximate nearest-neighbor (ANN) search against a pre-indexed corpus of document chunks.</p></li><li><p><strong>Generation phase</strong>: The retrieved passages are concatenated with the original query and injected into the LLM&#8217;s context window as an augmented prompt. The model, then, conditions its output token generation on both its parametric weights and the retrieved evidence, producing a response that is grounded in the supplied documents.</p></li></ol><p>Modern RAG implementations have evolved beyond this baseline. Advanced RAG patterns introduce query rewriting, hypothetical document embeddings (HyDE), re-ranking layers, and recursive or agentic retrieval loops. Modular RAG frameworks further decompose the pipeline into interchangeable components, enabling fine-grained control over each retrieval and generation step.</p><p>At the infrastructure level, modern RAG pipelines rely on three core components working in concert:</p><ul><li><p>A vector database for storing and querying document embeddings at scale.</p></li><li><p>An embedding model responsible for encoding both documents and queries into a shared latent semantic space.</p></li><li><p>A generative model (the LLM) that synthesizes retrieved evidence into a coherent, task-specific response.</p></li></ul><p>Below is an image that shows the high-level architecture:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JGU4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JGU4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 424w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 848w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 1272w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JGU4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png" width="1118" height="554" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:554,&quot;width&quot;:1118,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:932771,&quot;alt&quot;:&quot;A RAG system schema by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206036182?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A RAG system schema by Federico Trotta" title="A RAG system schema by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!JGU4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 424w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 848w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 1272w, https://substackcdn.com/image/fetch/$s_!JGU4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefc3d14a-8eba-4e66-be82-8d8d55c9905d_1118x554.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A RAG system schema</figcaption></figure></div><h2>Why LLMs Need RAG</h2><p>During the training phase, an LLM compresses knowledge from its training corpus into billions of parameters. This process is inherently lossy because the model doesn&#8217;t store facts verbatim: it learns statistical associations between tokens. As a result of this process:</p><ul><li><p><strong>Factual recall is probabilistic, not deterministic</strong>: The model may confidently produce a plausible-sounding but incorrect answer on a user query, because it&#8217;s sampling from a learned distribution rather than retrieving from a verifiable source. The process of producing a plausible-sounding but incorrect response is called hallucination.</p></li><li><p><strong>Knowledge is frozen at the training cutoff:</strong> Any event, document, regulation, product update, or research finding that postdates the model&#8217;s training window is entirely invisible to the model. For enterprise applications where data changes frequently, this is a critical failure mode. This means that if you query a model on something that occurred after its training ended, it will surely hallucinate the response.</p></li><li><p><strong>Specific, private, or proprietary knowledge is absent by design:</strong> Internal documentation, CRM records, legal contracts, and domain-specific corpora are never part of a pre-training dataset.</p></li></ul><p>RAG was designed precisely to address these constraints that are inherent to LLMs. Below is how RAG maps to concrete business scenarios that enterprises face every day.</p><h3>Documentation-Aware Support Bots</h3><p>One of the most immediate and impactful enterprise applications of RAG is the construction of intelligent support bots grounded in a product&#8217;s technical documentation. Consider a SaaS company with several pages of technical docs, API references, changelogs, and troubleshooting guides. An LLM cannot reliably answer user questions about that product. What happens is that it either lacks the knowledge entirely or, worse, generates plausible-but-wrong instructions that erode user trust.</p><p>With RAG, every user query triggers a retrieval step against the indexed documentation corpus. The bot responds based on what the docs <em>actually say</em>, not on what the model statistically associates with similar-sounding topics.</p><p>The same pattern extends naturally to internal knowledge bases like HR policy portals, IT helpdesks, onboarding assistants, and legal FAQ systems, where the source of truth is a controlled, company-owned corpus rather than the public web.</p><h3>Legal and Regulatory Intelligence on Recent Developments</h3><p>The legal industry represents one of the clearest demonstrations of RAG&#8217;s necessity. Why? Because court rulings, regulatory guidance, legislative amendments, and compliance frameworks are published continuously. Legal research on an LLM is inherently dangerous because its training cutoff means the model is blind to any case law or regulation published after that date. And, in law, a single overlooked precedent can have material consequences.</p><p>RAG enables a fundamentally different architecture: legal documents, newly published court opinions, and regulatory updates are scraped, processed, and indexed into the retrieval layer as soon as they are available. When a lawyer or compliance officer queries the system, the retriever fetches the latest relevant documents, and the LLM synthesizes a grounded answer.</p><h3>Competitive Intelligence and Market Monitoring</h3><p>Enterprises routinely need to <a href="https://app.notion.com/p/TWS-How-to-Use-Web-Scraping-for-RAG-38b945fea5028092b6baca3f49d54755?pvs=21">track competitor activity, industry trends, and market signals</a> across news sources, press releases, job postings, and public filings. This information is inherently ephemeral because a competitor&#8217;s product launch announcement published yesterday is invisible to any LLM. By building a RAG pipeline that continuously ingests and indexes targeted public web sources, organizations can deploy analysts-in-the-loop systems that answer strategic queries based on fresh, real-world evidence rather than stale parametric knowledge.</p><h2>Why Web Search Integration Is Not Enough</h2><p>On the side of the architecture, the retrieval part of RAG systems can be built in different ways. The common ones are two:</p><ul><li><p>Creating a knowledge base of documents (like a plethora of PDFs and similar).</p></li><li><p>Retrieving the needed information from the live web.</p></li></ul><p>The knowledge base of documents is generally something that companies have already built over the years. So, let&#8217;s focus on the web retrieval part&#8212;which is also the most interesting one for us, scraping professionals.</p><p>Today, every commercial LLM has a web search tool integrated into it. So, at first glance, it seems to be the right tool to use for creating RAG systems. After all, if the model can query the live web, doesn&#8217;t that solve the knowledge cutoff problem entirely? The answer is: partially, and only for a narrow subset of enterprise needs. This is because the web search integration and RAG are fundamentally different mechanisms that solve different problems. Below are the main differences between the two:</p><ul><li><p><strong>Web search operates on public web content</strong>: First of all, a web search tool cannot reach your internal knowledge base, your proprietary documentation, your CRM history, or your company&#8217;s legal contracts. Sure, some companies put their internal knowledge on the web with restricted access, but this encompasses only a few cases. Also, the truth is that no company actually puts all its documentation on a website, even if with restricted access (think of legal contracts, for example).</p></li><li><p><strong>Web search is non-deterministic and uncontrolled by design</strong>: When an LLM issues a search query, the results it retrieves depend on the search engine&#8217;s ranking algorithm, which is commercially influenced and optimized for general web traffic, not for your specific domain. In a RAG system, instead, you control the corpus. In other words, you decide what documents are indexed, how they are chunked, how they are weighted, and when they are refreshed. This level of governance is not optional in regulated industries where compliance is a requirement. Indeed, an enterprise cannot defend an AI-generated legal or financial output that was grounded in whatever Google happened to rank first. Also, no one guarantees that the web search is actually able to read the content on a website that is highly protected. In other words, very often happens that the web search tool can&#8217;t overcome the anti-bot systems on a target website, and the model simply hallucinates the response to your query (and you don&#8217;t even notice!).</p></li><li><p><strong>The retrieval mechanism itself is categorically different</strong>: Web search tools rely on keyword-based and PageRank-style relevance signals. RAG retrieval, by contrast, operates in a dense semantic vector space. This means that it finds documents that are conceptually relevant to a query even when they share no exact keywords with it. For domain-specific queries, this distinction in retrieval precision directly impacts the quality of the generated response.</p></li><li><p><strong>Web search tools introduce latency, rate limits, and external dependencies</strong>: A RAG system backed by an internal vector store is a self-contained, auditable, scalable infrastructure component. A system that depends on a web search tool at every call is coupled to external services, subject to availability failures, and difficult to reproduce or audit</p></li><li><p><strong>Web search tools don&#8217;t solve the hallucination problem:</strong> Web search tools increase the probability that relevant information surfaces in the context window, but if the search query is poorly formed, if the right page isn&#8217;t indexed, or if the model misreads the retrieved snippet, hallucination remains entirely possible. RAG, when implemented with rigorous chunking strategies, high-quality embeddings, and re-ranking layers, provides a far more controlled and reliable grounding mechanism.</p></li></ul><p>In short, web search tools make general-purpose LLMs more useful for casual queries. This means that an LLM equipped with a web search tool is useful to respond to basic queries that rely on data recently published on the web. However, they can&#8217;t replace RAG systems for any organization that requires precision, privacy, control, and auditability over wide and specific knowledge.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>Web Scraping as the Data Acquisition Layer for RAG</h2><p>The limitations of web search tools presented in the previous paragraph are structural. The solution to overcome them is to use web scraping as the retrieval layer for your RAG pipelines. This is because by using web scraping, you are not querying an external search engine and accepting whatever it returns. You get direct, programmatic access to the content of any publicly accessible web page, on your own schedule, under your own control.</p><p>So, let&#8217;s see how scraping the web changes the dynamic of retrieving content from the web for RAG purposes.</p><h3>Full Control Over the Knowledge Corpus</h3><p>When you build a RAG pipeline fed by a web scraper, you are the one defining the boundaries of your knowledge base. You decide which domains, subdomains, and URL patterns are in scope. You decide how frequently each source is re-crawled, which pages are included, which are filtered out, and which are prioritized during indexing. None of this is possible with web search integration, where the retrieval scope is, by definition, the entire public web as ranked by an opaque external algorithm.</p><p>This level of corpus governance is a prerequisite for any enterprise deployment where the knowledge base must be auditable, bounded, and defensible.</p><p>Also, using web scraping as the retrieval layer doesn&#8217;t mean that you have to code and manage your own scraping infrastructure&#8212;which could cause overheads as well as a huge amount of investments. The scraping industry today is mature enough to offer you:</p><ul><li><p>Pre-scraped datasets whose data can be refreshed based on your needs.</p></li><li><p>Scraping infrastructure as-a-service. In other words, you tell the provider the content to scrape, and their professionals do the job for you, providing you with ready-for-analytics data.</p></li></ul><h3>Accessing Content That Search Engines Cannot Deliver</h3><p>Public search engines index a fraction of the publicly accessible web, and they do so on their own timeline and according to their own crawl priorities. Pages that were published recently, that exist on domains with low authority, that are dynamically rendered via JavaScript, or that are structured in ways that resist standard crawling are routinely underrepresented or absent from search engine indexes entirely.</p><p>A purpose-built web scraper is not subject to any of these constraints. It can be engineered to handle JavaScript-rendered single-page applications using headless browser automation tools such as Playwright or Puppeteer, capturing <a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision">the fully hydrated DOM rather than the bare HTML</a> shell that a naive HTTP request would return. It can navigate paginated content, follow internal links recursively to achieve full site coverage, and process non-HTML formats.</p><p>Now, you can also think that a plausible solution is to put a target URL into the prompt and ask the LLM to retrieve the content via the web search tool. But due to the nature of the web search tool, this is not a reliable solution, because, as discussed previously:</p><ul><li><p>The web search tool may not be able to retrieve the content if the domain is highly protected by anti-bots.</p></li><li><p>The use of a web search tool is non-deterministic due to how LLMs work. This means that the LLM can respond without actually retrieving the content. Or, in some cases, the LLM can respond, but its response can be a mix of content retrieved from the target URL and other content that the web search tool has retrieved from the web. In other words, the LLM can autonomously decide to retrieve the content, for a given query, from the target URL you passed into the prompt, and from other content that the web search tool retrieves from the web, based on the query.</p></li></ul><p>But for RAG pipelines that need comprehensive, deep coverage of a specific web domain, the right degree of control over the crawling behavior is a fundamental feature, often a non-negotiable one.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>Deterministic, Reproducible Retrieval</h3><p>One of the most underappreciated properties of a scraping-fed RAG system is reproducibility. When a user queries a RAG system backed by a web-scraped and version-controlled vector store, the retrieval behavior is deterministic: the same query against the same index returns the same results. This makes the system testable, debuggable, and auditable in ways that a live-search-grounded system categorically is not.</p><p>In a search-integrated LLM, the retrieved content is ephemeral. Specifically speaking, the content exists only in the context window of a single inference call. This means that it cannot be logged in a structured way, and may differ entirely if the same query is issued five minutes later because the search ranking shifted. In a scraping-fed RAG system, instead, every document in the index has a known origin, a known ingestion timestamp, and a known embedding. If an output is questioned, you can trace it back to the exact chunk, the exact source page, and the exact crawl that produced it. This traceability is the operational backbone of trustworthy enterprise AI.</p><h3>Freshness on Your Terms</h3><p>The knowledge cutoff problem that cripples base LLMs does not disappear with a static RAG corpus. A vector store that was indexed six months ago and never refreshed is, from a knowledge currency standpoint, equivalent to a model with a six-month-old training cutoff. <strong>Web scraping solves this by making</strong> <strong>freshness a configurable, automated pipeline</strong>.</p><p>A production RAG scraping pipeline typically implements a tiered crawl schedule calibrated to the update frequency of each source: high-volatility sources like breaking news feeds, regulatory update pages, earnings release portals, and product changelog endpoints are re-crawled on a schedule ranging from hourly to daily. Lower-volatility sources may be re-crawled weekly or triggered by change detection signals. When new content is detected, only the affected chunks are re-embedded and re-indexed, making incremental updates computationally efficient even at scale.</p><p>This architecture gives enterprises something that neither a base LLM nor a search-integrated model can offer: a knowledge base with a freshness SLA<strong>.</strong> This is a contractual guarantee that the information grounding the system&#8217;s outputs is no older than a defined threshold.</p><h3>Clean, Structured Text as a First-Class Output</h3><p>Web scraping, when implemented correctly, does not simply dump raw HTML into the processing pipeline. A <a href="https://substack.thewebscraping.club/p/how-to-use-llms-data-extraction-unstructured-text">production-grade scraping pipeline extracts clean, structured</a>, semantically meaningful text from the web.</p><p>This matters enormously for chunking quality, and by extension, for retrieval quality. Recall that the integrity of every chunk is bounded by the integrity of the raw text it was derived from. A scraper that faithfully extracts clean, well-structured prose gives the downstream chunker the structural signals it needs to produce semantically coherent chunks. A scraper that emits raw HTML soup, or that fails to distinguish between primary content and navigational boilerplate, contaminates the entire corpus with noise that no chunking strategy can fully recover from.</p><p>Furthermore, this is another point of distinction with web search tools. In another article here at the web scraping club, we already covered the <a href="https://substack.thewebscraping.club/i/184656666/why-markdown-is-a-perfect-data-format-for-llms-and-ai-ready-scrapers-use-it-too">importance of feeding LLMs in markdown, rather than in HTML</a>. Based on this, consider that:</p><ul><li><p>Every scraping pipeline can be managed to return data in any format you prefer. It can be a structured JSON, markdown, or anything else.</p></li><li><p>Web search tools go directly to &#8220;read&#8221; the HTML of the target web pages. This means that the LLM responds based also on footers, banners, and anything in between. And this can lead the model to confusion as it responds to users&#8217; queries.</p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>RAG is an architectural commitment and, as such, it must be preceded by a deliberate choice to build a system where outputs are grounded in a controlled and continuously refreshed knowledge base. But that commitment is only as strong as the pipeline feeding it.</p><p>Web search integration tools are not that pipeline. This is because they are optimized for general-purpose queries, not for the precision, governance, and reproducibility that enterprises demand.</p><p>Web scraping, on the other hand, gives you full ownership over what enters the knowledge base, how fresh it is, how it is structured, and how it can be traced back when an output is questioned.</p><p>The next step is to start thinking of your scraping infrastructure not as a standalone data collection tool, but as the retrieval backbone of an intelligent system.</p><p>So, let us know in the comments: are you using web scraping for RAG purposes?</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/rag-pipeline-web-scraping?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/rag-pipeline-web-scraping?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div>]]></content:encoded></item><item><title><![CDATA[THE LAB #112: Intercepting a Website's Internal API Calls]]></title><description><![CDATA[Fifteen tools against two live bot detectors, and only four passed the strict one.]]></description><link>https://substack.thewebscraping.club/p/intercepting-a-website-api</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/intercepting-a-website-api</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Thu, 30 Jul 2026 22:09:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e5f50404-43ab-45fd-acc0-66b5c9cafefa_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my experience, any site that needs to show changing data, like a product catalog or prices that update often, almost never puts that data directly in the HTML. </p><p>Instead, the site loads a basic shell and then fetches the live content from an internal API, usually as JSON, which the frontend then renders. E-commerce sites rely on this approach the most, since stock and prices change all the time and nobody wants to redeploy a page for every update. In fact, this is how modern frontends work.</p><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><blockquote><div><hr></div></blockquote><p>This actually works in our favor. Internal APIs are much more stable targets than the HTML around them. If the site gets a redesign, all your selectors might break, but the JSON endpoint usually stays put because the frontend still needs it. They&#8217;re also easy to spot, since they use regular HTTP in the browser, so you can watch them and see exactly what comes back. The real challenge is finding the right request and figuring out how to reach it past any anti-bot protection.</p><p>I always start by hand, in the browser, because that&#8217;s the best way to build a mental model of the target and keep your skills sharp. After that, I move to code, since clicking around DevTools for every new site gets tedious, and a small interception script can turn a twenty-minute manual search into a quick automated run. For this example, I&#8217;ll use Harrods (<a href="https://www.harrods.com/en-it/">https://www.harrods.com/en-it/</a>) as the target. By the end, we&#8217;ll be pulling the full product catalog straight from the API the frontend uses.</p><h2>Doing it by hand first</h2><p>Open DevTools, go to the Network tab, and filter to Fetch/XHR. That filter drops the images, fonts, scripts, and CSS, and leaves you with the requests the page makes to move data around. On a well behaved site you reload the page, watch a handful of JSON calls show up, and one of them is obviously the product list.</p><div><hr></div><blockquote><p><em>From identifying internal API calls to analyzing structured responses, LLMs are transforming web research. <strong><a href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_llm">anyIP</a></strong> powers the access layer with residential and mobile IPs built for modern web-data workflows.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_llm" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ULXn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ULXn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:915254,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_llm&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/209169884?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ULXn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!ULXn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6204e749-fe63-4afd-a1e3-5be52bb5656d_4585x2292.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_llm&quot;,&quot;text&quot;:&quot;Explore anyIP Proxies &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_llm"><span>Explore anyIP Proxies &#8594;</span></a></p></blockquote><div><hr></div><p>Harrods doesn&#8217;t make it that easy, and the reason is worth understanding because it&#8217;s common. When you load a category page like <code>women-new-in</code>, the products are already in the HTML. The page is server side rendered, so the first response comes back with the grid baked in and no separate product API call fires. If you only look at the initial load, you&#8217;ll conclude there&#8217;s no API and reach for HTML parsing.</p><p>The API is there. It just doesn&#8217;t fire until the page needs new products it doesn&#8217;t already have. So you paginate. Click to page two, and now the frontend has to go get sixty products it doesn&#8217;t have in memory, so it makes the call. This is the habit that pays off most when you hunt internal APIs. You interact with the page and watch what fires. Paginate, filter, sort, scroll. The data call shows up when the page needs data.</p><p>Do that on Harrods with the Network tab open and one request stands out from the analytics noise, a POST to <code>/api/search/1/indexes/*/queries</code>. That path is a giveaway. It&#8217;s the Algolia query API, and we&#8217;ve pulled product data out of Algolia before (<a href="https://substack.thewebscraping.club/p/scraping-algolia-endpoints">https://substack.thewebscraping.club/p/scraping-algolia-endpoints</a>). Harrods proxies it through its own domain instead of calling Algolia directly, which turns out to matter, but the shape is familiar.</p><p>That&#8217;s how I do it manually. It works, and honestly, it teaches you more about the target than any tool. But it&#8217;s slow, and if you need to check ten sites in an afternoon, it just doesn&#8217;t scale. So I automate the search instead.</p><h2>What Harrods actually is</h2><p>Before I run any tool, I like to map out the layers, since each one is a possible failure point.</p><p>The storefront is a Nuxt application, which we can see from the <code>/_nuxt/builds/meta/*.json</code> calls in the traffic. Nuxt server renders the first page and then hydrates into a single page app, which is exactly why the product grid is in the initial HTML but pagination is a client side fetch. Commerce runs on SCAYLE, visible from the <code>hrd-prd.middleware.api.scayle.cloud</code> and <code>hrd-live.cdn.scayle.cloud</code> hosts. Product search is Algolia, proxied through <code>harrods.com/api/search</code>. Currency and pricing for the Italian storefront are handled by Global-e, which shows up as the <code>gepi.global-e.com</code> calls.</p><p>On top of all that, there&#8217;s Akamai Bot Manager. This is the layer you have to get past just to load the page, and it decides if you can even use an automated browser. I&#8217;m not going to reverse engineer Akamai&#8217;s sensor here. That&#8217;s another story. Instead, I&#8217;ll sidestep it using a stealth browser and a warm-up navigation, then focus on the data. For this walkthrough, the real target is the JSON API layer. Akamai is just the wall I need to climb to get there.</p><h2>Building the interceptor</h2><p>The core of the tool is a handler attached to the browser&#8217;s <code>response</code> event. For every response, I check the content type, keep the JSON ones, drop the analytics noise, and save the body. Here&#8217;s the handler, from  <code>intercept.py</code>:</p><pre><code><code>def make_handler(captured, bodies_dir):
    seen = set()

    async def on_response(response):
        try:
            headers = await response.all_headers()
        except Exception:
            return
        ctype = headers.get("content-type", "").lower()
        if not any(m in ctype for m in JSON_MARKERS):
            return
        if is_noise(response.url):
            return

        request = response.request
        base = response.url.split("?")[0]
        key = (request.method, base)
        if key in seen:
            return
        seen.add(key)

        try:
            raw = await response.body()
        except Exception:
            raw = b""
        ...
        print(f"  [json] {request.method} {response.status} {base}  ({len(raw)} B)")

    return on_response</code></code></pre><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><p>For the content type filter, I use <code>application/json</code>, <code>application/ld+json</code>, <code>text/json</code>, and anything ending with <code>+json</code>. To cut out the noise, I block hosts that are almost always analytics or consent, Google, Facebook, OneTrust, Segment, and similar, so they don&#8217;t drown out the real endpoints. I deduplicate by method and path, since hitting a paginated endpoint five times is still just one endpoint. Every response I keep gets its body saved to disk, so I can check the payloads later.</p><p>Attaching it is one line, right after I open the page:</p><pre><code><code>page.on("response", make_handler(captured, bodies_dir))</code></code></pre><p>There are two details that make this work on a real site.</p><p>First, you need a warm up. If you go straight to a deep URL like <code>women-new-in</code>, Akamai will block you, since you&#8217;re asking for an inner page without the cookies a real browser would have collected. So I always load the homepage first, let Akamai set its <code>_abck</code> and <code>bm_sz</code> cookies, wait a bit, and only then go to the category page in the same session.</p><pre><code><code>if warmup:
    print(f"  warmup -&gt; {warmup}")
    await safe_goto(page, warmup, settle_ms * 2)
if await safe_goto(page, url):
    await drive(page, scrolls, settle_ms)</code></code></pre><p>Second, there&#8217;s pagination. From the manual check, I know the product API call only happens when the page needs products it doesn&#8217;t already have. Just navigating to <code>?page=2</code> isn&#8217;t enough, since that triggers another server-rendered load. What you need is a client-side click, just like a real user would do. The most reliable way is to trigger the click through the DOM. Playwright&#8217;s normal click kept timing out on the pagination control.</p><pre><code><code>async def click_through(page, selectors, clicks, settle_ms):
    for selector in selectors:
        for n in range(clicks):
            count = await page.locator(selector).count()
            if not count:
                print(f"  click skipped: {selector} not in DOM")
                break
            await page.evaluate("() =&gt; window.scrollTo(0, document.body.scrollHeight)")
            await page.wait_for_timeout(1000)
            try:
                await page.eval_on_selector(selector, "el =&gt; el.click()")
                print(f"  js-click [{n + 1}] {selector}  (matches={count})")
                await page.wait_for_timeout(settle_ms)
            except Exception as exc:
                print(f"  click failed: {selector} -&gt; {type(exc).__name__}")
                break</code></code></pre><h2>Running it</h2><p>Everything here runs from the shared venv, where Playwright (1.55.0), Camoufox (0.4.11), and <code>curl_cffi</code> (0.14.0) were already installed.</p><p>First the control. Plain Playwright, headless, straight at the category page:</p><pre><code><code>python intercept.py \
  --url "https://www.harrods.com/en-it/women-new-in" \
  --engine playwright --headless --scrolls 3 --out runs/harrods_vanilla</code></code></pre><p>It doesn&#8217;t even get a page back:</p><pre><code><code>playwright._impl._errors.Error: Page.goto: net::ERR_HTTP2_PROTOCOL_ERROR
  at https://www.harrods.com/en-it/women-new-in</code></code></pre><p>That&#8217;s Akamai dropping the connection at the HTTP/2 layer, before any HTML is served. It didn&#8217;t like the TLS and connection fingerprint of an unpatched automated browser. Worth noticing that this is a different failure than a block page. There&#8217;s no &#8220;Access Denied&#8221; body to read, the socket just closes. The control confirms plain Playwright is a non starter on this target, which is the whole reason the control exists.</p><p>Now Camoufox, with the homepage warm up and a click through to page two:</p><pre><code><code>python intercept.py \
  --url "https://www.harrods.com/en-it/women-new-in" \
  --warmup "https://www.harrods.com/en-it/" \
  --click 'a[href="/en-it/women-new-in?page=2"]' --click-times 1 \
  --engine camoufox --scrolls 6 --settle-ms 3000 \
  --out runs/harrods_jsclick</code></code></pre><p>This time the page loads, the title comes back as <code>Designer Women New In | Harrods IT</code>, and the harness prints the JSON calls as they land. Stripping the Akamai sensor beacon and the third party hosts, here&#8217;s what Harrods itself serves as JSON:</p><pre><code><code>GET  200 /_i18n/10acb0d1/en-gb/messages.json            (54186 B)
POST 200 /api/rpc/getUser
POST 200 /api/rpc/getBasket                             -&gt; basket
POST 200 /api/rpc/getWishlist                           -&gt; key,items
POST 200 /api/rpc/getHashedString                       -&gt; hash
POST 200 /api/rpc/getExternalIdpRedirect                -&gt; harrods
GET  200 /_nuxt/builds/meta/d3043d4e-...-631f954ba023.json
POST 200 /api/search/1/indexes/*/queries               -&gt; results  (488909 B)</code></code></pre><p>The <code>/api/rpc/*</code> calls are the storefront&#8217;s own internal RPC endpoints for things like the basket, wishlist, and user session. These are interesting and worth mapping if you&#8217;re modeling the site, but they&#8217;re not what I was after. The last line is the one I wanted: a 488 KB POST to the Algolia proxy, keyed on <code>results</code>, and it only showed up after clicking to page two. On the first load, it wasn&#8217;t there, just like I saw in the manual check.</p><h2>Reading the payoff</h2><p>Here&#8217;s what came back in that response:</p><pre><code><code>top keys: ['results']
result[0] keys: ['hits', 'nbHits', 'offset', 'length', 'facets', 'query', 'index', 'queryID', ...]
index: prod_harrods.com | nbHits: 1199
hits on this page: 60</code></code></pre><p>Sixty products in one call, out of 1199 in the category, from the index <code>prod_harrods.com</code>. Each hit carries what you&#8217;d actually want:</p><pre><code><code>- brand='Rodo'          name='Satin Dafne Slingback Heels 75'   price={'GBP': 79800, 'EUR': 100000, 'USD': 110000, ...}
- brand='Roksanda'      name='Wool Scarf-Tie Isabel Blazer'     price={'GBP': 139500, ...}
- brand='Alessandra Rich' name='Silk Polka-Dot Bow Dress'       price={'GBP': 160000, ...}</code></code></pre><p>You get product id, reference key, name, brand, gender, URL, images, category hierarchy, and price as a map of currencies in minor units. For example, <code>GBP: 79800</code> means &#163;798.00. This is exactly the same data you see in the product grid, but now you can store it directly without having to parse the HTML.</p><p>The reusable part is the request itself. Here&#8217;s the POST body the frontend sent:</p><pre><code><code>{"requests":[{"indexName":"prod_harrods.com","query":"",
  "params":"facets=%5B%22*%22%5D&amp;clickAnalytics=true&amp;ruleContexts=%5B%22EUR%22%5D&amp;maxValuesPerFacet=1000&amp;facetFilters=%5B%5B%22categoryPageIdentifier%3AWomen%20New%20In%22%5D%5D&amp;offset=60&amp;length=60"}]}</code></code></pre><p>If you decode the params, it&#8217;s all clear. The <code>facetFilters</code> with <code>categoryPageIdentifier:Women New In</code> limits the query to this category. <code>offset=60&amp;length=60</code> handles pagination, so page two starts at offset sixty. Change the offset and you can walk through the whole category, sixty products at a time.</p><p>One thing is clearly missing here. There&#8217;s no <code>x-algolia-application-id</code> or <code>x-algolia-api-key</code>, which a direct Algolia call always carries. That&#8217;s because we&#8217;re not calling Algolia, we&#8217;re calling <code>harrods.com/api/search</code>, and the proxy injects the credentials server side. We don&#8217;t need to find or rotate an Algolia key, we just POST to the Harrods path with the cookies our browser already earned.</p><h2>Replaying it to page the whole catalog</h2>
      <p>
          <a href="https://substack.thewebscraping.club/p/intercepting-a-website-api">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Crawl of Fame - July 2026]]></title><description><![CDATA[The rollercoaster of the proxy industry and a a sigh of relief for the industry]]></description><link>https://substack.thewebscraping.club/p/crawl-of-fame-july-2026</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/crawl-of-fame-july-2026</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Mon, 27 Jul 2026 03:00:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e3b04569-100e-4d6d-814f-e10e027c4bf6_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What a month for the proxy and scraping industry: great news, bad news, and companies running to cover. </p><div><hr></div><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><div><hr></div><h2>The rollercoaster inside the proxy industry</h2><p>Residential proxy networks are facing a hard time. <span>After the&nbsp;</span><a href="https://substack.thewebscraping.club/p/google-vs-ipidea-takedown"><span>IPIDEA case</span></a><span>, the F</span><a href="https://substack.thewebscraping.club/p/when-the-fbi-knocks-on-your-proxy"><span>BI targeted NetNut</span></a><span>, one of the biggest names in the industry, and seized their domain&nbsp;</span><strong><span>netnut.io</span></strong><span>,&nbsp;</span><strong><span>proxyjet.io (</span></strong><span>subsidiary company</span><strong><span>)</span></strong><span>, and&nbsp;</span><strong><span>divinetworks.com (</span></strong><span>partner network for IP sourcing).</span> The suspicion is that their residential proxy network was used for fraudulent operations. </p><p>I&#8217;ve worked closely with NetNut, and I don&#8217;t think they&#8217;re directly involved in anything: it&#8217;s a public company, there&#8217;s no need to put their network at a fraudster&#8217;s disposal. But some pieces of the KYC procedures and auditing were probably missing, given that they also had a network of resellers which are harder to control.<br><br>But the hard news is not ending here: following <a href="https://spur.us/blog/smart-tv-apps-residential-proxy-sdks">the Spur research on Smart TVs</a> we shared last month, <a href="https://krebsonsecurity.com/2026/07/lg-to-ban-residential-proxies-from-smart-tv-apps/">LG decided to ban the residential proxy option from their apps on the webOS platform</a>.<br><br>This crusade against residential proxy networks probably will lead to major shifts in the next months (ready to be contradicted).<br></p><ul><li><p>Less supply, higher demand: higher prices and/or worse quality. At least for residential proxies, the price run to the bottom will stop. With demand growing and fueled by AI needs and less supply of IPs, more requests will transit through the same addresses, degrading quality. More providers will try to avoid this by charging more for premium-quality addresses (read: addresses with fewer requests on them).</p></li><li><p>No more easy access to proxies: some companies have already restricted the usage of residential networks to customers who have already completed the KYC process. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3PGE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3PGE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 424w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 848w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 1272w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3PGE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png" width="1456" height="511" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:511,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:101733,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208310760?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3PGE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 424w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 848w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 1272w, https://substackcdn.com/image/fetch/$s_!3PGE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3d0605a-5085-457a-9eb0-5bacd59d2d3b_1736x609.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Bright Data's new KYC screen for residential proxies</figcaption></figure></div><p>In this example, Bright Data is requiring KYC for using residential proxies. Until a few months ago, it was required only when targeting specific websites.</p></li></ul><p>An interesting point of view about this situation can be read in an article from <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Jason Grad&quot;,&quot;id&quot;:1811564,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f775967f-af3d-4436-a2b8-56af06aa8623_385x385.jpeg&quot;,&quot;uuid&quot;:&quot;b017fb72-2798-4392-b0ae-b8fe4224a2e7&quot;}" data-component-name="MentionToDOM"></span> (Massive founder) on this Substack.</p><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:207764139,&quot;url&quot;:&quot;https://jsongrad.substack.com/p/the-web-needs-a-front-door&quot;,&quot;publication_id&quot;:10111198,&quot;embedding_publication_id&quot;:1023328,&quot;publication_name&quot;:&quot;Jason's Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!0UUv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59f55231-b0bf-44d9-9b43-ccb15fc6c1d7_809x809.jpeg&quot;,&quot;title&quot;:&quot;The Web Needs a Front Door&quot;,&quot;truncated_body_text&quot;:&quot;The web&#8217;s original breakthrough was radically low-friction access. CERN released its core technology royalty-free, allowing anyone with an internet connection to publish information, link to others, and build without asking a central platform for permission.&quot;,&quot;date&quot;:&quot;2026-07-20T14:46:57.562Z&quot;,&quot;like_count&quot;:5,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:114641279,&quot;name&quot;:&quot;Jason&quot;,&quot;handle&quot;:&quot;jsongrad&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/59f55231-b0bf-44d9-9b43-ccb15fc6c1d7_809x809.jpeg&quot;,&quot;bio&quot;:&quot;CEO of Massive, a web access infrastructure company. Writing about the open web, who closed it, and how to reopen it.&quot;,&quot;profile_set_up_at&quot;:&quot;2026-07-20T10:05:24.678Z&quot;,&quot;reader_installed_at&quot;:null,&quot;publicationUsers&quot;:[{&quot;id&quot;:10378538,&quot;user_id&quot;:114641279,&quot;publication_id&quot;:10111198,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:true,&quot;publication&quot;:{&quot;id&quot;:10111198,&quot;name&quot;:&quot;Jason's Substack&quot;,&quot;subdomain&quot;:&quot;jsongrad&quot;,&quot;custom_domain&quot;:null,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;My personal Substack&quot;,&quot;logo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/59f55231-b0bf-44d9-9b43-ccb15fc6c1d7_809x809.jpeg&quot;,&quot;author_id&quot;:114641279,&quot;primary_user_id&quot;:114641279,&quot;theme_var_background_pop&quot;:&quot;#FF6719&quot;,&quot;created_at&quot;:&quot;2026-07-20T10:05:49.316Z&quot;,&quot;email_from_name&quot;:null,&quot;copyright&quot;:&quot;Jason&quot;,&quot;founding_plan_name&quot;:null,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;disabled&quot;,&quot;language&quot;:null,&quot;explicit&quot;:false,&quot;homepage_type&quot;:&quot;newspaper&quot;,&quot;is_personal_mode&quot;:false,&quot;logo_url_wide&quot;:null}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null,&quot;status&quot;:{&quot;bestsellerTier&quot;:null,&quot;subscriberTier&quot;:null,&quot;leaderboard&quot;:null,&quot;vip&quot;:false,&quot;badge&quot;:null,&quot;subscriber&quot;:null}}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;,&quot;source&quot;:null}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://jsongrad.substack.com/p/the-web-needs-a-front-door?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web&amp;embedding_publication_id=1023328"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!0UUv!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59f55231-b0bf-44d9-9b43-ccb15fc6c1d7_809x809.jpeg" loading="lazy"><span class="embedded-post-publication-name">Jason's Substack</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">The Web Needs a Front Door</div></div><div class="embedded-post-body">The web&#8217;s original breakthrough was radically low-friction access. CERN released its core technology royalty-free, allowing anyone with an internet connection to publish information, link to others, and build without asking a central platform for permission&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">25 days ago &#183; 5 likes &#183; Jason</div></a></div><h3>A rising tide lifts all boats</h3><p>Luckily, we don&#8217;t have just bad news from the scraping industry. </p><p>After the <a href="https://www.nimbleway.com/blog/announcing-47m-series-b-web-search-agent-platform">Nimble February announcement of a Series B funding round</a> of 47M USD, <a href="https://oxylabs.io/blog/oxylabs-receives-investment">Oxylabs received a 130M USD investment from private equity firm Warburg Pincus</a>.<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://oxylabs.io/blog/oxylabs-receives-investment" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3J0C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 424w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 848w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 1272w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3J0C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif" width="1456" height="764" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:764,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:317256,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/avif&quot;,&quot;href&quot;:&quot;https://oxylabs.io/blog/oxylabs-receives-investment&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208310760?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3J0C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 424w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 848w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 1272w, https://substackcdn.com/image/fetch/$s_!3J0C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49980407-f05e-422d-88d6-979e3fc1be37_2400x1260.avif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The need for data by AI, both for training and in real time, is fueling the industry revenues. <br>But it&#8217;s not just a matter of money; it&#8217;s about being recognized as a crucial technology layer for every business that needs web data.</p><p>Another piece of good news comes from the legal side: <a href="https://serpapi.com/blog/google-v-serpapi-the-court-granted-our-motion-to-dismiss/">Federal Court Grants SerpApi&#8217;s Motion to Dismiss Google&#8217;s DMCA Lawsuit</a>. This is a major win for the web scraping industry, since &#8220;<em>the court rejected Google&#8217;s attempts to expand the DMCA to assert control over access to public pages</em>&#8221;.</p><h2>The Napster era for content</h2><p>I&#8217;m not saying anything new when I state that AI overviews and LLMs&#8217; answers are crunching visits to websites (and, in some cases, hammering them with millions of requests for scraping them). <br><a href="https://www.cloudflare.com/press/press-releases/2026/cloudflare-allows-the-agentic-internet-to-flourish-with-a-simple-philosophy-your-content-your-rules/">Cloudflare recently announced</a> that, by default, &#8220;<em>for new customers and for new sites for existing customers, on September 15, 2026, the defaults will be set to allow for search but block training and agent use for pages with ads</em>&#8221;.</p><p>The idea, which seems good on paper, is to make AI crawlers pay for data to compensate the publisher instead of scraping it. They already announced the Pay-per-crawl protocol some time ago, and this choice goes in the same direction.</p><p>We did the math some time ago, and it doesn&#8217;t make any sense. Those fees should be low enough to make it more convenient to pay instead of bypassing Cloudflare. This means that 99% of website owners won&#8217;t even notice the payment on their bank account. </p><p>I believe we&#8217;re entering the Napster era for online content. Premium content that we don&#8217;t want to be fully cannibalized by AI will be under a paywall. There will always be someone who pays for it and then shares it for free with others; it&#8217;s unavoidable, just like on Napster in the 2000s. Let&#8217;s call this unwanted marketing expenses.</p><div><hr></div><h2>Read and share more of this</h2><p>Want to flag and discover more articles like the ones above? <a href="https://news.thewebscraping.club/">Scraping News</a> (still in beta) is where the community surfaces them. <strong>Sign up</strong> and submit what you find worth reading.</p><p>Want a concept map of everything covered here, cross-referenced with our own work and other sources worth your time? </p><p><a href="https://github.com/TheWebScrapingClub/scraping-wiki/tree/main">The Web Scraping Club Wiki lives on GitHub</a>, and <a href="https://publish.obsidian.md/twsc-public/Web+Scraping/Wiki/README">as an interactive site</a>. It is plain Markdown, so you can also clone it into your own Obsidian vault and read it locally.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Hands-On Guide to SearchApi's Web Search MCP Server]]></title><description><![CDATA[Enable AI agents to access data from major search engines via MCP with SearchApi!]]></description><link>https://substack.thewebscraping.club/p/hands-on-guide-search-api</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/hands-on-guide-search-api</guid><dc:creator><![CDATA[Antonello Zanini]]></dc:creator><pubDate>Sun, 26 Jul 2026 09:15:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4ce62723-400a-48da-9eb1-d54c3105ce7e_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>SearchApi, the popular provider of web scraping APIs for retrieving data from search platforms (and more), has recently released an official remote MCP server. In this complete walkthrough, I&#8217;ll guide you through what the SearchApi Web Search MCP server offers, how to use it, and the scenarios it covers. Follow me!</p><div><hr></div><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><div><hr></div><p></p><h2>An Introduction to SearchApi</h2><p>Before exploring the new MCP offering, let me first introduce you to the world of SearchApi!</p><h3>What Is SearchApi?</h3><p><a href="https://www.searchapi.io/">SearchApi</a> is an online service that provides multiple scraping APIs. It allows you to get data from a wide range of websites, with a strong focus on major search engines.</p><p>SearchAPI endpoints provide programmatically access to real-time data from Google, Bing, and YouTube, as well as platforms like Amazon, Airbnb, Zillow, TikTok, and many others. It handles the underlying infrastructure for you, while also taking care of proxy rotation and bot protections.</p><h3>Main APIs</h3><p>Below is a table of some of the most relevant SearchApi endpoints:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6_8m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6_8m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 424w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 848w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 1272w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6_8m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png" width="1456" height="1871" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1871,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:371992,&quot;alt&quot;:&quot;The main SearchApi endpoints&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/205751434?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The main SearchApi endpoints" title="The main SearchApi endpoints" srcset="https://substackcdn.com/image/fetch/$s_!6_8m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 424w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 848w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 1272w, https://substackcdn.com/image/fetch/$s_!6_8m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b27b110-4860-41e9-80c9-5a3e7e7edf2b_1491x1916.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The main SearchApi endpoints</figcaption></figure></div><p>To discover all endpoints, <a href="https://www.searchapi.io/docs/google">visit the official documentation</a>. On each API page, you can also access the OpenAPI specification, as well as download the Postman collection.</p><h3>Pricing Plans</h3><p>SearchApi follows a pay-per-success pricing model built around monthly subscription plans. These range from developer-level access ($40/mo) to high-throughput enterprise tiers ($5,000/mo), each including monthly search quotas and 99.9% SLA guarantees.</p><p>Pricing decreases with scale, starting at around $4 per 1,000 searches and going down to about $1 per 1,000 at higher volumes. A free trial is also available, offering 100 free requests before committing to a paid plan.</p><h2>Introduction to the SearchApi Web Search MCP Server</h2><p>As a web scraping enthusiast, chances are you&#8217;re already familiar with scraping APIs or SearchApi itself. So, since the company has recently launched a new MCP server product (called <em>Web Search MCP</em>), let me focus on that!</p><h3>How It Works</h3><p>Web Search MCP enables AI models to connect to SearchApi&#8217;s endpoints via a unified interface.</p><p>It&#8217;s a remote-only MCP server that operates over <a href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http">Streamable HTTP</a>. That means you can&#8217;t install it locally. Instead, it runs as a hosted service that your AI client connects via an MCP URL. The server also supports OAuth 2.0, enabling secure authentication.</p><p>Thanks to the OAuth support, you can connect SearchApi to your AI tools through a simple &#8220;Connect&#8221; flow. This way, the AI client can act on the user&#8217;s behalf without ever handling or storing the user&#8217;s API key or password. Access can be revoked at any time from either the SearchApi dashboard or the connected AI platform, giving you full control over permissions.</p><p>Your AI assistant sends requests to the MCP server, which processes them, executes the required actions, and returns structured results in real time. This setup removes the need to manage local infrastructure or dependencies while keeping integration straightforward.</p><p>SearchApi&#8217;s Web Search MCP server can be connected to any tool that supports remote MCP servers via Streamable HTTP, including Claude Desktop, Claude Code, Cursor, and many others. It&#8217;s also available as an official Claude connector.</p><div><hr></div><blockquote><p><strong>S<a href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE">tart your scraping journey with Byteful</a></strong>: 10GB New Customer Trial | Use TWSC for 15% OFF | $1.75/GB Residential Data | ISP Proxies in 15+ Countries</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png" width="630" height="69.35779816513761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1090,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:133037,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/194398731?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;text&quot;:&quot;Claim your 10GB here&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE"><span>Claim your 10GB here</span></a></p></blockquote><div><hr></div><h3>Tools</h3><p>The Web Search MCP server exposes over 80 tools. Some of the most useful ones include:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CRQr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CRQr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 424w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 848w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 1272w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CRQr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png" width="1456" height="3233" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3233,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:867040,&quot;alt&quot;:&quot;Some of the most important tools exposed by the Web Search MCP&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/205751434?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Some of the most important tools exposed by the Web Search MCP" title="Some of the most important tools exposed by the Web Search MCP" srcset="https://substackcdn.com/image/fetch/$s_!CRQr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 424w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 848w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 1272w, https://substackcdn.com/image/fetch/$s_!CRQr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab74f413-2cd4-440f-bdfa-3655b466c909_1490x3308.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Some of the most important tools exposed by the Web Search MCP </figcaption></figure></div><p>Discover all other tools in the <a href="https://www.searchapi.io/integrations/mcp#tools">official docs</a>.</p><h3>Pricing and Limitations</h3><p>Pricing follows the same pay-per-success model as the regular SearchApi APIs, with each MCP tool invocation counting as a single API request. Web Search MCP supports up to 10 MCP integrations per account. Also, standard SearchApi rate limits apply.</p><h2>How to Use the SearchApi Web Search MCP Server in a Real-World Scenario</h2><p>To showcase the SearchApi Web Search MCP Server, I&#8217;ll configure it in Claude Code (though any other compatible MCP tool will work as well) and use it in a sentiment analysis workflow. The goal is to retrieve the latest reviews for a restaurant and let the AI analyze them.</p><p>Follow the instructions below!</p><h3>Prerequisites</h3><p>To follow along with this section, make sure you have:</p><ul><li><p>A <a href="https://www.searchapi.io/users/sign_up">SearchApi account</a> (a free trial account is enough).</p></li><li><p><a href="https://code.claude.com/docs/en/quickstart">Claude Code installed</a> and configured locally.</p></li><li><p>A basic understanding of <a href="https://modelcontextprotocol.io/docs/learn/server-concepts">how MCP works</a>.</p></li></ul><p><strong>Step #1: Create Your MCP Integration</strong></p><p>Start by <a href="https://www.searchapi.io/users/sign_in">logging in to your SearchApi account</a>. From the dashboard, click &#8220;MCP&#8221; under the &#8220;INTEGRATIONS&#8221; section:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TJTd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TJTd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 424w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 848w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 1272w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TJTd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png" width="1456" height="775" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:775,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Selecting the &#8220;MCP&#8221; option&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Selecting the &#8220;MCP&#8221; option" title="Selecting the &#8220;MCP&#8221; option" srcset="https://substackcdn.com/image/fetch/$s_!TJTd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 424w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 848w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 1272w, https://substackcdn.com/image/fetch/$s_!TJTd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb383137-c538-45a0-ad82-cda0ebcf1b5d_3072x1636.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Selecting the &#8220;MCP&#8221; option</figcaption></figure></div><p>Next, select &#8220;Your MCPs&#8221; and click &#8220;New Integration&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gj3e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gj3e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 424w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 848w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 1272w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gj3e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png" width="1456" height="775" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:775,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pressing the &#8220;New Integration&#8221; button&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Pressing the &#8220;New Integration&#8221; button" title="Pressing the &#8220;New Integration&#8221; button" srcset="https://substackcdn.com/image/fetch/$s_!gj3e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 424w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 848w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 1272w, https://substackcdn.com/image/fetch/$s_!gj3e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec45ea78-d8e9-40ea-a7d2-1466b34dd7b5_3072x1636.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Pressing the &#8220;New Integration&#8221; button</figcaption></figure></div><p>You&#8217;ll be taken to the page for creating a new SearchApi Web Search MCP integration. Start by giving your integration a name (e.g., &#8220;Review Bundle&#8221;).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oK2u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oK2u!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 424w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 848w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oK2u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png" width="1456" height="778" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:778,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Giving your SearchApi Web Search MCP integration a name&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Giving your SearchApi Web Search MCP integration a name" title="Giving your SearchApi Web Search MCP integration a name" srcset="https://substackcdn.com/image/fetch/$s_!oK2u!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 424w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 848w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!oK2u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd57373b-2fdd-4f67-b00b-f7c54d860fcc_3072x1642.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Giving your SearchApi Web Search MCP integration a name</figcaption></figure></div><p>Next, either select one of the recommended tool bundles or customize your own. To do so, scroll down, search for &#8220;review,&#8221; and add all review-related tools:</p><ul><li><p><em>Airbnb Property Reviews</em></p></li><li><p><em>Facebook Business Page Reviews</em></p></li><li><p><em>Google Maps Reviews</em></p></li><li><p><em>Tripadvisor Reviews</em></p></li><li><p><em>Walmart Reviews</em></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ak-t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ak-t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 424w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 848w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 1272w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ak-t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png" width="1456" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Selecting the review scraping tools&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Selecting the review scraping tools" title="Selecting the review scraping tools" srcset="https://substackcdn.com/image/fetch/$s_!Ak-t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 424w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 848w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 1272w, https://substackcdn.com/image/fetch/$s_!Ak-t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31eb87c0-f37c-4e81-9f1d-4210545244c1_1826x878.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Selecting the review scraping tools</figcaption></figure></div><p>Now, most review tools require a page URL, place ID, or another entity identifier. To retrieve those automatically, you&#8217;ll also need some search tools.</p><p>For that reason, search for &#8220;Google&#8221; and add:</p><ul><li><p><em>Google Maps Search</em></p></li><li><p><em>Google Maps Reviews</em></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yEB9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yEB9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 424w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 848w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 1272w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yEB9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png" width="1456" height="296" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:296,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Selecting the search tools&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Selecting the search tools" title="Selecting the search tools" srcset="https://substackcdn.com/image/fetch/$s_!yEB9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 424w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 848w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 1272w, https://substackcdn.com/image/fetch/$s_!yEB9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8620835-8cc3-47c7-8c4d-98d7778f66cd_1820x370.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Selecting the search tools</figcaption></figure></div><p>The &#8220;Google Search Light&#8221; tool is fundamental. From the returned search results, AI finds the relevant page URL (e.g., the Tripadvisor page for a specific restaurant), which typically already contains the required identifier or can be used to derive it. This ID or URL can then be passed directly to the corresponding review tools to fetch detailed reviews and structured data.</p><p>Once you&#8217;ve selected all the required tools, click &#8220;Create Integration&#8221; to generate your SearchApi MCP integration. You&#8217;re now ready to connect it to your AI client. Cool!</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3>Step #2: Configure Your SearchApi MCP URL in Claude Code</h3><p>After creating the MCP integration, you&#8217;ll be redirected to your SearchApi MCP page. Here, you can find your MCP URL along with setup instructions for Claude Code, Claude Desktop, and Cursor.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vXvH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vXvH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 424w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 848w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vXvH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png" width="1456" height="790" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:790,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the SearchApi Web Search MCP URL&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the SearchApi Web Search MCP URL" title="Note the SearchApi Web Search MCP URL" srcset="https://substackcdn.com/image/fetch/$s_!vXvH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 424w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 848w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 1272w, https://substackcdn.com/image/fetch/$s_!vXvH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b1cbe-896e-451b-8555-29cead80521b_3026x1642.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the SearchApi Web Search MCP URL</figcaption></figure></div><p>Copy the MCP URL, which follows this format:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">https://www.searchapi.io/mcp?token=&lt;YOUR_SEARCHAPI_MCP_TOKEN&gt;</code></pre></div><p><em><span>&lt;YOUR_SEARCHAPI_MCP_TOKEN&gt;</span></em> is a unique token generated by SearchApi. It identifies your specific MCP integration and is used for authentication.</p><p><strong>Note</strong>: For enterprise integrations and agent platforms that require delegated access, OAuth authentication is the recommended approach.</p><p>Next, add the MCP server called <span>review_bundle</span> to Claude Code using this command:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">claude mcp add review_bundle "&lt;YOUR_SEARCH_API_URL&gt;" --transport http</code></pre></div><p>Make sure to replace the <em><span>&lt;YOUR_SEARCH_API_URL&gt;</span></em> placeholder with the URL you copied from the dashboard. Amazing!</p><h3>Step #3: Verify That the MCP Integration Works</h3><p>Begin by launching Claude Code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">claude</code></pre></div><p>Then run the command below:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">/mcp</code></pre></div><p>This will list all available MCP servers, including <em>review_bundle</em>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t9Ta!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t9Ta!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 424w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 848w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t9Ta!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png" width="1456" height="814" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:814,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the &#8220;review_bundle&#8221; MCP server&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the &#8220;review_bundle&#8221; MCP server" title="Note the &#8220;review_bundle&#8221; MCP server" srcset="https://substackcdn.com/image/fetch/$s_!t9Ta!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 424w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 848w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!t9Ta!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41859477-471a-4105-9fb7-b7b300c94098_3028x1692.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the &#8220;review_bundle&#8221; MCP server</figcaption></figure></div><p>Select the <em>review_bundle</em> server, then choose &#8220;View tools&#8221;. You&#8217;ll see all 7 configured tools:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!58cG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!58cG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 424w, https://substackcdn.com/image/fetch/$s_!58cG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 848w, https://substackcdn.com/image/fetch/$s_!58cG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 1272w, https://substackcdn.com/image/fetch/$s_!58cG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!58cG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png" width="1456" height="210" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:210,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the 7 available tools&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the 7 available tools" title="Note the 7 available tools" srcset="https://substackcdn.com/image/fetch/$s_!58cG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 424w, https://substackcdn.com/image/fetch/$s_!58cG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 848w, https://substackcdn.com/image/fetch/$s_!58cG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 1272w, https://substackcdn.com/image/fetch/$s_!58cG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe59de8a2-c498-4a8d-b3c3-175153e4e232_3030x436.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Note the 7 available tools</figcaption></figure></div><p>This confirms that your Claude Code environment has successfully connected to the remote SearchApi Web Search MCP tools. Perfect!</p><h3>Step #4: Test the Workflow</h3><p>To verify that the MCP integration works for review scraping, try a sentiment analysis prompt like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Get the latest reviews for Sottocasa Pizzeria Harlem in New York from Google Maps and Tripadvisor. Then, generate a sentiment analysis report in Markdown that includes quotes from the retrieved reviews, and save it as reviews.md.</code></pre></div><p>Execute the prompt, and you should see something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eDxG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eDxG!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 424w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 848w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 1272w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eDxG!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif" width="1438" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1438,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Prompt execution in Claude Code&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Prompt execution in Claude Code" title="Prompt execution in Claude Code" srcset="https://substackcdn.com/image/fetch/$s_!eDxG!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 424w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 848w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 1272w, https://substackcdn.com/image/fetch/$s_!eDxG!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea73c144-37c4-4508-a13c-7b2807d9222b_1438x800.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Prompt execution in Claude Code</figcaption></figure></div><p>This is what Claude Code did:</p><ol><li><p>Understood that it first needed to retrieve place IDs.</p></li><li><p>Used google_maps_search and <em>google_light_search</em> to find the Google Maps ID and Tripadvisor ID for the restaurant, respectively.</p></li><li><p>Called <em>tripadvisor_reviews</em> to fetch the latest 15 reviews using the Tripadvisor ID, and <em>google_maps_reviews</em> to fetch 15 recent reviews using the Google Maps ID.</p></li><li><p>Aggregated the retrieved reviews in JSON format and generated a structured Markdown sentiment analysis report with supporting quotes.</p></li><li><p>Exported the final output to <em>reviews.md</em>.</p></li></ol><p><strong>Important</strong>: Claude&#8217;s built-in Fetch and Web Search tools may not reliably achieve this goal due to anti-bot protections on platforms like Google and Tripadvisor.</p><p>The final result is a <em>reviews.md</em> file containing a sentiment analysis based on the latest 15 Google Maps reviews and 15 Tripadvisor reviews for the selected restaurant:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IB_S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IB_S!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 424w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 848w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 1272w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IB_S!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif" width="956" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:956,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The final &#8220;reviews.md&#8221; report&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The final &#8220;reviews.md&#8221; report" title="The final &#8220;reviews.md&#8221; report" srcset="https://substackcdn.com/image/fetch/$s_!IB_S!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 424w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 848w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 1272w, https://substackcdn.com/image/fetch/$s_!IB_S!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe57eddb-4350-4d4a-bb6d-736d750914dc_956x500.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The final &#8220;reviews.md&#8221; report</figcaption></figure></div><p>Notice how the report includes direct quotes from relevant reviews and real-world insights extracted from them. Mission complete!</p><h3>[Extra] Analyze the Output of the Web Search MCP Tools</h3><p>Expand the MCP tool calls made by Claude Code, and you&#8217;ll see:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CKyb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CKyb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 424w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 848w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 1272w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CKyb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png" width="1456" height="687" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:687,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The &#8220;google_maps_search&#8221; tool call&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The &#8220;google_maps_search&#8221; tool call" title="The &#8220;google_maps_search&#8221; tool call" srcset="https://substackcdn.com/image/fetch/$s_!CKyb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 424w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 848w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 1272w, https://substackcdn.com/image/fetch/$s_!CKyb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60e41634-8e5d-4e55-97a7-3aba03de146a_3024x1426.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The &#8220;google_maps_search&#8221; tool call</figcaption></figure></div><p>Notice the use of Google Maps Search to retrieve the Google Maps ID of the target restaurant.</p><p>Similarly, expand the Google Search Light tool call to inspect the JSON SERP returned by SearchApi for the &#8220;Sottocasa Pizzeria Harlem Tripadvisor&#8221; query in the US:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cHfD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cHfD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 424w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 848w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 1272w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cHfD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png" width="1456" height="707" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:707,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The &#8220;google_search_light&#8221; tool call&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The &#8220;google_search_light&#8221; tool call" title="The &#8220;google_search_light&#8221; tool call" srcset="https://substackcdn.com/image/fetch/$s_!cHfD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 424w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 848w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 1272w, https://substackcdn.com/image/fetch/$s_!cHfD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50ed91e0-bf08-4a80-a3b3-5e6ec30e83d5_3028x1470.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The &#8220;google_search_light&#8221; tool call</figcaption></figure></div><p>Next, focus on the Google Maps review scraping step:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gmH3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gmH3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 424w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 848w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 1272w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gmH3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png" width="1456" height="716" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:716,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The &#8220;google_maps_reviews&#8221; tool call&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The &#8220;google_maps_reviews&#8221; tool call" title="The &#8220;google_maps_reviews&#8221; tool call" srcset="https://substackcdn.com/image/fetch/$s_!gmH3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 424w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 848w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 1272w, https://substackcdn.com/image/fetch/$s_!gmH3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe518c6-b7ed-4394-98f1-04becb83ac2b_3018x1484.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The &#8220;google_maps_reviews&#8221; tool call</figcaption></figure></div><p>Note how this returns results in a structured array field (<em>reviews</em>) containing all relevant review data. The same pattern applies to the Tripadvisor review tools:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jgi_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jgi_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 424w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 848w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 1272w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jgi_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png" width="1456" height="702" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:702,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The &#8220;tripadvisor_reviews&#8221; tool call&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The &#8220;tripadvisor_reviews&#8221; tool call" title="The &#8220;tripadvisor_reviews&#8221; tool call" srcset="https://substackcdn.com/image/fetch/$s_!jgi_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 424w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 848w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 1272w, https://substackcdn.com/image/fetch/$s_!jgi_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87c1fcfc-a391-46b6-9e0a-2add49229f63_3022x1458.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The &#8220;tripadvisor_reviews&#8221; tool call</figcaption></figure></div><p>This demonstrates how the SearchApi Web Search MCP enables Claude Code to complete sentiment analysis tasks by providing real-time scraped review data from multiple platforms, returned in a structured format that is easy to process and analyze.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>Other Supported Use Cases</h3><p>Beyond review scraping and sentiment analysis, SearchApi&#8217;s Web Search MCP unlocks a wide range of use cases. These include:</p><ul><li><p><strong>Travel planning and price optimization</strong>: Search flights, hotels, and vacation rentals while comparing prices and availability across dates. AI agents can recommend optimal travel windows and cost-efficient itineraries.</p></li><li><p><strong>Market and ad intelligence monitoring</strong>: Analyze ads across Meta, Google, TikTok, and LinkedIn to track competitor messaging, creative strategies, and campaign activity in real time.</p></li><li><p><strong>E-commerce product research and comparison</strong>: Retrieve product listings, pricing, and reviews across Amazon, Walmart, eBay, Best Buy, and Google Shopping to build product comparison or recommendation systems.</p></li><li><p><strong>Local business discovery and mapping agents</strong>: Use Google Maps and Apple Maps to find places, extract reviews, generate directions, and build location-aware assistants for restaurants, services, or POIs.</p></li><li><p><strong>Social media and brand intelligence tracking</strong>: Fetch public profiles from Instagram, TikTok, and Facebook to monitor influencers, competitors, or brand presence and engagement metrics.</p></li><li><p><strong>News and trend monitoring agents</strong>: Search Google News to track breaking news, industry updates, and topic trends for real-time intelligence dashboards or alerting systems.</p></li><li><p><strong>Educational and research assistants</strong>: Query Google Scholar to retrieve academic papers, legal opinions, and citations for research summarization and knowledge extraction.</p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>I&#8217;ve personally tested MCP servers from various providers in the scraping industry, and the experience with SearchApi&#8217;s Web Search MCP has definitely been smooth.</p><p>I didn&#8217;t encounter any significant issues during setup, and the integration worked immediately. Across the MCP tools I tested, none of the requests failed, which is a strong indicator of reliability and overall quality.</p><p>I&#8217;d therefore recommend it as a solid solution for giving AI agents rich search capabilities across multiple platforms, especially for companies and developers with some budget (given the lack of a free plan).</p><p>I hope you find this post useful. If you have any questions, feel free to reach out in the comments below. Until next time!</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/hands-on-guide-search-api?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading The Web Scraping Club! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/hands-on-guide-search-api?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/hands-on-guide-search-api?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p>]]></content:encoded></item><item><title><![CDATA[THE LAB #111: The OSS browser automation stealth benchmark]]></title><description><![CDATA[Fifteen tools against two live bot detectors, and only four passed the strict one.]]></description><link>https://substack.thewebscraping.club/p/open-source-browser-automation-stealth-benchmark</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/open-source-browser-automation-stealth-benchmark</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Thu, 23 Jul 2026 03:00:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/155e990f-2e5f-4108-ad1c-7c47fc836d2f_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every few months, I see a new &#8220;undetectable&#8221; browser automation library pop up on GitHub. The README always promises the same things: no <code>navigator.webdriver</code>, patched fingerprints, Cloudflare bypasses. These claims are easy to make but hard to verify. If you choose the wrong tool, you might not notice at first. Your scraper keeps running, pages load, but the data slowly turns into soft-blocked junk that looks fine until you actually check it.</p><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><blockquote><div><hr></div></blockquote><p>I wanted a number I could actually trust, not just another marketing claim, and started to write this piece. Then I saw the great work on the Tyler Richards website (<a href="https://richards.foo/tools/stealth-benchmark">richards.foo/tools/stealth-benchmark</a>) and took some inspiration from it.  My idea was to take the open source Python automation stack, point each tool at the same signals a bot detector checks in JavaScript, and score them all the same way. In the past, I have written about anti-detect browsers and fingerprint test pages, but those were about commercial GUI browsers. This time, I focused on the libraries you actually <code>pip install</code> and use in code.</p><p>The whole test harness is <a href="https://github.com/TheWebScrapingClub/thelab">in our GitHub repository reserved for paying users, inside the folder </a><strong><a href="https://github.com/TheWebScrapingClub/thelab">111.</a></strong><a href="https://github.com/TheWebScrapingClub/thelab">STEALTH_BENCHMARK</a>. You can run it yourself and get your own results.</p><h2>The tools I put on the bench</h2><p>I grouped the fifteen tools into families, so the scores are easier to compare.</p><p>My two baselines are plain <a href="https://playwright.dev/python/">Playwright</a> and plain <a href="https://www.selenium.dev/documentation/">Selenium</a>, with no stealth and no patches. These are the control group, and they are supposed to get caught. If a &#8220;stealth&#8221; tool scores the same as vanilla Playwright, that tells you a lot.</p><p>The Playwright stealth patches are <a href="https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python">patchright</a>, <a href="https://github.com/rebrowser/rebrowser-patches">rebrowser-playwright</a>, and <a href="https://github.com/QIN2DIM/undetected-playwright">undetected-playwright</a>. These keep the Playwright API and try to remove specific automation leaks underneath it.</p><p>The CDP-native group is <a href="https://github.com/autoscrape-labs/pydoll">pydoll</a>, <a href="https://github.com/ultrafunkamsterdam/nodriver">nodriver</a>, and <a href="https://github.com/cdpdriver/zendriver">zendriver</a>. They drop WebDriver entirely and talk to Chrome over the DevTools Protocol. nodriver is the official successor to undetected-chromedriver, written by the same author, and zendriver is a maintained fork of nodriver.</p><div><hr></div><blockquote><p><em>Undetectable browsers are getting impressively capable, but even the stealthiest one stalls when its connection lets it down. anyIP&#8217;s residential and mobile proxies pair real-user IPs with 99.9% uptime - so the network is never the weak link</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_4&amp;utm_content=banner_undetectable_browsers" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gs8k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gs8k!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png" width="726" height="363" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:726,&quot;bytes&quot;:962001,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_4&amp;utm_content=banner_undetectable_browsers&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208113514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gs8k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!gs8k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10e0c226-5c6e-45e7-ae8b-b34d38e570f3_4585x2292.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_4&amp;utm_content=banner_undetectable_browsers&quot;,&quot;text&quot;:&quot;Build with anyIP &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_4&amp;utm_content=banner_undetectable_browsers"><span>Build with anyIP &#8594;</span></a></p><p></p></blockquote><div><hr></div><p>Then the browsers that rebuild the fingerprint instead of patching flags on top of a normal Chrome. <a href="https://github.com/daijro/camoufox">camoufox</a> and <a href="https://github.com/feder-cr/invisible_playwright">invisible_playwright</a> are patched Firefox builds that rewrite the fingerprint at the C++ level. <a href="https://github.com/CloakHQ/CloakBrowser">CloakBrowser</a> does the same to Chromium, shipping its own patched binary with a drop-in Playwright API. <a href="https://github.com/rayobyte-data/rayobrowse">RayoBrowse</a> is a self-hosted stealth Chromium from Rayobyte that runs in a Docker container and serves a fingerprint picked from a database of real devices. <a href="https://github.com/h4ckf0r0day/obscura">Obscura</a> is the odd one out, a headless browser engine written in Rust that embeds V8 and ships its own browser rather than driving Chrome at all. And <a href="https://github.com/D4Vinci/Scrapling">scrapling</a> through its StealthyFetcher wraps a stealth Chromium, while <a href="https://github.com/ultrafunkamsterdam/undetected_chromedriver">undetected-chromedriver</a> is patched Selenium.</p><h2>What the detector actually sees</h2><p>A bot detector is not just one thing, so before testing, you have to decide which layer you are actually targeting. In practice, a real detector looks at four main areas: the JavaScript fingerprint surface, the transport (TLS and HTTP/2), request timing, and the proxy exit. For this benchmark, I focused only on the JavaScript fingerprint surface and ignored the rest on purpose.</p><p>This is not about being lazy. Scoping it this way is what keeps the results honest. Transport fingerprinting mostly depends on the browser&#8217;s own network stack, which is the same whether you use Chromium or Firefox, no matter which Python library you use. Timing and behavior are a different topic, more about mouse movement and dwell time. Proxy reputation is about your IP, not your tool. So the real question I can answer by swapping libraries is simple: when a detector&#8217;s JavaScript runs inside the page, what does it actually find?</p><p>The detector looks for a fixed list of tells. Is <code>navigator.webdriver</code> true. Does the user agent say <code>HeadlessChrome</code>. Is the WebGL renderer a software rasterizer like SwiftShader instead of a real GPU. Are there leftover automation globals on <code>window</code>, like the old chromedriver <code>cdc_</code> variables or a framework&#8217;s init scripts. Does the <code>chrome</code> object have the right properties. Do the user agent, <code>navigator.platform</code>, and the Client Hints all agree on the OS. The knowledge base on richards.foo lists hundreds of these, but I pulled the highest severity ones into my own probe.</p><h2>How I set up the test</h2><p>At the core, I use a single HTML page called <code>probe.html</code>, served from a small local server. Each tool loads this page, the page reads its own fingerprint in JavaScript, and writes the result back into the DOM as base64 JSON. I use base64 so I do not run into any HTML-escaping issues when I pull the rendered page from each driver.</p><p>To keep the harness manageable, I wrap every tool, no matter how different its API, in a single method:</p><pre><code><code>def render(url, wait_selector=None, timeout=30000, settle_ms=6000, screenshot_path=None) -&gt; str:
    # launch in the tool's stealth config, goto(url), wait, return final HTML, close</code></code></pre><div><hr></div><blockquote><p><em>The new anti-bot solution - Toughest walls, lowest price. Claim your free 10 000 requests with coupon code WSCLUB</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0jGM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 424w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 848w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png" width="724" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/baf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:724,&quot;bytes&quot;:493234,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208113514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0jGM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 424w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 848w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!0jGM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaf4debc-e56d-4592-992d-02cbb3112a17_2400x1200.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k&quot;,&quot;text&quot;:&quot;Claim your credits&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://scrapeunblocker.com/?utm_source=wsclub&amp;utm_medium=email&amp;utm_campaign=free-10k"><span>Claim your credits</span></a></p></blockquote><div><hr></div><p>Whether it is Playwright sync, Selenium&#8217;s <code>execute_script</code>, pydoll and nodriver&#8217;s async CDP calls, scrapling&#8217;s <code>StealthyFetcher.fetch</code>, CloakBrowser&#8217;s <code>launch()</code>, RayoBrowse over a Docker CDP socket, or Obscura over its Rust CDP server, they all get wrapped by <code>render(url) -&gt; html</code>. I use the same method for the probe and the two oracle pages, so I never have to special-case a driver. Here is the full vanilla Playwright adapter, and it does not get simpler than this:</p><pre><code><code> from playwright.sync_api import sync_playwright

def render(url, wait_selector=None, timeout=30000, settle_ms=6000, screenshot_path=None):
    with sync_playwright() as p:
        browser = p.chromium.launch(channel="chrome", headless=True)
        page = browser.new_page()
        try:
            page.goto(url, wait_until="load", timeout=timeout)
            if wait_selector:
                page.wait_for_selector(wait_selector, timeout=timeout)
            else:
                page.wait_for_timeout(settle_ms)
            if screenshot_path:
                page.screenshot(path=screenshot_path, full_page=True)
            return page.content()
        finally:
            browser.close()</code></code></pre><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><p>For every Chrome-based tool, I used <code>channel="chrome"</code> to drive the real installed Chrome, not Playwright&#8217;s bundled Chromium. This choice is important. Playwright&#8217;s bundled Chromium in headless mode reports a software WebGL renderer (SwiftShader), which is just a headless artifact, not something the tool did. When I point the same tools at real Chrome, the WebGL renderer shows the actual Apple M2 GPU. By using real Chrome everywhere, the tests I measure reflect the tool&#8217;s stealth, not which Chromium binary happened to ship. The engine-level browsers like Camoufox, CloakBrowser, and Obscura ship their own binary, so they use that instead.</p><p>I ran everything in headless mode on purpose, since that is both harder and more common for scraping. Headed mode hides some of these tells automatically, and I mention that where it is relevant.</p><p>I do not just trust my own score, so I use two outside referees. My probe gives a 0 to 100 score by subtracting a weight for each tell the tool leaks. Then I check two open bot-detection pages for an independent verdict: <a href="https://www.browserscan.net/bot-detection">BrowserScan</a> and <a href="https://deviceandbrowserinfo.com/are_you_a_bot">deviceandbrowserinfo</a>. deviceandbrowserinfo is more useful because it returns a JSON breakdown, an <code>isBot</code> flag, and about twenty individual detections like <code>hasWebdriverTrue</code>, <code>isHeadlessChrome</code>, and <code>isAutomatedWithCDP</code>. I tuned the weights in my probe so the ordering matches those verdicts, and that is the calibration step. The runner also saves a screenshot of the deviceandbrowserinfo verdict for every tool, so the human or bot call is on record, not just my parser&#8217;s output.</p><h2>Running it, and what came back</h2><p>Fifteen tools, three targets each, and here is the table the reporter produced.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u4lc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u4lc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 424w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 848w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 1272w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u4lc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png" width="813" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c313fb4-a001-4efb-9e81-359426621665_813x794.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:813,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100053,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208113514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!u4lc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 424w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 848w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 1272w, https://substackcdn.com/image/fetch/$s_!u4lc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c313fb4-a001-4efb-9e81-359426621665_813x794.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>My probe score and the deviceandbrowserinfo verdict matched on 12 out of 13 tools I could get a verdict for, so that is a 92 percent match. I saved the heatmap of every tell by every tool at <code>111.STEALTH_BENCHMARK/results/heatmap.png</code>, and you can see the tiers at a glance.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!apLu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!apLu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 424w, https://substackcdn.com/image/fetch/$s_!apLu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 848w, https://substackcdn.com/image/fetch/$s_!apLu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 1272w, https://substackcdn.com/image/fetch/$s_!apLu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!apLu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png" width="1456" height="907" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cba13293-6327-47b8-9627-921bacd963bb_2142x1335.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:907,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105958,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/208113514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!apLu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 424w, https://substackcdn.com/image/fetch/$s_!apLu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 848w, https://substackcdn.com/image/fetch/$s_!apLu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 1272w, https://substackcdn.com/image/fetch/$s_!apLu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcba13293-6327-47b8-9627-921bacd963bb_2142x1335.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Four tools passed the strict referee: camoufox, CloakBrowser, RayoBrowse, and scrapling. Three of them get there the same way, by rebuilding the browser itself instead of patching automation flags onto a normal Chrome, so there is no <code>HeadlessChrome</code> in the user agent and nothing that reads as CDP automation. scrapling is the fourth, and it passes for a reason worth its own section below, because it took a version bump to get there. Everything that still leaves <code>navigator.webdriver</code> true sits at the bottom of the table, and everything in the middle is one user agent string away from a clean pass.</p>
      <p>
          <a href="https://substack.thewebscraping.club/p/open-source-browser-automation-stealth-benchmark">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The Engineer's Guide to Residential Proxies: From IP Fundamentals to Exit Node Sourcing]]></title><description><![CDATA[Everything an engineer needs to know about residential proxies, ranging from how they work, their types, and where those IPs actually come from]]></description><link>https://substack.thewebscraping.club/p/the-engineers-guide-residential-proxies</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/the-engineers-guide-residential-proxies</guid><dc:creator><![CDATA[Federico Trotta]]></dc:creator><pubDate>Sun, 19 Jul 2026 08:32:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d1f6fc98-d194-4113-b550-c482ad11ec89_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let&#8217;s consider a common scraping scenario. You&#8217;ve been working on a new scraping project for days on a target website that is a heavily protected e-commerce. You launch the scraper to test it, but your first run gets blocked within a few minutes. This is where you try using a datacenter proxy pool because, you know, they are cheap. But the scraper is blocked again.</p><p>Then you get access to a residential proxy pool, and the scraper works.</p><p>If you&#8217;ve been there, you probably moved on without asking why. The adage is simple: if it works, don&#8217;t touch it!</p><p>But that &#8220;why&#8221; matters more than you think because residential proxies aren&#8217;t a kind of black magic. They&#8217;re a specific technical architecture on top of which your scrapers work. And as with any architectural choice, you have to make decisions on purpose and based on specific parameters.</p><p>In this article, you&#8217;ll get a complete technical picture of residential proxies, starting from how IP addresses are classified, how the proxy infrastructure routes your traffic, what residential proxies are, and their common types. In the end, you&#8217;ll also discover the ethics behind residential IP sourcing and how to choose ethical providers with a practical decision framework.</p><p>Let&#8217;s get into it!</p><div><hr></div><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="556" height="278" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p><div><hr></div></blockquote><h2>What Is an IP Address?</h2><p>An IP address (Internet Protocol address) is a numerical label assigned to every device connected to a network that uses the Internet Protocol for communication. On the practical side, the IP protocol serves two core functions:</p><ul><li><p>Host or network interface identification.</p></li><li><p>Location addressing.</p></li></ul><p>The current dominant versions are IPv4 and IPv6:</p><ul><li><p>IPv4 addresses are 32-bit integers, expressed in dotted-decimal notation as four octets ranging from 0 to 255 (for example, <em>203.0.113.47</em>), yielding a theoretical address space of ~4.3 billion unique addresses.</p></li><li><p>Due to exhaustion of this space, IPv6 was introduced, using 128-bit addresses expressed in colon-separated hexadecimal groups (for instance, <em>2001:0db8:85a3:0000:0000:8a2e:0370:7334</em>), offering a space of ~3.4 &#215; 10&#179;&#8312; addresses.</p></li></ul><p>IP addresses aren&#8217;t handed out randomly by providers: there&#8217;s a strict hierarchy that they must respect. Specifically, a global authority called <a href="https://iana.org/">IANA</a> divides the total pool of IP addresses into large blocks and distributes them to regional bodies known as RIRs (Regional Internet Registries). These RIRs then assign smaller blocks to ISPs (your home internet provider) and cloud providers (like AWS or Google Cloud), who finally assign individual IPs to end users and servers.</p><p>Why does this matter for scraping? Because <strong>this entire chain is publicly documented,</strong> and anyone can look up who owns a given IP address using tools like <a href="https://who.is/">WHOIS</a> (a directory of IP ownership records). This means a target website can instantly tell whether your request is coming from a residential IP, a datacenter IP, or a known proxy or VPN provider.</p><p>This is precisely why residential proxies are so valuable in web scraping: their IPs are indistinguishable from those of regular home users, making them much harder for anti-bot systems to flag.</p><div><hr></div><blockquote><p><strong><a href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE">Start your scraping journey with Byteful</a></strong>: 10GB New Customer Trial | Use TWSC for 15% OFF | $1.75/GB Residential Data | ISP Proxies in 15+ Countries</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png" width="630" height="69.35779816513761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1090,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:133037,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/194398731?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;text&quot;:&quot;Claim your 10GB here&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE"><span>Claim your 10GB here</span></a></p></blockquote><div><hr></div><h2>What Is a Proxy Server?</h2><p>A proxy server is an intermediary host that sits between your client and the target web server, forwarding requests and responses on your behalf:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-h-9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-h-9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 424w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 848w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 1272w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-h-9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png" width="813" height="239" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:239,&quot;width&quot;:813,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:78922,&quot;alt&quot;:&quot;Proxy servers&#8217; architecture by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203665222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Proxy servers&#8217; architecture by Federico Trotta" title="Proxy servers&#8217; architecture by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!-h-9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 424w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 848w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 1272w, https://substackcdn.com/image/fetch/$s_!-h-9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72b51d07-75f3-4686-9b58-d0fe8fc03f8f_813x239.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Proxy servers&#8217; architecture</figcaption></figure></div><p>Without a proxy, the TCP connection to the target server is established directly from your machine. With a proxy, your client opens a connection to the proxy, which opens a separate connection to the target, and the target sees the proxy&#8217;s IP address as the request origin. This way, your real IP never appears in the target&#8217;s access logs or network layer.</p><p>This IP substitution is the fundamental value proposition of a proxy in a scraping context. Every request your scraper sends carries a source IP and, as covered above, target servers actively use that IP to make trust decisions. By routing through a proxy, you <strong>externalize your network identity.</strong> This way, the anti-bots on target servers evaluate the reputation, geolocation, and classification of the proxy&#8217;s IP, not yours.</p><p>At the network level, a proxy is simply a process listening on a TCP port, capable of accepting inbound connections and initiating outbound ones. It maintains two separate TCP connections for each proxied request: one with your client and one with the target. These connections are independent: they can use different protocols, different keep-alive settings, and the proxy can pool or reuse the outbound connection across multiple client requests. </p><p>The proxy may also perform additional functions depending on its implementation. For example, it can manage authentication, logging, <a href="https://substack.thewebscraping.club/p/use-ipv6-scraping-nyxproxy">IP rotation (cycling through a pool of IPs across requests)</a>, and header manipulation.</p><h2>Proxy Protocols: HTTP/HTTPS vs. SOCKS5</h2><p>When routing traffic through a proxy, the protocol determines how the proxy handles your traffic at the application and transport layers. This has real implications for scraping purposes. The main protocols are the following:</p><ul><li><p><strong>HTTP/HTTPS</strong>: Proxies that use these protocols operate at the application layer (OSI Layer 7). When your scraping client sends a request through an HTTP proxy, it constructs a full HTTP request and sends it to the proxy server, which forwards it to the target on your behalf. For plain HTTP traffic, the proxy reads the request in full. For HTTPS traffic over an HTTP proxy, the client issues a <em>CONNECT</em> method request, instructing the proxy to establish a raw TCP tunnel to the destination. Once the tunnel is open, the TLS handshake occurs directly between your client and the target server. This means that the proxy becomes a blind pipe and cannot decrypt the payload. This is critical to understand: an HTTP proxy handling HTTPS via <em>CONNECT</em> does not perform SSL termination (unless it&#8217;s explicitly a man-in-the-middle proxy with a custom CA cert injected).</p></li><li><p><strong>SOCKS5</strong>: Is a lower-level protocol operating at the transport layer (OSI Layer 5). Unlike HTTP proxies, SOCKS5 is protocol-agnostic. This means that it simply relays raw TCP (and optionally UDP) streams without any awareness of the application-layer protocol being tunneled. After a brief handshake, the proxy establishes a TCP connection to the destination and shuttles bytes in both directions without inspection. This makes SOCKS5 suitable for any TCP-based protocol, not just web traffic.</p></li></ul><p>One operationally significant detail to consider is DNS resolution. With SOCKS5, the domain name is forwarded to the proxy for resolution, meaning DNS queries originate from the proxy&#8217;s network, not yours. This prevents <a href="https://substack.thewebscraping.club/p/the-stealth-stack-web-scraping#:~:text=following%20main%20mechanisms%3A-,DNS%20leaks,-%3A%20They%20happen">DNS leaks</a>, which can expose your real network location even when your traffic routes through a proxy. HTTP proxies also resolve DNS on the proxy side for <em>CONNECT</em>-tunneled requests, but behavior can vary by implementation.</p><p>Now, here&#8217;s a question for you: for scraping purposes, which protocol is the best? Well, for most scraping use cases, either protocol is functionally equivalent from the target server&#8217;s perspective, since both can tunnel TLS. SOCKS5 is generally preferred for its flexibility and slightly lower overhead, but HTTP proxies are often easier to drop into existing HTTP client configurations without additional dependencies.</p><div><hr></div><blockquote><p><span>Tired of stitching together proxies, browsers, and parsers just to scrape one page? </span><strong><a href="https://gaffa.dev/?utm_source=web_scraping_club&amp;utm_medium=email&amp;utm_campaign=sponsorship&amp;utm_content=homepage"><span>Gaffa</span></a></strong><span> handles the whole stack for you, with the control to fine-tune every step when you need it.</span></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://gaffa.dev/?utm_source=web_scraping_club&amp;utm_medium=email&amp;utm_campaign=sponsorship&amp;utm_content=homepage" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!v6_W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 424w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 848w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 1272w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!v6_W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png" width="664" height="110.81868131868131" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:243,&quot;width&quot;:1456,&quot;resizeWidth&quot;:664,&quot;bytes&quot;:43266,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://gaffa.dev/?utm_source=web_scraping_club&amp;utm_medium=email&amp;utm_campaign=sponsorship&amp;utm_content=homepage&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203665222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!v6_W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 424w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 848w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 1272w, https://substackcdn.com/image/fetch/$s_!v6_W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F061555da-affe-4456-aa1f-c74eff73a1ce_2400x400.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://gaffa.dev/?utm_source=web_scraping_club&amp;utm_medium=email&amp;utm_campaign=sponsorship&amp;utm_content=homepage&quot;,&quot;text&quot;:&quot;Start With Gaffa&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://gaffa.dev/?utm_source=web_scraping_club&amp;utm_medium=email&amp;utm_campaign=sponsorship&amp;utm_content=homepage"><span>Start With Gaffa</span></a></p></blockquote><div><hr></div><h2>What Are Residential Proxies?</h2><p>A residential proxy is a proxy server whose outbound IP address is assigned by a consumer Internet Service Provider (ISP<strong>)</strong> to a real, physical household device like a home router, laptop, smartphone, smart TV, or similar. The word &#8220;residential&#8221; refers directly to the ISP classification of the IP: these are addresses allocated to residential customers, and they appear as such in public IP intelligence databases.</p><h3>How Residential Proxies Work</h3><p>The operational model of a residential proxy network involves three distinct parties: the proxy provider (the company offering proxy servers on the market), the exit node (the residential device), and the scraping client (you).</p><p>The exit node is a real consumer device whose owner has installed software that, in exchange for some compensation, allows the provider to route third-party traffic through their internet connection. This software runs as a background process and registers the device with the provider&#8217;s orchestration infrastructure. The device&#8217;s residential IP is thus made available in the provider&#8217;s pool.</p><p>The provider&#8217;s infrastructure is the backbone that ties everything together. It consists of:</p><ul><li><p><strong>A</strong> <strong>gateway layer</strong>: A set of proxy endpoints that your scraping client connects to. These endpoints are hosted on standard data center infrastructure and serve as the entry point into the residential network.</p></li><li><p><strong>An</strong> <strong>orchestration/routing layer</strong>: The internal system responsible for selecting which residential exit node to use for a given outbound request, based on criteria like target geolocation, session persistence requirements, and node availability.</p></li><li><p><strong>The exit node pool</strong>: The fleet of residential devices registered with the provider, each maintaining a persistent connection back to the orchestration layer.</p></li></ul><p>Thanks to this infrastructure, the scraping requests flow like that:</p><ol><li><p>Your scraping client connects to the provider&#8217;s gateway endpoint and authenticates.</p></li><li><p>The gateway receives your request and passes it to the orchestration layer, which selects an available residential exit node from the pool based on your session&#8217;s parameters.</p></li><li><p>The orchestration layer forwards the request to the selected exit node over the persistent internal tunnel.</p></li><li><p>The exit node&#8217;s software initiates the actual outbound TCP connection to the target server from the residential device&#8217;s IP.</p></li><li><p>The target server receives a request from what appears to be a residential IP, processes it, and returns the response.</p></li><li><p>The response travels back through the same path in reverse: exit node &#8594; orchestration layer &#8594; gateway &#8594; your client.</p></li></ol><p>This is why, from the target server&#8217;s perspective, the only visible connection is the one from the residential exit node. Your client&#8217;s IP, the provider&#8217;s gateway IP, and the internal routing infrastructure are entirely invisible.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>Types of Residential Proxies</h2><p>Residential proxies are segmented into distinct types based on two primary axes: IP persistence (how long you hold the same IP across requests) and targeting granularity (how precisely you can select the exit node&#8217;s location).</p><p>This section reports and describes the common residential proxy categories that are based on those two axes.</p><h3>Rotating Residential Proxies</h3><p>This is the most common type. With rotating proxies, the provider&#8217;s orchestration layer assigns a new exit node&#8212;and, therefore, a new IP&#8212;for each outbound request, or at a configurable interval. From your client&#8217;s perspective, you connect to the same gateway endpoint every time, but each request exits from a different residential IP. This is the default behavior on most residential proxy platforms and is the correct choice for large-scale scraping where you need to distribute requests across a wide IP footprint to avoid per-IP rate limits. Belos is a schema that shows, at a high level, how this process works:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AS8D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AS8D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 424w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 848w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 1272w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AS8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png" width="957" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8695816-0df5-400e-95fd-f25925a6f017_957x428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:957,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:133881,&quot;alt&quot;:&quot;Rotating residential proxies schema by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203665222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Rotating residential proxies schema by Federico Trotta" title="Rotating residential proxies schema by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!AS8D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 424w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 848w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 1272w, https://substackcdn.com/image/fetch/$s_!AS8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8695816-0df5-400e-95fd-f25925a6f017_957x428.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Rotating residential proxies schema</figcaption></figure></div><p>The rotation can be triggered in two ways, depending on the provider:</p><ul><li><p><strong>Per-request rotation</strong>: A new IP is selected for every single HTTP request.</p></li><li><p><strong>Timed rotation</strong>: The same IP is held for a configurable duration before rotating.</p></li></ul><p>In the context of web scraping, the primary tradeoff is that rotating proxies make stateful interactions difficult. If a target website tracks session state via server-side session IDs or cookies tied to an IP, switching IPs mid-session will break the session. So, for purely stateless scraping cases like fetching product pages, search results, and public data, rotation is ideal.</p><h3>Sticky Residential Proxies</h3><p>Sticky proxies allow you to hold the same residential IP for an extended, configurable period<strong>.</strong> This typically ranges from a few minutes up to 30 minutes, depending on the provider, and is bounded by the exit node&#8217;s availability online. The session is maintained by passing a session identifier in your proxy credentials, which instructs the orchestration layer to pin your requests to the same exit node for the duration of the session.</p><p>This type is essential for scraping workflows that require statefulness, like multi-step form submissions, login-based scraping, checkout flows, or any target that correlates sequential requests by IP and invalidates sessions on IP change. The risk is that if the exit node goes offline mid-session (the residential device disconnects from the network, which happens regularly on consumer connections), the session is broken, and the provider will typically reassign you to a new IP. This requires your scraper to handle session recovery; otherwise, your pipelines will break.</p><h3>Static Residential Proxies</h3><p>Static residential proxies (often known as ISP proxies) occupy a middle ground. These IPs are registered to an ISP (giving them a residential-looking ASN and WHOIS classification) but are hosted on stable data center infrastructure<strong>,</strong> rather than actual consumer devices. The provider procures these IPs directly from ISPs and hosts them on servers they control.</p><p>The key advantage over standard rotating residential proxies is stability and speed. Since the IP is hosted on a server rather than a consumer device, it doesn&#8217;t go offline unpredictably, latency is lower, and bandwidth is not constrained by a household connection. You get a fixed, persistent residential-classified IP that behaves like a data center proxy in terms of reliability.</p><p>The tradeoffs are:</p><ul><li><p><strong>Cost</strong>: These are among the most expensive proxy types.</p></li><li><p><strong>Increasing detectability</strong>: As anti-bot vendors are building databases of known static residential/ISP proxy IP ranges, this kind of proxy works as a cat-and-mouse race to escape anti-bots.</p></li></ul><h3>Mobile Proxies</h3><p>Mobile proxies are a specialized subtype where the exit node is a mobile device connected via a cellular network, and the IP belongs to a mobile carrier&#8217;s ASN. These are distinct from standard residential proxies because mobile IPs carry a specific characteristic: mobile carriers use large-scale carrier-grade NAT (CGNAT), meaning a single public IP is shared among potentially thousands of concurrent mobile users.</p><p>This has a profound implication for anti-bot systems: blocking a mobile carrier IP risks blocking thousands of legitimate users simultaneously, making mobile IPs extremely difficult for targets to block without significant collateral damage. As a result, mobile proxies are the hardest proxy type to block and command the highest price per GB in the market. They are most valuable for targets with aggressive anti-bot systems, typically heavily protected e-commerce sites, social platforms, and ad verification use cases.</p><p>The tradeoff is latency and bandwidth variability<strong>.</strong> The exit node is on a cellular connection, which is subject to signal quality, network congestion, and higher round-trip times compared to a wired residential or data center connection.</p><h2>Residential Proxies Types: A Summary Comparison</h2><p>The table below summarizes the subtypes of residential proxies, each with its own specific characteristics:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LmCH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LmCH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 424w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 848w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 1272w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LmCH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png" width="1273" height="672" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:672,&quot;width&quot;:1273,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93154,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203665222?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LmCH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 424w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 848w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 1272w, https://substackcdn.com/image/fetch/$s_!LmCH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cc65955-ab76-407b-af19-a3d555b7e468_1273x672.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h2>How Residential Proxies Are Sourced and Why It Matters</h2><p>The technical sophistication of residential proxy networks is surely interesting for techies. But what&#8217;s also interesting is where the exit nodes actually come from. This is because understanding the sourcing model is not just an ethical exercise. It has direct operational implications for scraping professionals because the legality and reputational standing of the proxies you use can affect your liability exposure and the long-term reliability of your infrastructure. It also has implications for companies working in highly regulated markets, where specific certifications matter more than anything else. <a href="https://substack.thewebscraping.club/p/when-the-fbi-knocks-on-your-proxy">We&#8217;ve seen recently how bad things can go from one day to another if your proxy provider is not fully compliant on both IP sourcing side and customer onboarding</a>.</p><p>As introduced previously, providers build their residential IP pools by recruiting real consumer devices to act as exit nodes. The mechanisms for doing this fall into a spectrum that is described in the subparagraphs below.</p><h3>SDK Monetization</h3><p>The most widespread IP sourcing method is SDK embedding. In this model, a residential proxy provider operates a B2B program where mobile app developers and software vendors integrate the provider&#8217;s SDK into their applications. In exchange, the developer receives a revenue share or a flat fee per active device. When an end user installs the app, the SDK runs in the background and enrolls the device&#8217;s internet connection into the proxy pool.</p><p>The provider&#8217;s SDK typically does the following:</p><ul><li><p>Establishes a persistent outbound connection to the provider&#8217;s orchestration infrastructure.</p></li><li><p>Monitors device state to only proxy traffic when the device is charging and connected to Wi-Fi (to avoid draining battery or mobile data, which would generate user complaints).</p></li><li><p>Throttles bandwidth consumption to stay below the threshold of user noticeability.</p></li><li><p>Handles NAT traversal to make the device reachable for outbound proxy sessions.</p></li></ul><p>The apps embedding these SDKs span a wide range. Just to name a few:</p><ul><li><p>Free VPN clients.</p></li><li><p>File utility apps.</p></li><li><p>Weather apps.</p></li><li><p>Games.</p></li></ul><p>So, the SDK is not the app&#8217;s core function: it&#8217;s the monetization layer that the developer has grafted on.</p><h3>Opt-In Peer Networks</h3><p>Some providers operate a peer model, where users knowingly and explicitly enroll their devices in exchange for a direct benefit. This typically is free access to a premium VPN or bandwidth credits. The consent flow clearly explains that the user&#8217;s connection will be used to route third-party traffic.</p><p>This is the most ethically defensible sourcing model, as the value exchange is explicit and the user retains full awareness of what their device is being used for.</p><h2>Ethical Considerations</h2><p>The ethical landscape of residential proxy sourcing is genuinely complex, and it deserves some treatment to help you discern the right proxy provider to choose.</p><h3>The Consent Problem</h3><p>The foundational ethical issue is informed consent. When a residential device is used as an exit node, its owner&#8217;s internet connection carries traffic for a third party. This means that their IP address becomes associated with requests they did not initiate, to targets they may never have interacted with. If a scraping client uses that exit node to send requests that the target considers abusive, the device owner&#8217;s IP is the one that appears in server logs. The potential consequences for an unknowing participant range from having their IP blacklisted by services they use personally to, in extreme cases, being flagged by automated fraud or abuse detection systems.</p><p>This is why true informed consent in this context is very important. Also, for deep ethical reasons, informed consent would require a clear, plain-language explanation that the user&#8217;s internet connection will relay unknown third-party traffic, that their IP will be the visible origin of that traffic, and that this may affect their IP&#8217;s reputation.</p><h3>Bandwidth and Resource Consumption</h3><p>Enrolling a device in a proxy pool consumes the device owner&#8217;s bandwidth. In many markets, this resource is metered and has a real financial cost. In mobile-heavy markets where Wi-Fi and cellular data are tightly managed household resources, this is a non-trivial extraction of value from the device owner. This is another reason why proxy providers offer rewards to IP owners.</p><h3>The Downstream Use Problem</h3><p>Even when sourcing is fully and clearly consensual, the ethical chain does not end at the exit node: it extends to what the proxy traffic is used for. This is because a residential proxy provider cannot fully control what its clients scrape. This means that the same infrastructure used by a legitimate price monitoring service can be used for credential stuffing attacks, ad fraud, scalping bots, or scraping protected personal data.</p><p>For this reason, responsible providers implement terms of service enforcement, traffic monitoring, and client vetting. As a scraping professional, you are a link in this chain and carry some responsibility for the downstream ethics of the traffic you generate.</p><h3>Legal Exposure</h3><p>The legal status of residential proxy usage varies by jurisdiction and use case. In the United States, the Computer Fraud and Abuse Act (CFAA) has been interpreted broadly to potentially cover unauthorized access to computer systems. And whether bypassing a website&#8217;s IP-based blocks via residential proxies constitutes &#8220;unauthorized access&#8221; has been the subject of significant litigation.</p><p>In the European Union, the GDPR introduces additional complexity when scraped data includes personal information. So, note that using residential proxies does not insulate you from these legal frameworks. It only changes the network-layer attribution of the requests.</p><h2>What to Look For in a Residential Proxy Provider</h2><p>If you&#8217;re new to the scraping industry and need to get residential proxies, you may be overwhelmed by the offers that are on the proxy market. There are a lot of providers out there, and choosing the best one for you may be hard. </p><p>If you want to evaluate providers not only based on budget, the suggestion for you is to primarily make ethical considerations. If you don&#8217;t know where to start, indicators of a responsible residential IP sourcing model include the following:</p><ul><li><p>Published transparency reports detailing how exit nodes are recruited.</p></li><li><p>Clear opt-in documentation and publicly accessible SDK disclosure pages.</p></li><li><p>Active terms of service enforcement against prohibited use cases.</p></li><li><p>Direct compensation models for exit node participants.</p></li><li><p>Compliance certifications<strong>.</strong> Some of the most ethical providers have pursued SOC 2 or ISO 27001 certifications, which indicate a structured approach to operational governance.</p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>Residential proxies are easy-to-use tools, but may be hard to understand. The gap between &#8220;it works&#8221; and &#8220;I know why it works&#8221; is where most engineers live, and it&#8217;s fine until it isn&#8217;t.</p><p>Understanding the full stack changes how you make decisions for your scraping projects. Why? Because it changes how you pick a provider, how you evaluate proxy types for a given target, and how you think about the ethical and legal weight of the infrastructure you&#8217;re routing traffic through.</p><p>So, now that you know how this infrastructure actually works, let us know: does it change how you&#8217;d pick proxies for your next scraping project?</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/the-engineers-guide-residential-proxies?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/the-engineers-guide-residential-proxies?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div>]]></content:encoded></item><item><title><![CDATA[THE LAB #110: Why Shopee is so hard to scrape]]></title><description><![CDATA[Usually, when I dig into an app&#8217;s request signing, I like to end with something practical you can use, like a script, an offline signer, or at least a way to forge a header.]]></description><link>https://substack.thewebscraping.club/p/why-shopee-is-so-hard-to-scrape</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/why-shopee-is-so-hard-to-scrape</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Thu, 16 Jul 2026 21:53:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b596c526-9ef3-4cbc-ad6d-c93e73d4ac25_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Usually, when I dig into an app&#8217;s request signing, I like to end with something practical you can use, like a script, an offline signer, or at least a way to forge a header. This time, though, things turned out differently, and I think that&#8217;s actually more interesting. I tried to tackle Shopee from every angle I know: the native library inside the app, the JSON API behind the website, you name it. Every route hit a different wall. So here&#8217;s my map of those walls, why they hold up, and, to be honest, why I couldn&#8217;t get product data out of any of them.</p><blockquote><p>Give your AI a web data layer &#8211; <strong><a href="https://visit.decodo.com/rE0PQB">Decodo&#8217;s Web Scraping API</a></strong> turns any site into clean, structured data your models can actually use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="556" height="278" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:716985,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><blockquote><div><hr></div></blockquote><p>I&#8217;m picking up where I left off in <a href="https://substack.thewebscraping.club/p/reversing-shopee-app-ghidra">a previous investigation</a>, so I won&#8217;t repeat all the details here. Back then, I pulled <code>libshopeeaegis.so</code> (one of Shopee&#8217;s native crypto libraries) into Ghidra and rebuilt it in Python, byte for byte. That was a straightforward win: just an integer switch over standard AES, SHA, and HMAC, once you get past the intentionally confusing symbol names. But as I mentioned at the end of that article, Aegis is just a general-purpose toolbox, not the actual library that signs API requests. The real signer is a different beast, and that&#8217;s what I&#8217;m looking at now.</p><h2>What actually gates the API</h2><p>Capture any Shopee API request, strip the anti-fraud headers, replay it, and the backend answers with an HTTP error and code <code>90309999</code>. That code is the whole story of this article. It is the anti-fraud rejection, and by the end you will have seen it come back from the app, from a plain HTTP client, and from two different real browsers.</p><p>Two headers carry the protection. On the Java side, two interceptors in okhttp, the HTTP client library the Android app is built on, attach them: <code>com.shopee.app.network.antifraud.b</code> and <code>.d</code>, which name themselves <code>SecurityNewSapInterceptor</code> and <code>SecurityNewSapPostInterceptor</code>. The first header is <code>af-ac-enc-sz-token</code>, a constant for the session:</p><pre><code><code>af-ac-enc-sz-token: ghHLT8yNv0Xd8t9C2/t6Sw==|uJEC5q...JfDCw4ImZS5+gWyOO5Dr...8bd|rsGw3AWMR7Ryh7Jo|08|1</code></code></pre><div><hr></div><blockquote><p><em>The right foundation to keep a smooth scraping workflow. anyIP helps teams collect web data more consistently with high-quality residential and mobile IPs worldwide.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_3&amp;utm_content=banner_scraping" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ro3G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ro3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg" width="574" height="287" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:287,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54790,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_3&amp;utm_content=banner_scraping&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/207213212?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ro3G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ro3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1943b734-365d-40a8-b4c3-04a3296bde99_574x287.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_3&amp;utm_content=banner_scraping&quot;,&quot;text&quot;:&quot;Explore anyIP Proxies &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_3&amp;utm_content=banner_scraping"><span>Explore anyIP Proxies &#8594;</span></a></p></blockquote><div><hr></div><p>This token is a pipe-delimited string: an encrypted device fingerprint, a 16-byte wrapped key, an 81-byte ciphertext, a 12-byte nonce, and two version markers. It&#8217;s computed once per session and then reused. The second header, <code>x-sap-ri</code>, comes with a set of signatures keyed by short hex strings, and these change every request since they&#8217;re computed over the request itself. Both headers are generated by <code>libshpssdk.so</code>, a hefty 4.7 MB native library. The tricky part is the per-request signature, since that&#8217;s the bit you can&#8217;t just precompute and reuse.</p><h2>Finding the signer, and deciding not to port it</h2><p><code>libshpssdk.so</code> exports exactly one symbol, <code>JNI_OnLoad</code>. Everything else is hidden, which tells you the native methods are registered at runtime with <code>RegisterNatives</code>, the Java Native Interface (JNI) call an app uses to bind native functions to Java methods, rather than exported by name. So we catch the registration as it happens. On arm64, <code>RegisterNatives</code> is a slot in the JNIEnv function table at byte offset <code>0x6b8</code>. We hook that slot spawn-gated, before the app&#8217;s own code runs, and read out every method the library registers. The agent is in <code>/shopee_sap_oracle/agent_oracle.js</code>.</p><p>We are after one JNI signature. A request signer takes the request and returns headers, which in JNI terms is two byte arrays in and a string out, <code>([B[B)Ljava/lang/String;</code>. One method matches. It is <code>vuwuuwvw</code>, registered at <code>libshpssdk+0xc7ebc</code>, on the obfuscated class <code>com.shopee.shpssdk.wvvvuwwu</code>, a name we recovered from the <code>jclass</code> argument of the registration call through <code>java.lang.Class.getName()</code>.</p><p>When I opened that address in Ghidra, I found the function itself barely does anything. It just marshals its arguments and passes them to another function, along with a 440-byte blob and a table of function pointers. That&#8217;s the classic shape of a bytecode interpreter: the blob is the program, the pointer table is the opcode handlers, and the real logic lives in the bytecode, not in any native function I can easily read. This is where my earlier approach hits a wall. Last time, I could just read the primitive bodies and match them to AES and SHA. Here, there are no such primitives. To reimplement the signer, I&#8217;d have to reverse and interpret the whole virtual machine (VM), a project that would take weeks and is on the same level as breaking DroidGuard, Google&#8217;s own anti-abuse VM. So instead of porting it, I decided to just call it directly.</p><h2>The one thing that works: the oracle</h2><p>The signer is a Java method on a class we already resolved, so we drive the app&#8217;s own code. The agent exposes one RPC (remote procedure call) export that takes a URL and a body, turns them into the two byte arrays the method expects, and returns whatever the signer returns. The driver (<code>/shopee_sap_oracle/frida_oracle.py</code>) spawns the app, waits for the signer to register, and signs requests we choose. Re-running it against the current app, the signer registers in three seconds and answers:</p><pre><code><code>[SIGN] url=https://mall.shopee.ph/api/v4/native/homepage body={"test":1}
   3c7b6059 = LR4te3nzTKb0RcbDqGs1bsXb0pB=
   71356940 = uMaRB6hpxBCq1BwZ2bFqGXjGFow=
   a0e0dcb3 = WFiutLJdM2C0t5Lr4yaoPr9CLn4=
   eaab58ec = 3BJOkkGhS53kj19RA2QqVLfC1m8sZFLSYm8W8S+Kl3yHU+vuzvb+...   (~2 KB)
   x-sap-ri = d9e7576a26efc4c9896e6716017c0e63cf0cae2c4c560ed7dd03</code></code></pre><div><hr></div><blockquote><p><strong><a href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE">Start your scraping journey with Byteful</a></strong>: 10GB New Customer Trial | Use TWSC for 15% OFF | $1.75/GB Residential Data | ISP Proxies in 15+ Countries</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png" width="630" height="69.35779816513761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1090,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:133037,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/194398731?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;text&quot;:&quot;Claim your 10GB here&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE"><span>Claim your 10GB here</span></a></p></blockquote><div><hr></div><p>That&#8217;s the win, and I want to be clear about what it actually means. I can now produce the exact headers the app would attach for any request I choose, without needing to understand how the signer works under the hood. But before I trust these headers, it&#8217;s worth looking closely at the output, because it gives you a sense of how tough it&#8217;ll be to reuse them. The structural checks I&#8217;m about to show run on the captured values using <code>/shopee_sap_oracle/analyze_headers.py</code>. No device needed.</p><p>The short values look like base64 of a 20-byte digest, which is the length of HMAC-SHA1, so the easy reading is that they are keyed hashes and that is where a first pass leaves them. The easy reading is wrong. Decode seven of them as standard base64, and five come back with non-zero bits in the final padded position, which a conforming base64 encoder never produces from raw bytes:</p><pre><code><code>  6m6r94xGLKAjTMYNMepdMiLQpSB=  len=20  NON-canonical (low2=1)
  wLJO02yz2I+FAZETVwC0aTCflyB=  len=20  NON-canonical (low2=1)
  1iwMbNiaPma2XLT7ToRs4jgiasE=  len=20  canonical
  47WhCSbrTx1r5FdFFlgtpHPN0OO=  len=20  NON-canonical (low2=2)
  LzCPR2/LYpvqP/z1HBXtuzj+8dQ=  len=20  canonical
  vmPAmagMmOlffOGIWF8MwJEBuNT=  len=20  NON-canonical (low2=3)</code></code></pre><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><p>So these aren&#8217;t just plain base64-encoded digests. Either the alphabet is shuffled or there&#8217;s some transformation after encoding, and that&#8217;s exactly the kind of detail that trips up anyone trying to reproduce the signature with HMAC-SHA1 and a standard encoder. The keys themselves are interesting too: within a session, no two requests share a key, and those eight-hex identifiers aren&#8217;t the actual header names you see on the wire. Plus, endpoints with a body return four entries, while GETs without a body return three. There&#8217;s a whole mapping layer from the signer&#8217;s per-request keys to the real header names, and I never managed to reverse that part.</p><p>Then there is <code>x-sap-ri</code> itself. It is 26 bytes: a leading counter, a three-byte session ID, an eight-byte middle field, a <code>01</code> marker at byte twelve, and a thirteen-byte tail. The counter is the interesting part, because it is coarser than it looks. In the fresh capture, both requests came back with counter <code>d9</code> and session <code>e7576a</code> in front, and only the middle and tail differed:</p><pre><code><code>d9 e7576a 26efc4c9896e6716 01 7c0e63cf0cae2c4c560ed7dd03
d9 e7576a b4c3b40323380413 01 d56d3f5c7eaef45395425b9720</code></code></pre><p>So the leading byte isn&#8217;t just a simple counter that increments with each request. What actually separates one request from another is hidden in the middle and tail fields, and the token is tightly bound to the specific request through those parts. That binding is the first reason why a replay fails, and it&#8217;s where the real obstacles begin.</p><h2>App wall one: the replay is out of sequence</h2><p>The obvious next step was to sign a real product request using the oracle and try replaying it from outside the app. I picked a phone case from Shopee&#8217;s public site (<code>shop_id=20396998, item_id=5420033304</code>), had the oracle sign its product detail URL, attached the session&#8217;s <code>af-ac-enc-sz-token</code> and a cookie I grabbed with a one-shot header hook, and replayed the request with <code>curl-cffi</code>. The driver for this is <code>/shopee_sap_oracle/replay.py</code>. Here&#8217;s what Shopee sent back:</p><pre><code><code>[*] oracle signed 4 headers: ['5cfcca02', 'c382fc01', 'cf1e6149', 'x-sap-ri']
==== REPLAY RESULT ====
HTTP 403
{"5":false,"2":false,"0":2,"3":90309999,"error":90309999, ...}</code></code></pre><p>The status code changes depending on the endpoint, but the error code is always the same. Having a valid signature is necessary, but it&#8217;s not enough. This replay was always going to fail for two reasons: first, the <code>x-sap-ri</code> binding ties the token to the device&#8217;s own request sequence, so any injected, out-of-sequence request gets rejected, even with a fresh signature. Second, I put the signer&#8217;s per-request-keyed values under those same eight-hex keys, but I never actually confirmed that&#8217;s how the app names them on the wire. For a clean external replay, you&#8217;d need both of those right, and I could only be sure about one.</p><h2>App wall two: the RASP cancels everything</h2><p>The way to remove both doubts is to stop replaying and make the request from inside the app, where the sequence, the device state, the TLS, and the real header names are already coherent. The app builds its API calls on okhttp, so we went looking for its <code>OkHttpClient</code> at runtime with <code>Java.choose</code>. The probe is in <code>/shopee_sap_oracle/crash_trace.js</code>. There are more than a dozen live instances, and you spot the API client by its interceptors. The antifraud layer is not among the application interceptors where we first looked. It sits lower, among the network interceptors, which run after okhttp has set up the real connection, so it signs the request that is actually about to go on the wire.</p><p>As always, the code that will be used for the python reimplementation we&#8217;re showing now can be found&nbsp;<a href="https://github.com/TheWebScrapingClub/thelab">in our GitHub repository reserved for paying users, inside the folder&nbsp;</a><strong><a href="https://github.com/TheWebScrapingClub/thelab">110.</a></strong><a href="https://github.com/TheWebScrapingClub/thelab">SHOPEE-PART2</a><strong><a href="https://github.com/TheWebScrapingClub/thelab">.</a></strong></p>
      <p>
          <a href="https://substack.thewebscraping.club/p/why-shopee-is-so-hard-to-scrape">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Browser Fingerprinting Deep Dive]]></title><description><![CDATA[How Detection Works and How Scrapers Adapt]]></description><link>https://substack.thewebscraping.club/p/browser-fingerprinting-deep-dive</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/browser-fingerprinting-deep-dive</guid><dc:creator><![CDATA[Dennis Kriukiov]]></dc:creator><pubDate>Tue, 14 Jul 2026 21:02:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/45ca223d-4bc5-4b3b-86ee-5867ae5e23e8_700x250.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is a guest post written by the Infatica team. For an independent benchmark of proxy prices, <a href="https://proxyprice.thewebscraping.club/">visit our Proxy Pricing Benchmark tool</a>.</em></p><div><hr></div><p>If you&#8217;ve run a scraper at any real scale recently, you&#8217;ve felt the shift. The block didn&#8217;t come from too many requests per minute, and rotating to a fresh IP didn&#8217;t fix it. The page just quietly refused to load the data you came for. That&#8217;s fingerprinting doing its job, usually before your first byte of useful content arrives.</p><p>We keep hitting the same pattern. A pipeline that ran fine for months starts returning empty pages or CAPTCHAs, the proxy pool looks healthy, the rate limits are nowhere near tripped, and nothing in the logs explains it. What changed is not how many requests you send. It is how much the target now knows about the client sending them.</p><h2>What browser fingerprinting is, and why it matters for scraping</h2><p>Fingerprinting identifies and tracks a client from the unique combination of characteristics its browser and device expose, with no cookies, no login, and no explicit identifier required. It doesn&#8217;t ask &#8220;who is this user?&#8221; It asks &#8220;does this look like the same client as before, and does this client look real?&#8221;</p><p>The signals are individually boring. Browser version, OS, screen resolution, installed fonts, timezone, locale, how the device renders graphics. None of them identify you alone. Put them together and you get a profile distinctive enough to survive across sessions, IP changes, and incognito mode. For the defense side that&#8217;s a bargain, because one collection step feeds fraud detection, bot detection, rate limiting, and access control at once.</p><h2>From IP-based blocking to identity-based detection</h2><p>The traditional model was simple. Send requests, rotate IPs, stay under the rate limit. As long as each request looked like it came from a different address, you stayed under the radar.</p><p>Fingerprinting breaks that model cleanly. Rotate all the IPs you want, and if your browser fingerprint stays identical across them, you&#8217;ve just told the anti-bot that one client is hiding behind a dozen addresses. No real user does that. It is more suspicious than a single sticky IP would have been. The rotation you relied on becomes the tell.</p><h2>How fingerprinting works under the hood</h2><p>Modern systems don&#8217;t lean on one identifier. They build a layered profile across browser properties, device capabilities, rendering behavior, and network characteristics, then score how coherent the whole thing looks. The more consistent and ordinary the profile, the more trust it earns. That last part is the one most scrapers get backwards, and we&#8217;ll come back to it.</p><h3>Passive signals</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9oS7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9oS7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 424w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 848w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 1272w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9oS7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png" width="700" height="275" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b80faccf-372c-414b-9d2e-15641f688bc1_700x275.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:275,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6531,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204182941?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9oS7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 424w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 848w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 1272w, https://substackcdn.com/image/fetch/$s_!9oS7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80faccf-372c-414b-9d2e-15641f688bc1_700x275.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>These come for free, straight from the HTTP request or a basic JavaScript query, with no heavy lifting required:</p><ul><li><p>User-Agent string (browser, version, OS)</p></li><li><p>Accept headers (language, encoding support)</p></li><li><p>Screen resolution and color depth</p></li><li><p>Timezone and locale</p></li><li><p>Installed fonts and plugins</p></li></ul><h3>Active signals</h3><p>Active fingerprinting runs JavaScript to pull things that are much harder to fake, because they depend on how the hardware actually behaves:</p><ul><li><p>Canvas fingerprinting renders hidden graphics. Tiny differences in font rasterization, anti-aliasing, and GPU instructions produce a distinctive output.</p></li><li><p>WebGL fingerprinting probes the GPU and surfaces details about the graphics hardware and driver stack.</p></li><li><p>AudioContext fingerprinting reads the audio processing pipeline, which varies slightly across systems and adds more entropy.</p></li></ul><p>These matter because they measure behavior, not claims. A User-Agent is just a string you can set to anything. A Canvas hash is the device answering for itself. Spoof the User-Agent but leave the Canvas output screaming &#8220;headless Chromium on a Linux server,&#8221; and the two halves of your story don&#8217;t match.</p><h3>Network-level signals</h3><p>Detection doesn&#8217;t stop at the browser. The network layer sanity-checks the rest of the profile:</p><ul><li><p>IP address and ASN (who owns the network)</p></li><li><p>Geolocation consistency, checking IP against timezone against language</p></li><li><p>TLS fingerprinting (JA3, and increasingly JA4), the shape of your TLS handshake, which most HTTP clients get wrong in a recognizable way</p></li><li><p>HTTP/2 fingerprinting, the frame and settings ordering that Akamai in particular leans on</p></li><li><p>Connection reuse and timing patterns</p></li></ul><p>A browser claiming to be mobile Safari in Spain, connecting from a datacenter ASN with a Python-default TLS handshake, has three independent signals contradicting each other. Any one is forgivable. Together they&#8217;re a verdict.</p><h2>What makes a fingerprint suspicious</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FXl_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FXl_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 424w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 848w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 1272w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FXl_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png" width="700" height="225" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:225,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6368,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204182941?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FXl_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 424w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 848w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 1272w, https://substackcdn.com/image/fetch/$s_!FXl_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6162bddd-cb96-46f5-9cce-73fe375dd4e3_700x225.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Most fingerprints aren&#8217;t obviously fake. They&#8217;re built from real values: common browsers, standard resolutions, familiar operating systems. What anti-bot systems hunt for is how those real values fit together.</p><p>The first giveaway is a mismatch between attributes. Real devices follow predictable patterns. Certain browsers cluster on certain operating systems, resolutions cluster around popular hardware, fonts and rendering align with the platform. A macOS Safari profile serving Windows fonts, or a mobile User-Agent reporting a 2560-wide desktop viewport, breaks that pattern. Each discrepancy is explainable on its own. Stacked together, they aren&#8217;t.</p><p>Then there&#8217;s rarity. A perfectly unique fingerprint feels like good privacy and is terrible for blending in. Real users fall into large, overlapping groups of near-identical configurations. A profile built from attributes that almost never co-occur is both easier to track and quicker to flag. This is the over-randomization trap, and it&#8217;s the most common self-inflicted wound we see. People randomize every parameter and end up with a device that has never existed on Earth.</p><p>Consistency over time counts just as much. Real users are stable, same device, same browser, broadly the same setup from one request to the next. When one fingerprint shows up on an IP in one region and then again on an IP in another, or when key attributes drift between sessions, it reads as synthetic. Several IPs sharing a single identity is a pattern normal traffic just doesn&#8217;t produce.</p><p>Automation leaves its own tells. Even a carefully configured environment leaks something: a missing or stubbed API, a <code>navigator.webdriver</code> flag left on, slightly different JS execution paths, rendering quirks that don&#8217;t match a real build. No single tell is fatal. Detectors collect the small ones until the picture tips toward automation.</p><p>Last comes behavior. A flawless fingerprint still falls apart under robotic behavior. Pages loaded instantly with no intermediate navigation, clicks landing with pixel precision, sessions that fire one request and vanish, all of it undercuts the identity. Online, your identity is as much how you move as how you look.</p><h2>Why fingerprinting breaks the old playbook</h2><p>For years the routine was simple. Rotate IPs, randomize headers, respect rate limits. It worked because defenses were built around request-level signals, mostly where traffic came from and how fast it arrived. Fingerprinting moves the decision from the isolated request to a persistent identity, and most of the old tricks stop paying off.</p><p>Stateless requests became stateful identities. The old model judged each request on its own. Block one IP, grab another, keep going. Fingerprinting adds continuity. Change the IP and the browser environment can still look identical, or inconsistent in ways that link the sessions together. Rotating IPs no longer resets who you are.</p><p>Header randomization stopped working too. Rotating User-Agents and tweaking Accept-Language used to add diversity. Fingerprinting doesn&#8217;t read those values in isolation. It checks whether they agree with each other. Spin up a new User-Agent on every request while your rendering and JS execution stay constant, and you don&#8217;t look like many users. You look like one unstable client lying about itself. Tools like Apify&#8217;s fingerprint-suite and BrowserForge exist because building a coherent set of headers and fingerprint values is harder than randomizing them.</p><p>Datacenter-only setups draw scrutiny. Datacenter proxies are fast, cheap, and easy to rotate, but once the network is part of the identity that stops being free. A datacenter ASN has a different shape than residential traffic, and pairing one with a fingerprint that claims to be a consumer laptop is a contradiction. It won&#8217;t always block you, but it raises the baseline scrutiny, and stacked with any other inconsistency it pushes you over the line. <a href="https://infatica.io/residential-proxies/?utm_source=thewebscrapingclub&amp;utm_medium=guest_post&amp;utm_campaign=fingerprinting_deep_dive&amp;utm_content=residential_proxies_inline">This is why residential and mobile proxies </a>have become table stakes on harder targets, even though they only fix the network half of the problem.</p><p>Detection also moved earlier. Older systems often gave you partial access before a rate limit kicked in. Now the fingerprinting script usually runs the moment the page loads, sometimes before any real content is served. Fail the check and you never reach the data. You get a CAPTCHA, a soft block, or a clean-looking empty response.</p><h2>How to build a setup that survives fingerprinting</h2><p>The goal isn&#8217;t to be invisible. It&#8217;s to be unremarkable, an identity where every layer tells the same ordinary story.</p><h3>Run a real browser engine</h3><p>Lightweight HTTP clients can&#8217;t fake Canvas, WebGL, or AudioContext, because those depend on a real rendering pipeline. So most serious setups drive an actual browser with Playwright, Puppeteer, or Selenium.</p><p>Vanilla automation still leaks, which is where the patched ecosystem comes in. playwright-stealth and puppeteer-extra-plugin-stealth paper over the best-known tells. undetected-chromedriver and its async successor nodriver harden Selenium-style automation, and patchright is a drop-in patched Playwright aimed at the same goal. When you need full managed profiles, anti-detect browsers like Camoufox (open-source, Firefox-based, with fingerprint injection built in), Kameleo, GoLogin, Multilogin, AdsPower, and Dolphin Anty handle the consistency for you. None of these is a magic bullet, since anti-bots study them too, but they clear the low-level signals that plain Playwright fails on day one.</p><h3>Keep each fingerprint internally consistent</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bWRn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bWRn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 424w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 848w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 1272w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bWRn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png" width="700" height="250" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:250,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:9143,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204182941?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bWRn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 424w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 848w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 1272w, https://substackcdn.com/image/fetch/$s_!bWRn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36c912a5-d9a8-4d1b-bbbb-07942d7f2cf6_700x250.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is where over-randomization kills more scrapers than under-randomization ever has. Don&#8217;t change every parameter on every request. Give each session one stable, coherent identity, where the User-Agent matches the OS, the resolution matches the device class, and fonts, language, and timezone all tell the same story. If you generate fingerprints programmatically, lean on something built for coherence, like BrowserForge or fingerprint-suite, rather than rolling your own random values.</p><h3>Align the fingerprint with the network</h3><p>A fingerprint is never judged alone. Claim to be a mobile user in Spain while connecting from a datacenter in another region, and the whole session weakens. Treat proxies as part of the identity layer, not just a source of IPs:</p><ul><li><p>Residential or mobile proxies to match real-user network conditions</p></li><li><p>Geo-targeted IPs so the IP, timezone, and language reinforce each other</p></li><li><p>Session-based (sticky) routing for continuity across a session</p></li></ul><p>And don&#8217;t forget the handshake. If your browser fingerprint is flawless but your TLS fingerprint is a Python default, JA3/JA4 will give you away. curl_cffi, curl-impersonate, and tls-client exist to make that layer match the browser you&#8217;re pretending to be.</p><h3>Treat sessions as isolated identities</h3><p>Each session should behave like its own user, with its own fingerprint, its own IP, and its own cookies and local storage. Don&#8217;t reuse one fingerprint across several IPs at the same time, and don&#8217;t let session state bleed between identities. In practice that means pairing one fingerprint to one IP for the life of a session, then rotating both together, the way a real device and its connection move as a unit.</p><h3>Make the behavior match the identity</h3><p>A perfect fingerprint can&#8217;t save robotic behavior. Real users don&#8217;t teleport onto deep pages, strip the data, and disappear. They land somewhere shallow, navigate, pause, scroll. Adding delays that reflect reading time, and routing through intermediate pages instead of hammering endpoints directly, does more for credibility than another round of fingerprint tuning.</p><h3>Know when to stop building it yourself</h3><p>Maintaining all of this is real, ongoing work, and the targets keep moving. Browser hardening, fingerprint coherence, proxy alignment, session isolation, behavioral pacing, every layer needs upkeep. At some point the maintenance cost outweighs the control you get from it, and pushing these layers down into infrastructure starts to make sense.</p><p>That&#8217;s the niche a managed scraper API fills. Instead of hand-coordinating proxies, browser environments, and anti-detection logic, you hand off the identity layer and keep your code about the data. <a href="https://infatica.io/scraper-api/?utm_source=thewebscrapingclub&amp;utm_medium=guest_post&amp;utm_campaign=fingerprinting_deep_dive&amp;utm_content=scraper_api_inline">Infatica&#8217;s Scraper API</a> is built for that hand-off, with fingerprinting, session management, and request routing handled underneath, so what you maintain is extraction logic rather than evasion logic. It isn&#8217;t the right call for every project, but when anti-detection upkeep starts eating your roadmap, it&#8217;s a trade worth weighing.</p><h2>Where this actually bites</h2><p>Fingerprinting decides what data you can reach, how trustworthy it is, and whether your pipeline survives at scale. Getting past IP filtering is step one. Holding a believable identity for the whole session is the real game, and it&#8217;s where most of the projects we see actually break.</p><p>Price intelligence and travel feel it first. Travel platforms are among the most aggressive adopters. Prices move by location, device, and browsing pattern, so a setup that trips the defenses sees prices real users never see, or different ones every session. A hotel-pricing comparison is only as reliable as the identities behind the requests.</p><p>Search results are another. Search engines read the context of a query, not only the query itself. Weak fingerprinting earns an instant CAPTCHA. To capture what real users in a given region actually see, the requests have to look like they came from real users in that region, on consistent devices.</p><p>E-commerce monitoring runs into the same wall, and we&#8217;ve watched it happen most often on the luxury retailers sitting behind Akamai. Retailers tune availability, pricing, and promotions by user profile, and they use fingerprinting to tell shoppers from bots. Get flagged and you see hidden or reordered listings, throttling, or temporary bans, small distortions that quietly poison competitor-pricing analysis over time.</p><p>Ad verification and market research depend on seeing exactly what a real user sees: ad placement, localized copy, device-specific variants. Fingerprinting interferes by serving fallback content, blocking certain placements, or masking geo-targeted campaigns. That&#8217;s fatal when you&#8217;re validating campaigns across regions.</p><p>Account-based platforms lean hardest on fingerprinting to spot unusual access. These setups tend to fail not on a single request but because the session itself stops looking trustworthy. A sudden device-profile shift, an IP-location jump, or off behavior can each trigger a security check or kill the session.</p><h2>Conclusion</h2><p>Fingerprinting changed the question. It used to be &#8220;where is this request coming from?&#8221; Now it&#8217;s &#8220;does this client hold together as a believable identity, request after request?&#8221; Browser attributes, network signals, and behavior all feed that judgment, and the old reflex of rotating IPs and randomizing headers actively works against you when the layers don&#8217;t agree.</p><p>The setups that hold up aren&#8217;t the ones that randomize the hardest. They&#8217;re the ones that look the most ordinary: one coherent fingerprint, matched to one plausible network, behaving like a real person, held steady for the length of a session. The closer your setup sits to how real users actually browse, the more reliable your data collection becomes, and the more boring, in the best way.</p>]]></content:encoded></item><item><title><![CDATA[How CAPTCHAs Are Evolving to Fight AI-Powered Bots]]></title><description><![CDATA[Is it game over for CAPTCHA solvers?]]></description><link>https://substack.thewebscraping.club/p/how-captchas-are-evolving</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/how-captchas-are-evolving</guid><dc:creator><![CDATA[Antonello Zanini]]></dc:creator><pubDate>Sun, 12 Jul 2026 04:00:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0de69b65-f569-4e56-89bb-12fda53cdc02_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You must have noticed that CAPTCHAs are getting crazier and crazier. What used to be a simple &#8220;What text do you see in this distorted image?&#8221; has turned into a sequence of layered, multi-step, highly interactive verification tasks.</p><p>Fortunately, not all providers have gone in that direction (think of the simple one-click Cloudflare Turnstile). However, many others are designing more intricate mechanisms to counter AI-based automation.</p><p><em>Is this the end of CAPTCHA solvers? And does this impact your scraping script? And how should we interpret these changes overall?</em> Let me introduce you to the new generation of CAPTCHA systems to address all of these questions!</p><div><hr></div><blockquote><p><span>Give your AI a web data layer &#8211; </span><strong><a href="https://visit.decodo.com/rE0PQB"><span>Decodo's Web Scraping API</span></a></strong><span> turns any site into clean, structured data your models can actually use.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/rE0PQB" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png" width="556" height="278" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1024,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:716985,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aRfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 424w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 848w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1272w, https://substackcdn.com/image/fetch/$s_!aRfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ef41f8-3e73-4fa1-a516-a17d90e53e20_1024x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/rE0PQB&quot;,&quot;text&quot;:&quot;Activate starter plan&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://visit.decodo.com/rE0PQB"><span>Activate starter plan</span></a></p></blockquote><div><hr></div><p></p><h2>Why CAPTCHAs Have Become More Sophisticated</h2><p>Before the rise of modern AI, CAPTCHAs could already be solved automatically using traditional machine learning techniques and browser automation. The approach was based on three steps:</p><ol><li><p>Detect the challenge.</p></li><li><p>Recognize its content.</p></li><li><p>Simulate the required user interaction.</p></li></ol><p>For example, <a href="https://arxiv.org/abs/2409.08831">image classification models can identify the correct images in reCAPTCHA v2 </a>(&#8221;Select all images containing hydrants&#8221;):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FqMY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FqMY!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 424w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 848w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FqMY!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif" width="472" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:472,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Letting an ML model solve a reCAPTCHA v2 challenge&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Letting an ML model solve a reCAPTCHA v2 challenge" title="Letting an ML model solve a reCAPTCHA v2 challenge" srcset="https://substackcdn.com/image/fetch/$s_!FqMY!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 424w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 848w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!FqMY!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac6c662a-5512-437f-ba42-bbeea16f824e_472x600.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Letting an ML model solve a reCAPTCHA v2 challenge</figcaption></figure></div><p>(For more details on reCAPTCHA solving, see our previous articles: <a href="https://substack.thewebscraping.club/p/bypassing-recaptcha-v3">Part I</a> and <a href="https://substack.thewebscraping.club/p/bypassing-recaptchas-with-open-source">Part II</a>.)</p><p>Similarly, OCR models could extract text from distorted image-based CAPTCHAs.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F8gB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F8gB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 424w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 848w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 1272w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F8gB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png" width="702" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:702,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Example of a text-based CAPTCHA&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Example of a text-based CAPTCHA" title="Example of a text-based CAPTCHA" srcset="https://substackcdn.com/image/fetch/$s_!F8gB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 424w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 848w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 1272w, https://substackcdn.com/image/fetch/$s_!F8gB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F949d6fa4-0d24-4b1d-937c-0b152786d860_702x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Example of a text-based CAPTCHA</figcaption></figure></div><p>Combined with browser automation, these models were often accurate enough to solve many CAPTCHA challenges without human intervention.</p><p>A good example was <em><a href="https://github.com/Vinyzu/Botright">Botright</a></em>, an open-source browser automation library that integrated machine learning models to solve CAPTCHAs. The project has since been abandoned (its last commit was over two years ago), but it demonstrated how effective this approach could be.</p><p>I&#8217;ve personally tested similar techniques. While they were far from 100% reliable, they were still capable of passing many CAPTCHA challenges.</p><p>CAPTCHA providers have long been aware of these techniques. As automated solvers became more capable, they responded by making CAPTCHAs steadily more intricate. This led to the introduction of puzzle-based challenges, such as those used by AWS WAF CAPTCHA, hCaptcha, and other providers.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jOdq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jOdq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 424w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 848w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 1272w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jOdq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png" width="341" height="462" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:462,&quot;width&quot;:341,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;An example of an AWS WAF puzzle CAPTCHA&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="An example of an AWS WAF puzzle CAPTCHA" title="An example of an AWS WAF puzzle CAPTCHA" srcset="https://substackcdn.com/image/fetch/$s_!jOdq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 424w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 848w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 1272w, https://substackcdn.com/image/fetch/$s_!jOdq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ac56b05-a077-4169-af09-aefcf0a42886_341x462.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An example of an AWS WAF puzzle CAPTCHA</figcaption></figure></div><p>Yet, the rapid advancement of multimodal AI models has raised the bar even further&#8230;</p><p>Instead of training specialized ML models for each CAPTCHA type, LLMs can understand images, reason about what they see, and let the controlled browser interact with the page much like a human would. That has forced CAPTCHA providers to develop more sophisticated techniques to distinguish humans from bots. </p><p>This is where we stand today!</p><h2>Are CAPTCHAs Dead Because of AI?</h2><p>The short answer is: <strong>No!</strong></p><p>While multimodal AI models have fundamentally changed how CAPTCHA providers think about distinguishing human users from automated bots, traditional CAPTCHAs are far from obsolete. There are at least three reasons why:</p><ol><li><p><strong>Not every bot uses AI</strong>: Many scraping bots still rely on traditional browser automation or simple scripts. They don&#8217;t have access to AI tools capable of understanding and solving CAPTCHA challenges.</p></li><li><p><strong>LLMs are not deterministic</strong>: AI models can solve the same CAPTCHA challenge most of the time, but fail spectacularly on others. No wonder you can find examples on Reddit and X of AI-powered browsers repeatedly failing at CAPTCHA challenges.</p></li><li><p><strong>Solving the challenge is only part of the verification process</strong>: CAPTCHA systems usually evaluate much more than just the answer to the test. They also analyze behavioral signals such as mouse movements, cursor acceleration, click timing, scrolling behavior, touch interactions, and many other indicators. That&#8217;s why one-click, press-and-hold, and slider CAPTCHAs exist. An AI model may correctly identify the solution, yet still exhibit interaction patterns that look &#8220;robotic&#8221; rather than &#8220;human,&#8221; causing the verification to fail.</p></li></ol><p>That said, AI is undeniably making life harder for CAPTCHA providers. <a href="https://www.usenix.org/conference/usenixsecurity25/presentation/teoh">Numerous research papers</a> have shown that, given sufficient training data and realistic browser automation techniques (such as human-like mouse movements, scrolling, and timing), AI systems can successfully solve many traditional CAPTCHA schemes.</p><p>The real question is no longer whether AI can solve older CAPTCHAs, as it clearly can. The more interesting question is: <em><a href="https://substack.thewebscraping.club/p/bypassing-hcaptcha-llm">Can it reliably solve the new generation of AI-resistant CAPTCHAs?</a></em></p><h2>New Approaches to AI-Resistant CAPTCHAs</h2><p>More and more CAPTCHA providers are experimenting with advanced challenges specifically engineered to resist AI-powered solvers.</p><p>In this section, I&#8217;ll focus on three approaches to newer CAPTCHAs that I&#8217;ve personally seen challenge even some of the most popular CAPTCHA-solving solutions.</p><h3>hCaptcha&#8217;s New Puzzle-Based Challenges</h3><p>hCaptcha has always been one of the more difficult CAPTCHA providers to bypass, thanks to its creative human verification tests.</p><p>As AI capabilities have advanced, hCaptcha has responded by introducing elaborate puzzles purpose-built to thwart automated solving:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8q6C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8q6C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 424w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 848w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8q6C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png" width="1225" height="1506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1506,&quot;width&quot;:1225,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Examples of recent hCaptcha puzzle-based challenges&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Examples of recent hCaptcha puzzle-based challenges" title="Examples of recent hCaptcha puzzle-based challenges" srcset="https://substackcdn.com/image/fetch/$s_!8q6C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 424w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 848w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!8q6C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70c24751-745c-42df-bfec-b519bd1e351b_1225x1506.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Examples of recent hCaptcha puzzle-based challenges</figcaption></figure></div><p>Notice how many of these challenges require much more than simply clicking on the correct images. They can involve drag-and-drop interactions, spatial reasoning, and specific knowledge.</p><div><hr></div><blockquote><p><em>Instead of fighting every CAPTCHA, focus on avoiding them. <strong>anyIP</strong> gives you access to high-quality residential and mobile proxies that help your traffic blend in more naturally.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_captcha" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sgdX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sgdX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png" width="590" height="295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:590,&quot;bytes&quot;:913094,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_captcha&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204450518?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sgdX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 424w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 848w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!sgdX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb21eff47-47c6-4800-be91-cb5baecdb729_4585x2292.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_captcha&quot;,&quot;text&quot;:&quot;Start with AnyIP&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://anyip.io/?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_2&amp;utm_content=banner_captcha"><span>Start with AnyIP</span></a></p></blockquote><div><hr></div><h3>Microsoft&#8217;s Multi-Option CAPTCHAs</h3><p>Explore the Microsoft forums and Reddit, and you&#8217;ll find plenty of users complaining about Microsoft&#8217;s newer human verification challenges (<a href="https://learn.microsoft.com/en-in/answers/questions/2289029/insane-captcha-6-times-x-10-tasks-and-doesnt-pass">example 1</a>, <a href="https://www.reddit.com/r/LinusTechTips/comments/1omalh3/hey_microsoft_this_captcha_is_one_of_the_worst/">example 2</a>, <a href="https://learn.microsoft.com/en-in/answers/questions/2289029/insane-captcha-6-times-x-10-tasks-and-doesnt-pass">example 3</a>). Here are a few examples:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FmoW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FmoW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 424w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 848w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 1272w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FmoW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png" width="1456" height="1387" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1387,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Microsoft&#8217;s new multi-option CAPTCHAs&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Microsoft&#8217;s new multi-option CAPTCHAs" title="Microsoft&#8217;s new multi-option CAPTCHAs" srcset="https://substackcdn.com/image/fetch/$s_!FmoW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 424w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 848w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 1272w, https://substackcdn.com/image/fetch/$s_!FmoW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8790bf-92fe-4646-9f60-a8f84b7d73fa_1868x1779.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Microsoft&#8217;s new multi-option CAPTCHAs</figcaption></figure></div><p>These challenges can be somewhat ambiguous. They tend to present multiple plausible answers, require you to search through numerous options, and may involve several consecutive steps before the verification is complete. As a result, they take considerably longer to solve and can be frustrating for legitimate users (especially if a mistake forces them to restart the entire challenge).</p><h3>Temu&#8217;s Proprietary CAPTCHAs</h3><p>Some platforms are moving away from standard CAPTCHA providers and building their own verification systems in-house. A notable example is Temu, which has recently introduced a restrictive, custom CAPTCHA mechanism:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R1hb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R1hb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 424w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 848w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 1272w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R1hb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png" width="815" height="1092" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1092,&quot;width&quot;:815,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Examples of Temu&#8217;s CAPTCHAs&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Examples of Temu&#8217;s CAPTCHAs" title="Examples of Temu&#8217;s CAPTCHAs" srcset="https://substackcdn.com/image/fetch/$s_!R1hb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 424w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 848w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 1272w, https://substackcdn.com/image/fetch/$s_!R1hb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94eb01ed-bc62-4d70-8cb0-67d57d1487d1_815x1092.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Examples of Temu&#8217;s CAPTCHAs</figcaption></figure></div><p>These challenges go beyond simple image selection and require very specific actions. For instance, they can involve multi-step interactions such as drag-and-drop tasks or slider-based tests that must be completed in a precise way.</p><p>What they generally have in common is the heavy use of AI-generated images. This creates an interesting dynamic: <em>AI is being used to produce the very content to stop AI-powered bots.</em></p><h3>The Future of CAPTCHA: What Comes Next</h3><p>While these new CAPTCHA challenges are definitely more difficult for AI to solve, it&#8217;s still unclear whether AI will evolve quickly enough to keep up in the ongoing arms race between <a href="https://substack.thewebscraping.club/p/the-evolving-career-scrapers">scraping developers</a> and CAPTCHA-protected websites.</p><p>What&#8217;s clear is that providers will continue experimenting&#8230;</p><h3>Hand-Gesture CAPTCHAs</h3><p>Hand-gesture CAPTCHAs represent a shift from traditional image-based verification toward real-world interaction signals.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mibw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mibw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mibw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg" width="1200" height="896" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:896,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;New Google reCAPTCHAs based on hand gestures&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="New Google reCAPTCHAs based on hand gestures" title="New Google reCAPTCHAs based on hand gestures" srcset="https://substackcdn.com/image/fetch/$s_!Mibw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mibw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa8be0fa-37a3-4ced-b703-2bb1927ef246_1200x896.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">New Google reCAPTCHAs based on hand gestures</figcaption></figure></div><p>Google has recently begun testing a new reCAPTCHA system that asks users to prove they&#8217;re human by performing simple hand gestures in front of their device camera.</p><p>When enabled, the browser requests camera access and records a short video of the user&#8217;s hand movement. The system then analyzes the footage by extracting around 21 hand-landmark points (measurements of finger and joint positions) to identify specific gestures.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9k5a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9k5a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9k5a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg" width="640" height="426" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:426,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Making simple hand gestures in front of a camera&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Making simple hand gestures in front of a camera" title="Making simple hand gestures in front of a camera" srcset="https://substackcdn.com/image/fetch/$s_!9k5a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9k5a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F628af754-1621-4429-99fb-e0cae7390f32_640x426.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Making simple hand gestures in front of a camera</figcaption></figure></div><p>This is an attempt to improve &#8220;liveness detection,&#8221; making it harder for automated systems to pass as real users. Still, it&#8217;s not impossible that AI-driven tools could eventually simulate these gestures using AI-generated videos via camera injection.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3>Stronger CAPTCHAs, Worse User Experience?</h3><p>Newer CAPTCHAs are significantly harder for AI to pass, but they also introduce a new layer of friction for us, the everyday users. That&#8217;s the main trade-off in the current wave of anti-AI verification systems.</p><p>As models become more capable, CAPTCHAs are forced to evolve in parallel, often becoming more demanding not only for bots but also for legitimate users.</p><p>As a result, many users have been complaining on Reddit and X about frustration, increasingly time-consuming challenges, and <a href="https://www.reddit.com/r/degoogle/comments/1ubocbe/google_is_testing_a_new_recaptcha_system_that/">privacy concerns</a> (such as having to use a camera just to complete a CAPTCHA).</p><p>This has led to growing criticism that could eventually push providers to relax some of these verification mechanisms, either by making them easier or less frequent (which would be a win-win scenario for web scraping).</p><p>It&#8217;s quite clear that the real objective is finding a balance between effectively blocking bots and avoiding unnecessary friction for legitimate users.</p><h3>Are These New CAPTCHAs Effective Against AI?</h3><p>These newer CAPTCHAs aren&#8217;t becoming more elaborate simply for the sake of increasing difficulty. Providers are well aware that the probability of AI reliably passing these checks at scale remains low, though not zero.</p><p>The idea is to design challenges that are intricate enough to deter automation, while still incorporating sufficient interaction signals and behavioral data to assess whether the user is actually human.</p><p>In essence, beneath the surface, the core principle hasn&#8217;t fundamentally changed. What we are seeing is an evolution in execution, rather than a reinvention of the underlying idea.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>Avoiding CAPTCHAs Remains More Effective Than Solving Them</h3><p>The final question is: &#8220;Should these new CAPTCHAs scare us, web scraping experts/enthusiasts?&#8221; In a sense, they might, but ultimately this is not really a revolution&#8230;</p><p>The truth is that in web scraping, the most effective strategy is rarely about solving CAPTCHAs. Instead, it&#8217;s about avoiding them altogether.</p><p>CAPTCHA systems are just one layer of a <a href="https://substack.thewebscraping.club/p/anti-detect-anti-bot-matrix">broader anti-bot ecosystem</a>, and triggering them is a signal that the traffic is already considered low-trust or detectable.</p><p>For this reason, the focus should be on prevention rather than resolution. Best practices involve:</p><ol><li><p>Routing traffic through high-quality <a href="https://substack.thewebscraping.club/p/what-is-a-residential-proxy">residential proxy networks</a> with strong reputation IPs.</p></li><li><p>Using stealth browser environments such as <a href="https://substack.thewebscraping.club/p/kameleo-docker-exploring-the-docker">Kameleo Docker</a>, <a href="https://substack.thewebscraping.club/p/is-camoufox-still-effective-scraping">Camoufox</a>, or <a href="https://substack.thewebscraping.club/p/rayobrowse-browser-scraping">Rayobrowse</a>.</p></li><li><p>Managing and rotating browser sessions in automated scraping workflows.</p></li></ol><p>The end goal is to consistently emulate real, human-like browsing behavior to minimize the chances of detection. If human verification tests still appear, CAPTCHA solvers will remain the go-to option, as they must evolve to keep up with new challenges in order to stay in business.</p><div><hr></div><p>The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p><div><hr></div><h2>Conclusion</h2><p>In this post, you&#8217;ve understood why CAPTCHAs have become more sophisticated and the role AI has played in this evolution. You&#8217;ve also seen what providers like hCaptcha, platforms like Microsoft, and sites like Temu are doing to defend against AI-powered automated scrapers and bots, as well as what the future of CAPTCHAs might look like.</p><p>I hope you now have a clearer understanding of the current and future CAPTCHA landscape. If you have any questions, feel free to leave them in the comments below. Until next time!</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/how-captchas-are-evolving?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/how-captchas-are-evolving?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[When the FBI Knocks on Your Proxy Provider's Door ]]></title><description><![CDATA[My Thoughts on the NetNut Takedown and What It Means for Us in Web Scraping]]></description><link>https://substack.thewebscraping.club/p/when-the-fbi-knocks-on-your-proxy</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/when-the-fbi-knocks-on-your-proxy</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Thu, 09 Jul 2026 20:46:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/309ad261-46b9-4c83-9e4f-48437b24fc91_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you tried to log in to <strong>netnut.io</strong> recently, you probably noticed something unusual. Instead of the usual dashboard, there was an FBI seizure banner staring back at you.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yj5F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yj5F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 424w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 848w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yj5F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png" width="1456" height="851" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:851,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2185706,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/206054175?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yj5F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 424w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 848w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!yj5F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1d3f70a-a0aa-4c98-98ea-263d6f38013e_2578x1506.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>On July 2nd, the FBI, together with several industry partners, seized hundreds of domains tied to NetNut. For those who don&#8217;t know, NetNut is a large residential proxy service run by Alarum Technologies, a company that&#8217;s even listed on NASDAQ. The seized domains included <strong>netnut.com</strong>, <strong>proxyjet.io</strong>, and <strong>divinetworks.com</strong>. </p><p>This didn&#8217;t come out of nowhere. Let me walk you through how we got here, because the timeline is important to understand what happened.</p><h3>How the takedown happened</h3><p>It all started on June 19th, when <a href="https://krebsonsecurity.com/2026/06/popa-botnet-linked-to-publicly-traded-israeli-firm/">three security firms published reports</a> showing that NetNut&#8217;s residential proxy network was actually powering a botnet called Popa. The software was running on everyday devices like smart TVs and streaming boxes. Qurium, one of the security firms, stumbled onto this while looking into some denial-of-service attacks and traced the control servers back to pirated streaming apps. Then Brian Krebs made the story public, and about two weeks later, the authorities stepped in.</p><p>The takedown was a team effort: Google, the FBI, Lumen Technologies, The Shadowserver Foundation, and others all played a part. This is where things get interesting from a technical perspective, because taking down a proxy network is nothing like just unplugging a server.</p><p>Residential proxy networks are built to be decentralized. The exit nodes are actually millions of consumer devices scattered all over the world. Google estimated that NetNut had at least 2 million devices in its network. Obviously, you can&#8217;t just go and seize someone&#8217;s smart TV. What you can do is target the things those devices rely on to function as part of a commercial proxy service.</p><p>First, there&#8217;s the command and control layer. Google shut down the accounts and services that NetNut was using to control the malware. What I found interesting is that this C2 infrastructure was actually running on Google&#8217;s own services. This technique, called &#8216;living off trusted services,&#8217; lets malicious traffic blend in with normal cloud traffic. Without command and control, there&#8217;s no way to route customer traffic through those devices.</p><p>Next is the enrollment pipeline. Google Play Protect began warning users and disabling apps that included NetNut SDKs, and it will keep blocking any new installs. If a proxy network can&#8217;t add new devices, it starts to shrink over time, since devices get reset, replaced, or just go offline.</p><p>Then there&#8217;s the commercial front door. By seizing the main domains, the FBI basically shut down NetNut&#8217;s storefront and made it impossible to bring in new customers at scale.</p><p>All of this together, according to Google, cut down the number of available devices by millions and seriously hurt NetNut&#8217;s business.</p><h3>What makes this case different</h3><p>I&#8217;ve seen proxy networks get taken down before, but NetNut is different. This wasn&#8217;t some anonymous group hiding on the dark web. NetNut was run by a company listed on NASDAQ, with investor relations, quarterly reports, and even a legal team that put out a statement saying they were aware of the seizure and cooperating with investigators.</p><p>It must be said that Alarum has rejected the accusations, disputing their accuracy. On the commercial and official side, NetNut has always presented itself exclusively as a legitimate proxy provider for enterprise data collection, without ever declaring any kinship with the clandestine Popa botnet. In its communications following the seizure, the company stated that neither Alarum nor NetNut had been formally contacted by the FBI or any other governmental authority in connection with these matters, while temporarily suspending data traffic through the affected network services in order to investigate the incident and assess the infrastructure involved. Markets, however, delivered their own verdict quickly: Alarum&#8217;s stock crashed by more than 70% at the end of last week, bringing its market cap down roughly 96% from its 2024 peak, and the company itself warned that prolonged disruptions are expected to have a material adverse effect on its operations and financial results.</p><p>It&#8217;s important to be clear about which part of NetNut&#8217;s network is involved here, because NetNut wasn&#8217;t just selling one type of proxy. They offered rotating residential proxies, static ISP proxies, mobile proxies, and regular datacenter proxies. Datacenter IPs are the least controversial, since they come from cloud and hosting providers with clear ownership. The takedown focused on the residential side, where NetNut actually used two very different sourcing models.</p><p>On one side there are the ISP proxies, sourced through DiviNetworks,  the company NetNut originally grew out of. This is an above-board arrangement: as Spur documented in its research on how proxy providers co-opt entire networks, DiviNetworks recruits ISP partners with a straightforward revenue-stream pitch, terminates a GRE tunnel on the partner&#8217;s edge router, installs software on a VM inside the partner network, and uses policy-based routing to steer a slice of traffic through that VM and back out through NetNut&#8217;s infrastructure. From the partner&#8217;s perspective, a small amount of traffic is diverted; from NetNut&#8217;s perspective, selected egress from the partner&#8217;s public IP space becomes a commercial proxy product. The ISPs sign an agreement and get paid. You can argue about whether their subscribers know, but at least the contractual chain is in daylight.</p><p>The other side is the residential proxy pool, and this is where the Popa botnet comes into play. Researchers found that NetNut built this network by distributing SDKs for devices like smart TVs and streaming boxes. Synthient looked at over 20 real Popa publishers and didn&#8217;t see any of them asking users for consent. This is the part of the network that led to the takedown. When you have two million devices enrolled without real consent, that&#8217;s not a legitimate proxy network; it&#8217;s a botnet with a billing system, at least from a law enforcement point of view.</p><p>But the fact that divinetworks.com was seized along with the other domains tells me that investigators aren&#8217;t making a clear distinction between the different parts of the business. Even providers who think their sourcing is clean should take note.</p><h3>This isn&#8217;t just a one-off event; it&#8217;s part of a bigger pattern</h3><p>If this all sounds familiar, it&#8217;s because we&#8217;ve seen it before, and not long ago. The NetNut takedown follows <a href="https://substack.thewebscraping.club/p/google-vs-ipidea-takedown">right after Google&#8217;s disruption of the IPIDEA proxy network back in January 2026</a>. At the time, IPIDEA was one of the biggest residential proxy operations out there, and NetNut&#8217;s main competitor.</p><p>Google&#8217;s post-mortem on IPIDEA included what I think is the key point here: when their own botnet starts to fall apart, proxy operators just buy capacity from competitors and become resellers. The proxy industry is tightly connected, and Google is pretty confident that a lot of popular residential proxy brands were actually just reselling NetNut&#8217;s botnet.</p><p>If you buy residential proxies from a brand you haven&#8217;t really checked out, pay attention. The IP pool behind your provider&#8217;s logo might be NetNut&#8217;s, or IPIDEA&#8217;s, or whoever is next in line.</p><p>The timing here is no accident. Bot traffic is exploding, especially with AI agents and LLM-based crawlers on the rise. In all my years doing this work, I&#8217;ve never seen web scraping infrastructure get this much attention from regulators and platforms. We&#8217;re in a real bind: we need more scraping and automation than ever, which means more proxies, but at the same time, there&#8217;s a real push for transparency about how these networks are built and used, so we can tell the good actors from the bad.</p><p>The lesson from NetNut is that just being transparent about where your IPs come from isn&#8217;t enough. You also need to know who is actually using your network. Alarum said they did KYC and due diligence on NetNut&#8217;s customers, but Spur found that NetNut didn&#8217;t really require corporate verification or real know-your-customer checks before selling proxy access. Down the line, resellers and white labelers usually didn&#8217;t do any KYC at all. Anyone who knew where to look could buy access with just a burner email and a few dollars in crypto. The result? In just one week in June 2026, Google saw 316 different threat groups using NetNut exit nodes, including cybercriminals and espionage actors.</p><h3>What this means if you were a customer</h3><p>Let&#8217;s be honest: losing a proxy provider isn&#8217;t really a technical problem. If you&#8217;re running a serious scraping setup, switching providers just means changing your endpoint. And if you&#8217;ve set up any kind of automatic fallback system, which you really should have, your pipelines probably won&#8217;t even notice the downtime.</p><p>The real headache is legal and compliance risk, especially if you&#8217;re working in a highly regulated industry.</p><p>Take financial markets, for example: I&#8217;ve worked in this space myself. Web scraping is a key part of what&#8217;s called alternative data: things like scraped prices, app usage stats, satellite images, and transaction data. Investment funds use these to get an edge on listed companies, alongside the usual financial statements and market data.</p><p>Anyone who has tried to sell web-scraped data to an investment manager knows what comes next: the due diligence questionnaire. I&#8217;ve been through this process, and it&#8217;s not a formality. The standard DDQ used in the industry, published by FISD&#8217;s Alternative Data Council, dedicates an entire appendix to web scraping and explicitly asks vendors whether they use proxies, whether those proxies are anonymizing, whether the proxy providers include information sufficient for scraped websites to contact the company, whether data is collected from pages behind logins or CAPTCHAs, and whether the vendor or its service providers have received cease and desist orders, subpoenas, or been subject to investigations in the past five years.</p><p>Now imagine you&#8217;re a data vendor facing that last question, and your proxy provider&#8217;s homepage is showing an FBI seizure banner. Telling a hedge fund that your infrastructure supplier is under federal investigation is not going to help you close any deals. In this business, your compliance is only as strong as the weakest link in your supply chain. Proxies are definitely part of that chain, whether your legal team knows it or not.</p><h3>How I Think About Choosing Proxy Providers After NetNut</h3><p>The reality is that residential and mobile proxies have always been the most controversial part of the proxy world. Unlike datacenter IPs or ISP deals, residential proxies need real people to agree to run a proxy on their devices in exchange for something, maybe money if they&#8217;re in a bandwidth-sharing program, or a free app, since developers get paid by proxy providers for every install.</p><p>Most people don&#8217;t realize how widespread this is. <a href="https://spur.us/blog/how-proxy-providers-co-opt-entire-networks">Spur scanned over 6,000 LG and Samsung smart TV apps and found that more than 2,000 of them had residential proxy SDKs inside</a>. That means about a third of smart TV apps are quietly acting as proxy infrastructure. The real difference between legitimate and abusive setups comes down to consent and disclosure. Some providers, like <a href="https://get.brightdata.com/twsc">Bright Data</a>, Massive, and <a href="https://oxylabs.go2cloud.org/aff_c?offer_id=7&amp;aff_id=665">Oxylabs</a>, at least spell out the arrangement in their terms of service, as Spur pointed out. For example, you can check Bright Data's peer program directly on <a href="http://bright-sdk.com/">bright-sdk.com</a>, where you can find the certifications and compliance that they obtained.</p><p>Some providers have shown they&#8217;re willing to take a hit to keep their networks clean. For example, <strong><a href="https://brightdata.com/blog/leadership/why-we-willingly-killed-10-percent-of-our-network">Bright Data has publicly shared that they dropped SDK partners who wouldn&#8217;t digitally sign their apps or who served ads leading to shady websites</a></strong>. These partners made up over 10% of their residential peer network, so it wasn&#8217;t a small decision. On the You might be skeptical about companies promoting their own good behavior, but I think this is the right direction: sourcing based on real standards, not just growth at any cost. They&#8217;re also founding members of the <strong><a href="https://responsibledatacollection.org/">Alliance for Responsible Data Collection</a>, </strong>together with other players like <strong><a href="https://www.sequentum.com/">Sequentum</a> </strong>and <strong><a href="https://commoncrawl.org/">Common Crawl</a></strong>.</p><p>So here&#8217;s what I take away from all this. After what happened with IPIDEA in January and NetNut in July, picking a proxy provider based only on price isn&#8217;t just about quality anymore; it&#8217;s about risk. You need to ask the same questions the security researchers asked NetNut: How do you source your IPs, and can you prove consent? Who can actually buy access to your network, and what does your KYC process look like, even for your resellers? And what happens, both in contracts and technically, when abuse is found?</p><p>If your provider can&#8217;t answer these questions, someone else will, maybe with a seizure banner.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Session Stickiness at Scale - Insights from DataImpulse]]></title><description><![CDATA[Building a Proxy Rotation Layer That Mimics Real Users]]></description><link>https://substack.thewebscraping.club/p/session-stickiness-at-scale-insights</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/session-stickiness-at-scale-insights</guid><dc:creator><![CDATA[Olia Liudko]]></dc:creator><pubDate>Tue, 07 Jul 2026 03:01:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XNg7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is a guest post written by the DataImpulse team. For an independent benchmark of proxy prices, <a href="https://proxyprice.thewebscraping.club/">visit our Proxy Pricing Benchmark tool</a>.</em></p><div><hr></div><p><span>You buy proxies from a provider with the biggest IP pool you can find. You rotate IPs for every request. You randomize User-Agent strings. You connect to proxy servers from various regions. You add delays between requests. You expect to smoothly scrape the necessary data in no time, as you have made everything so your scraper does not leave any traces behind and is impossible to get caught. The next thing you see usually happens around request 150-300 - this is blocks. CAPTCHAs, error 403, redirects to honeypot pages serving you wrong data. The whole pipeline crumples down.</span></p><p><span>If this situation is painfully familiar, you have probably let session stickiness out of sight while building a proxy rotation layer - a common mistake. This article explains in detail how to rotate proxies to mimic real users so your scraper remains a reliable data source even at scale.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XNg7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XNg7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XNg7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1162929,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/204178385?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XNg7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!XNg7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5a58a9f-44c5-4200-b15d-aba98ee9fe68_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2><span>Why careless IP rotation may speed up bot detection</span></h2><p><span>When you realize a website has blocked you out, the first instinct is to add more IPs - maybe buy proxies that perform better and are more adapted for dealing with detection systems. You try to add more geo-diversity. In other words, you use the same approach as before, just scale it. Sometimes it helps a bit; however, sometimes, blocks are back even faster.</span></p><p><span>The mistake here is that you are looking for a problem in the wrong place. It is not the lack of IP diversity, but the lack of session consistency.</span></p><p><span>Modern anti-bot systems like Cloudflare, Akamai Bot Manager, DataDome, or PerimeterX do not rely on the IP address as a primary method of bot detection. Instead, they consider a lot of signals and model session behavior. In such circumstances, your rotating efforts, if not strategic, can only make things worse and produce behavioral signals that are bot-like, not user-like. More IPs are not a fix for that problem. Modeling behavioral signals of genuine users is.</span></p><h2><span>The anatomy of bot detection</span></h2><p style="text-align: justify;"><span>In order to build a truly stealthy scraper with a rotation layer that gets the job done, it is important to understand first how detection happens - what exactly can give you away.</span></p><p><span>So, there are four layers of different signals that anti-bot systems analyze simultaneously and make a decision whether to let you be or deny access.</span></p><ul><li><p><span>Layer 1 - Network</span></p></li></ul><p><span>IP reputation, ASN classification, type of IP (residential, mobile, or datacenter), and provider fingerprints belong to that layer. Also, if a proxy or VPN IP is known, it would also be shown here.</span></p><p><span>This layer is the one developers usually optimize the most for. Ironically, this is the least important layer for security systems. That is why you fail when following scraping tutorials that offer to simply set as big an IP pool as possible and rotate addresses for every request. It is not because you have done something wrong or your proxies are bad, but because this approach does not work for scraping at scale.</span></p><ul><li><p><span>Layer 2 - TLS/HTTP fingerprints</span></p></li></ul><p><span>HTTP clients&#8217; fingerprints are nearly as unique as an IP address. TLS handshake leaves quite a trace with its cipher suite order, list of supported extensions, and elliptic curves. HTTP/2 creates another signal with header prioritization, window size, and frame ordering. The combination of TLS and HTTP/2 fingerprints is often enough for security systems to figure out whether it&#8217;s human-generated or bot-generated traffic, even without considering signals from other layers.</span></p><p><span>Widely used scraping libraries, for example, curl, requests, httpx, aiohttp  produce distinct, detectable fingerprints. Python is a popular choice for building scrapers now; still, if you use its requests library, a calibrated WAF would spot it from TLS handshake alone, User-Agent headers be forgotten, whatever they say.</span></p><ul><li><p><span> Layer 3 - Behavioral</span></p></li></ul><p><span>Requests cadence, referrer chain integrity, cookie handling, navigation patterns, and timing distributions are evaluated here. Even the delays between requests, if they are too precise and equal, can fuel suspicions, as humans do not make requests with a machine&#8217;s precision. Real users&#8217; referrers have logic to them. Human users&#8217; cookies are consistent and show that they came from a search engine page. They do not disappear mid-session or mid-navigation.</span></p><ul><li><p><span>Layer 4 - Session Graph</span></p></li></ul><p><span>This layer evaluates whether the sequence of cookies, tokens, page flow, and state transitions within the session makes sense for a human user. That is a layer most scrapes fail to pass, as not so many developers pay attention to coherence. Cause even if stand-alone signals look normal, it is important that they make sense when evaluated together. For example, a user visits an e-commerce website. Their session token would show that. Their viewport size would stay the same throughout the visit. They will go between pages with different time intervals, reflecting reading and decision time.</span></p><p><span>Coherence is the key that opens or closes a door for your scraper. And one proxy rotation at the wrong time can reveal your scraper&#8217;s true identity.</span></p><h2><span>Session stickiness: a true solution</span></h2><p><span>In the context of a proxy architecture, session stickiness is a condition when all requests that belong to the same logical session are routed via the same IP address. At the very least, it must be the same subnet, geo location, and ASN cluster.</span></p><p><span>Now, let&#8217;s define what a session may mean, cause in terms of scraping, there are several options possible.</span></p><ul><li><p><span>Authentication session</span></p></li></ul><p><span>The most obvious case. You log in, receive a session token, and proceed to the data. If your IP changes somewhere between the login request and the first data request after authentication, to the target server, it looks like a user logged in from Paris and then suddenly that same user is asking for data from Seoul. Session invalidation or re-verification is guaranteed.</span></p><ul><li><p><span>Stateful pagination</span></p></li></ul><p><span>This type is subtler and catches even sophisticated scrapers off guard. The thing is that many modern applications track your pagination state on a server&#8217;s side - in other words, a server &#8220;remembers&#8221; a page you are currently at and ties it to your IP. If the IP address changes between pages 3 and 4, the server loses this track. It may either block you or return incorrect data.</span></p><ul><li><p><span>Multi-step forms</span></p></li></ul><p><span>Cases when you need to simulate checkouts, survey scrapers, or lead generation cases are the most session-sensitive. The state that was established at the beginning is carried forward across the rest of the steps. A mid-process IP change is a red flag in such a scenario; detection systems will react immediately.</span></p><p><span>To sum up, it is not random IPs you need, but sessions and a rotation strategy that considers session coherence.</span></p><h2><span>Building the rotation layer</span></h2><p><span>Time to get to work. Remember: rotating session objects, not IP addresses.</span></p><h3><span>The session object model</span></h3><p><span>A session object, in simple words, is a set of signals that make a set of requests look like they originated from a real human user.</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;8a857197-6886-4ede-acef-8093a63ecbcc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">@dataclass
class ProxySession:
    session_id: str
    proxy_endpoint: str          # host:port or provider session token
    cookies: dict = field(default_factory=dict)
    headers_profile: dict = field(default_factory=dict)
    geo: str = ""                # e.g. "pl,us,en"
    asn: str = ""                # e.g. "12345"
    created_at: float = field(default_factory=time.time)
    last_used: float = field(default_factory=time.time)
    request_count: int = 0
    flagged: bool = False

    def is_expired(self, ttl_seconds: int = 600, max_requests: int = 200) -&gt; bool:
        age = time.time() - self.created_at
        return self.flagged or age &gt; ttl_seconds or self.request_count &gt;= max_requests

</code></pre></div><p><span>The headers_profile is not just a User-Agent string. It is a set of HTTP headers that are used for each and every request of one session: User-Agent, Accept-Language, Accept-Encoding, Accept, sec-ch-ua, sec-ch-ua-platform, sec-ch-ua-mobile. They must stay the same for every request. If one request is coming as if from Chrome browser version 108, and another one from version 124, detection systems will notice a mismatch. Even without knowing exactly that you are a scraper, such a mismatch is enough to block you.</span></p><h3><span>Sticky session assignment</span></h3><p><span>Any scraper must use the same session object within one session - this is a rule. So the session assignment must not be random, but based on that rule to prevent any mix-ups.</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;3cf937ef-7a7a-42c8-9a78-f67e1c439f88&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import hashlib
import threading
from typing import Dict

class SessionPool:
    def __init__(self, proxy_provider):
        self.provider = proxy_provider
        self._sessions: Dict[str, ProxySession] = {}
        self._lock = threading.Lock()

    def _make_key(self, job_id: str, target_domain: str) -&gt; str:
        raw = f"{job_id}:{target_domain}"
        return hashlib.md5(raw.encode()).hexdigest()[:12]

    def get_or_create(self, job_id: str, target_domain: str) -&gt; ProxySession:
        key = self._make_key(job_id, target_domain)
        with self._lock:
            session = self._sessions.get(key)
            if session is None or session.is_expired():
                session = self.provider.new_session(geo=self._infer_geo(target_domain))
                self._sessions[key] = session
            session.last_used = time.time()
            session.request_count += 1
            return session

    def _infer_geo(self, domain: str) -&gt; str:
        # Simplified &#8212; in production, map TLDs/domains to geo requirements
        tld_map = {".pl": "PL", ".de": "DE", ".co.uk": "GB", ".fr": "FR"}
        for tld, geo in tld_map.items():
            if domain.endswith(tld):
                return geo
        return "US"  # Default
</code></pre></div><p><span>Notice that the session key is determined by job_id + target_domain, so the scraper sticks to the same session until it expires. The session expiration is also based on 2 rules - TTL (sessions older than 10 minutes automatically get refreshed) and request count (after 200 requests, the session gets refreshed to prevent statistical fingerprinting from long-lived sessions).</span></p><h3><span>Geo-tied rotation</span></h3><p><span>Another life hack is to rotate IPs within the same geo or ASN cluster even when a session has expired, and you are spinning to the new one. Even between sessions, sudden changes (like jumping from Tokyo residential IP to Toronto residential IP) are noticeable and suspicious. When that happens, it looks more like a VPN switch, not a user returning.</span></p><p><span>Result-oriented proxy providers offer sticky sessions. In such a case, a session token has a location backed into it, and the provider guarantees that the traffic will originate as if from that location during a session&#8217;s lifetime.</span></p><h3><span>Header profile coherence</span></h3><p><span>Not only must IP remain the same throughout the session. If you rely on the same address, but the header profile changes from request to request, it is like a &#8220;Hello, I&#8217;m a scraper&#8221; sign for detection systems.</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;d0fd10ba-049f-4f61-a916-3047fad3c8a6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">HEADER_PROFILES = [
    {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate, br",
        "sec-ch-ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": '"Windows"',
    },
    # Add more profiles reflecting real browser market share distributions
]
</code></pre></div><p><span>One session - one profile. No changes mid-session.</span></p><h3><span>Retry logic</span></h3><p><span>Retry logic is another thing that can blow your cover. When a request fails due to some reason and the target server instantly receives another one from the same origin, it most certainly means bots are in the game, as humans do not act with such light speed. An even less obvious trap is retrying with a different session object when your current session simply needs a brief backoff.</span></p><p><span>The better approach is to retry while relying on the same session object and a slight delay. If you receive a clear block signal, like 407, 429 errors with specific headers, or CAPTCHA, switch to the new session.</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;079799a9-54dd-48c6-a0a7-2ac6fc112533&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def fetch_with_retry(
    url: str,
    pool: "SessionPool",
    job_id: str,
    target_domain: str,
    max_retries: int = 3,
) -&gt; requests.Response:
    failures: list[str] = []

    for attempt in range(max_retries):
        session = pool.get_or_create(job_id, target_domain)
        try:
            response = make_request(url, session)
            if response.status_code in (407, 429) or is_captcha(response):
                session.flagged = True
                failures.append(
                    f"attempt {attempt}: session {session.session_id} "
                    f"blocked (status={response.status_code})"
                )
                if attempt &lt; max_retries - 1:
                    base = min(2 ** attempt * 2, 30)
                    time.sleep(base * (0.8 + 0.4 * random.random()))
                continue
            return response
        except (requests.Timeout, requests.ConnectionError) as e:
            failures.append(f"attempt {attempt}: {type(e).__name__}: {e}")
            if attempt &lt; max_retries - 1:
                base = min(2 ** attempt * 2, 30)
                time.sleep(base * (0.8 + 0.4 * random.random()))

    raise MaxRetriesExceeded("All attempts failed:\n  " + "\n  ".join(failures))
</code></pre></div><p><span>There is an important difference: TransientError (which includes network hiccup and timeout) retries with the current session. BlockedError marks the session as flagged, which in turn triggers is_expired() and forces a new session creation.</span></p><h2><span>Scaling concurrent sessions</span></h2><p><span>At a small scale, the session pool model works just fine. However, if your scraper runs on 50+ machines simultaneously, you need all of them not to create new sessions each, but to stick to the one.</span></p><p><span>A Redis-backed session pool is a solution. Basically, Redis is a shared notepad that lives on a server and that every machine can read and write to, so that there is no chaos in sessions. Store each ProxySession object (serialized as JSON) with a TTL key:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;6a6de4fb-90af-4210-b5fa-1aa72d5a0d01&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def store_session(session: ProxySession, ttl: int = 600):
    key = f"session:{session.session_id}"
    r.setex(key, ttl, json.dumps(session.__dict__))

def load_session(session_id: str) -&gt; Optional[ProxySession]:
    data = r.get(f"session:{session_id}")
    if data:
        return ProxySession(**json.loads(data))
    return None
</code></pre></div><p><span>If a proxy provider offers sticky sessions, your Redis only needs to track the session token, not the exit node state. A provider handling IP consistency and you dealing with cookies and headers is the preferred architecture for effective scaling because building and maintaining a distributed session pool is good 2-4 weeks of work. You need developers to do it - and add ongoing maintenance as websites update their detection systems.</span></p><h2><span>Testing rotation layer</span></h2><p><span>To be sure everything works fine, verify your rotation layer. Send 10 requests to see whether all of them really go via the same IP address.</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;64feb32a-56fd-4b85-85a2-e1cb6929b223&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import requests

def verify_session_stickiness(session_token: str, n: int = 10):
    proxy = f"http://user__sessid.{session_token}:pass@gw.dataimpulse.com:823"
    seen_ips = set()

    for i in range(n):
        r = requests.get("https://httpbin.org/ip", proxies={"https": proxy})
        ip = r.json()["origin"]
        seen_ips.add(ip)
        print(f"Request {i+1}: {ip}")

    print(f"\nUnique IPs: {len(seen_ips)}")
    assert len(seen_ips) == 1, f"FAIL: Session leaked across {len(seen_ips)} IPs"
    print("PASS: Session sticky across all requests")

verify_session_stickiness("your_session_token_here")
</code></pre></div><p><span>To verify headers, use https://httpbin.org/headers and compare headers across requests. Any differences in User-Agent, Accept-Language, or sec-ch-ua between requests of the same session are a problem.</span></p><p><span>If you want a deeper test, use bot.sannysoft.com or pixelscan.net. Those sites show what detection systems see - WebDriver flags, inconsistent browser APIs, JA3 anomalies, timezone/language mismatches. You see what exactly is wrong and at which layer. This is an easier, faster, and cheaper way than constant tries and errors.</span></p><h2><span>Final thoughts</span></h2><p><span>Scrapers that remain undetected are not the ones with the largest IP pools. They are the ones that mimic real users&#8217; behavior the most persuasively - when the IP, the TLS fingerprint, the header profile, the cookie state, and the navigation flow all together create traffic patterns that are typical for a genuine human visitor.</span></p><p><span>IP rotation is necessary, but it is a tactic, while session architecture is a strategy. When you adopt that approach, you feel the difference - in lower block rates and higher data accuracy, in how much less firefighting your team goes through every time security systems update.  Scalability is another benefit.</span></p><p><span>Also, there is an undeniable tendency for detection systems to develop, and so must your scrapers do. Rotation that is based on sessions, not single IPs, allows for that development.</span></p><p><span>If you want to skip the &#8220;build infrastructure from scratch&#8221; part, </span><a href="https://dataimpulse.com/"><span>DataImpulse</span></a><span> is an ethical proxy provider that offers both rotating and sticky sessions. You can set the duration of a session manually - up to 120 minutes is possible. DataImpulse (dataimpulse.com) provides 90M+ of residential, mobile, and datacenter enterprise-grade addresses in 195 locations with advanced targeting options (extra costs) to help maintain session coherence. Web scraping, SERP tracking, price monitoring, and other sensitive scenarios are among its use cases. Prices start from $1/GB - for non-expiring traffic and 24/7 human support.</span></p>]]></content:encoded></item><item><title><![CDATA[From Local Scripts to Cloud Power: Scaling Your Scrapers with Oxylabs Headless Browser]]></title><description><![CDATA[A deep dive into why "headless" doesn't just mean "invisible", and why your architecture depends on it.]]></description><link>https://substack.thewebscraping.club/p/oxylabs-headless-browser</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/oxylabs-headless-browser</guid><dc:creator><![CDATA[Federico Trotta]]></dc:creator><pubDate>Mon, 06 Jul 2026 03:00:50 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c760f6b1-4f2b-464d-a81f-5cdc5ed93846_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Scraping data from the web is a craft that requires learning to use different tools. This is because you may start working on a target website with a scraping framework, realize there are issues you didn&#8217;t consider, and end up using other solutions. </p><p>Among the many tools a scraping engineer should master are headless browsers. But if you want to be completely honest, in the scraping industry there&#8217;s some confusion about the concepts of &#8220;headless browsers&#8221; and &#8220;browser automation tools&#8221;.</p><div><hr></div><blockquote><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/WyQ3mA" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="521" height="293.0625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:521,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p><div><hr></div></blockquote><p>In this article, you&#8217;ll get your ideas clear on headless browsers and browser automation tools. You&#8217;ll also discover the <strong><a href="https://oxylabs.go2cloud.org/aff_c?offer_id=7&amp;aff_id=665&amp;url_id=214">Oxylabs Headless Browser</a></strong> and learn how to use it in practice against common anti-bots. In particular, you&#8217;ll see the difference in servers&#8217; responses when hitting the same target URLs with and without the Oxylabs solution.</p><p>Let&#8217;s get into it!</p><h2>What is a Headless Browser?</h2><p>A headless browser is a fully functional web browser that operates without a graphical user interface (GUI). To understand what this means in practice, it helps to discuss what a browser actually does under the hood.</p><p>When you open a browser like Chrome and navigate to a URL, the browser performs a precise sequence of operations:</p><ul><li><p>It sends an HTTP request to a server.</p></li><li><p>It receives an HTML document.</p></li><li><p>It parses that <a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision">HTML into a DOM (Document Object Model</a><strong><a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision">)</a></strong><a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision"> tree</a>.</p></li><li><p>It fetches and applies CSS stylesheets to compute the visual layout, downloads and executes JavaScript files, and processes any asynchronous network requests (XHR/Fetch API calls) triggered by that JavaScript.</p></li><li><p>It renders everything into visible pixels on your screen.</p></li></ul><p>Below is an image that graphically shows the whole process:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8kZp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8kZp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 424w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 848w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 1272w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8kZp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png" width="1145" height="328" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:328,&quot;width&quot;:1145,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:352227,&quot;alt&quot;:&quot;What happens under the hood when browsers perform actions by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/202688828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="What happens under the hood when browsers perform actions by Federico Trotta" title="What happens under the hood when browsers perform actions by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!8kZp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 424w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 848w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 1272w, https://substackcdn.com/image/fetch/$s_!8kZp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff24c0d1e-a88d-4c62-bc89-e371a157093e_1145x328.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">What happens under the hood when browsers perform actions</figcaption></figure></div><p>A headless browser performs every single one of those steps, except painting pixels to a physical display. It still builds the DOM, executes JavaScript, processes AJAX calls, and maintains a fully accurate representation of the page state in memory. But it does it without needing a graphical rendering environment.</p><p>It&#8217;s also important to understand the difference between a headless browser and a basic HTTP client. Tools like <a href="https://requests.readthedocs.io/en/latest/">Python&#8217;s </a><em><a href="https://requests.readthedocs.io/en/latest/">requests</a></em> library or <em><a href="https://curl.se/">curl</a></em> are pure HTTP clients. This means that they send a request and return whatever raw response the server provides. They have no concept of a DOM, no JavaScript engine, and no rendering pipeline. </p><p>The most widely used headless browsers are the following:</p><ul><li><p><strong><a href="https://phantomjs.org/">PhantomJS</a></strong>: One of the first dedicated headless browsers, built on an older version of WebKit. It was widely used before 2017 but has since been officially abandoned and is no longer maintained. You may still encounter it in legacy codebases, but it&#8217;s better not to use it for new projects.</p></li><li><p><strong><a href="https://developer.chrome.com/docs/chromium/headless">Headless Chrome/Chromium</a></strong>: Google officially introduced headless mode in Chrome 59 (2017), effectively making PhantomJS obsolete overnight. It exposes the <a href="https://chromedevtools.github.io/devtools-protocol/">Chrome DevTools Protocol (CDP)</a> as its programmatic interface, which automation frameworks connect to to send instructions and receive data.</p></li><li><p><strong><a href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Headless Firefox</a></strong>: Mozilla introduced headless support in Firefox 55. Powered by the <a href="https://firefox-source-docs.mozilla.org/overview/gecko.html">Gecko rendering engine</a> and the <a href="https://spidermonkey.dev/">SpiderMonkey JavaScript engine</a>, it&#8217;s a strong alternative to Chromium, particularly useful when you need to scrape or test behavior tied to the Gecko engine specifically.</p></li><li><p><strong><a href="https://webkit.org/">WebKit</a></strong>: WebKit is the browser engine that powers Apple&#8217;s Safari. Playwright bundles a version of WebKit that can be run in headless mode on non-Apple platforms, giving you the ability to simulate Safari&#8217;s rendering behavior on Linux or Windows servers (something that would be otherwise impossible).</p></li><li><p><strong><a href="https://splash.readthedocs.io/en/stable/">Splash</a></strong>: A lightweight, scriptable headless browser built specifically for web scraping, developed by the Scrapy team. It is written in Python and <a href="https://www.lua.org/">Lua</a>, exposes an HTTP API, and integrates natively with the <a href="https://www.scrapy.org/">Scrapy framework</a>, making it a beginner-friendly option for Python-based scraping pipelines.</p></li></ul><div><hr></div><blockquote><p>Your scraping workflows deserve a proxy infrastructure that just works. With <strong>Swiftproxy</strong> on your side, consistency is built-in.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://www.swiftproxy.net/?ref=webscrapingclub" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g3qW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 424w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 848w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 1272w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g3qW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png" width="670" height="83.75" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:182,&quot;width&quot;:1456,&quot;resizeWidth&quot;:670,&quot;bytes&quot;:445760,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.swiftproxy.net/?ref=webscrapingclub&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/193806031?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!g3qW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 424w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 848w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 1272w, https://substackcdn.com/image/fetch/$s_!g3qW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49af1519-bfa5-4c03-afea-f45743bd057b_2880x360.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.swiftproxy.net/?ref=webscrapingclub&quot;,&quot;text&quot;:&quot;Try Swiftproxy today&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.swiftproxy.net/?ref=webscrapingclub"><span>Try Swiftproxy today</span></a></p></blockquote><div><hr></div><h2>Headless Browsers vs. Automation Frameworks: A Critical Distinction</h2><p>At this point, it&#8217;s essential to draw a clear architectural boundary between two categories that are frequently, but incorrectly, used interchangeably: headless browsers and browser automation frameworks.</p><p>As said in the previous paragraph, a <strong>headless browser is the actual browser engine itself</strong>. So, it&#8217;s the software responsible for all the core browser operations described above.</p><p>A <strong>browser automation framework</strong>, on the other hand, <strong>is a programming library or tool that sits on top of a headless (or full) browser and provides a developer-friendly API to control it programmatically</strong>. The framework itself does not render pages, execute JavaScript, or manage network traffic: it delegates all of that to the underlying browser engine. What it provides is an abstraction layer to navigate to URLs, click elements, fill in forms, wait for conditions, intercept network requests, take screenshots, and to perform any similar activity.</p><p>Think of it this way: the headless browser is the engine of a car, and the automation framework is the steering wheel, pedals, and dashboard. You need both to drive, but they are fundamentally different components with different responsibilities.</p><p>This distinction also has a practical implication. If a website employs bot detection based on browser fingerprinting, it&#8217;s the underlying browser engine&#8217;s characteristics that matter, not the automation framework on top of it. This means that switching from Puppeteer to Playwright doesn&#8217;t change your browser fingerprint if both are driving the same Chromium engine with the same configuration.</p><p>The list below reports the programming libraries and tools used to control headless (or full) browsers programmatically:</p><ul><li><p><strong><a href="https://pptr.dev/">Puppeteer</a></strong>: <a href="https://nodejs.org/en">A Node.js</a> library developed and maintained by Google that provides a high-level API to control Headless Chrome/Chromium over CDP. It was the first major modern automation framework to replace PhantomJS and remains widely used in the JavaScript/Node.js ecosystem. </p></li><li><p><strong><a href="https://playwright.dev/">Playwright</a></strong>: Developed by Microsoft, Playwright is a more modern and feature-rich automation framework that supports Chromium, Firefox, and WebKit under a single unified API. It has become the preferred choice for many scraping engineers due to its superior <a href="https://substack.thewebscraping.club/i/162123239/manage-concurrency-with-asyncio-and-aiohttp">handling of async operations</a>, automatic waiting strategies, built-in network interception, and robust multi-browser support. On the side of programming languages, it&#8217;s available for Node.js, Python, Java, and .NET.</p></li><li><p><strong><a href="https://app.notion.com/p/TWSC-Oxylabs-headless-browser-365945fea5028086ad6ac71eba2df177?pvs=21">Selenium</a></strong>: The oldest and most widely adopted browser automation framework in existence, originally released in 2004. Unlike Puppeteer and Playwright, Selenium communicates with browsers via the <a href="https://app.notion.com/p/TWSC-Oxylabs-headless-browser-365945fea5028086ad6ac71eba2df177?pvs=21">W3C WebDriver protocol</a>. This means it supports a broader range of browsers and is the de facto standard in enterprise testing environments. Selenium supports multiple languages, including Python, Java, C#, Ruby, and JavaScript, which gives it an exceptionally large community and an extensive ecosystem of documentation and tooling. For engineers working in Python, Selenium with a headless Chrome or Firefox driver is still a very common scraping approach. Its main trade-off is that it can be slightly slower and less ergonomic for modern async-heavy scraping scenarios.</p></li></ul><h2>Why Do Engineers Need a Headless Browser?</h2><p>When you start defining how to scrape a website, your first instinct is often to reach for a lightweight HTTP client. And, in many cases, that is the right call. Simple, server-rendered websites that return complete HTML in their initial response are perfectly scrapable with tools like <em><a href="https://requests.readthedocs.io/en/latest/">requests</a></em><a href="https://requests.readthedocs.io/en/latest/"> </a>coupled with <em><a href="https://beautiful-soup-4.readthedocs.io/en/latest/">BeautifulSoup</a></em>. </p><p>However, as you begin working with modern websites, you will quickly encounter scenarios where an HTTP client falls flat. Understanding why this happens (and when a headless browser becomes necessary) is one of the most fundamental skills you need to master for your career.</p><p>This section discusses the most common scenarios when you need to use a headless browser for scraping target websites.</p><h3>JavaScript-Rendered and SPA Content</h3><p>The most common reason to turn to headless browsers is client-side JavaScript rendering. A large proportion of modern websites, in fact, are built as Single Page Applications (SPAs) using frameworks like React, Vue.js, Angular, or Next.js. In these architectures, the server does not send a fully populated HTML page. Instead, it sends a minimal HTML shell along with a bundle of JavaScript files. The browser then executes that JavaScript, which makes additional API calls to fetch the actual data and dynamically constructs the DOM. </p><p>If you scrape the raw HTML with an HTTP client, you will receive that empty shell and find none of the content you are looking for. A headless browser, instead, loads the page as a real user&#8217;s browser would, waits for the JavaScript to finish executing, and exposes the fully populated DOM for you to extract data from.</p><h3>AJAX and Asynchronous Data Loading</h3><p>Closely related to SPAs is the broader pattern of asynchronous data fetching. Even on websites that are not full SPAs, it&#8217;s extremely common for certain page sections to be populated via AJAX requests that fire after the initial page load. These requests hit internal or external APIs, and the responses are injected into the page dynamically. </p><p>With a headless browser and a tool like Playwright, you can intercept these network requests directly. Also, this is a powerful web scraping technique. Rather than scraping the rendered HTML, you capture the raw API response (usually as JSON), which gives you clean and structured data to work with.</p><h3>Infinite Scroll and Pagination</h3><p>Many websites like social media platforms, job boards, and e-commerce product listings implement <a href="https://substack.thewebscraping.club/p/handling-infinite-scrolling-python-js">infinite scroll</a>. This means that new content is loaded dynamically as the user scrolls down the page. On the practical side, this means that there is no &#8220;Page 2&#8221; URL to follow. The content doesn&#8217;t exist in the DOM until a scroll event triggers a new batch of data to load. </p><p>In this scenario, a headless browser allows you to simulate scroll events, wait for new content to be injected, and continue extracting data until a stopping condition is met. This is fundamentally impossible to replicate with a plain HTTP client.</p><h3>User Interaction Simulation</h3><p>Some content is only accessible after specific user interactions, like clicking on a button, selecting a value from a dropdown menu, submitting a search form, switching between tabs, and similar. A headless browser gives you a full interaction API that allows you to click on elements, type into input fields, select options, trigger keyboard shortcuts, and simulate virtually any user action. </p><p>This is particularly important when <a href="https://substack.thewebscraping.club/p/scraping-booking-playwright">scraping search-driven websites like travel booking sites</a>, real estate portals, and any similar websites where results are generated after the user performs actions.</p><h3>Bot Detection and Browser Fingerprinting Evasion</h3><p>Many high-value websites deploy anti-bot systems that analyze incoming requests to determine whether they originate from a real browser or an automated script. These systems are <a href="https://substack.thewebscraping.club/p/machine-learning-for-detecting-bots">trained using machine learning models to check for dozens of signals</a>. A headless browser provides a much more convincing browser environment than a raw HTTP client. </p><p>In particular, with additional configurations and stealth patches, you can significantly reduce the likelihood of your scraper being detected and blocked. Of course, this is an arms race: anti-bot technology continues to evolve, and a headless browser alone is not a silver bullet.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>What Is Oxylabs Headless Browser?</h2><p></p><p><a href="https://oxylabs.go2cloud.org/aff_c?offer_id=7&amp;aff_id=665&amp;url_id=214">Oxylabs Headless Browser</a> is a <strong>cloud-based browser automation solution</strong> that allows engineers to run and control remote browser sessions without the overhead of managing browser infrastructure locally or on their own servers. Rather than spinning up a local Chromium or Firefox instance on your own machine or cloud VM, <a href="https://oxylabs.io/products/headless-browser">Oxylabs Headless Browser</a> offloads all of that complexity to dedicated remote servers maintained by Oxylabs. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://oxylabs.go2cloud.org/aff_c?offer_id=7&amp;aff_id=665&amp;url_id=214" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QELq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QELq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QELq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QELq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QELq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg" width="697" height="364.7760989010989" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:762,&quot;width&quot;:1456,&quot;resizeWidth&quot;:697,&quot;bytes&quot;:812366,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://oxylabs.go2cloud.org/aff_c?offer_id=7&amp;aff_id=665&amp;url_id=214&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/202688828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QELq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QELq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QELq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QELq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc98d44ab-8eee-4984-b9f5-cd54c2ab4401_2400x1256.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The result is a production-ready and fully managed browsing environment that you connect to via a standard WebSocket (WSS) connection, and control using any automation framework that supports the Chrome DevTools Protocol (CDP) exactly as you would a local browser instance.</p><p>The image below shows, at a high level, the architectural difference between traditional browser automation and using Oxylabs&#8217; solution:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!i_yr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!i_yr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 424w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 848w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 1272w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!i_yr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png" width="995" height="518" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:518,&quot;width&quot;:995,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:368152,&quot;alt&quot;:&quot;Browser automation: local VS cloud-based via Oxylabs servers by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/202688828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Browser automation: local VS cloud-based via Oxylabs servers by Federico Trotta" title="Browser automation: local VS cloud-based via Oxylabs servers by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!i_yr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 424w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 848w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 1272w, https://substackcdn.com/image/fetch/$s_!i_yr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feae7e0eb-20c8-4f67-b278-dbc294526bc8_995x518.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Browser automation: local VS cloud-based via Oxylabs servers</figcaption></figure></div><p>The currently available browser instance is a <a href="https://developers.oxylabs.io/scraping-solutions/headless-browser/chrome">Chrome-based environment (</a><em><a href="https://developers.oxylabs.io/scraping-solutions/headless-browser/chrome">ubc.oxylabs.io</a></em><a href="https://developers.oxylabs.io/scraping-solutions/headless-browser/chrome">)</a>. This runs high-performance Chromium instances with advanced stealth configurations on dedicated servers with integrated <a href="https://substack.thewebscraping.club/p/differences-residential-mobile-proxies">residential proxies</a>.</p><h3>Key Features</h3><p>What differentiates Oxylabs Headless Browser from a self-managed setup is the set of capabilities that are baked directly into the infrastructure. Rather than requiring you to implement them yourself, it provides you with the following:</p><ul><li><p><strong>Integrated residential proxies</strong>: Every browser session is automatically routed through Oxylabs&#8217; residential proxy network. This eliminates the need to manage a separate proxy integration and ensures that outgoing requests carry legitimate residential IP addresses, reducing the risk of IP-level blocks.</p></li><li><p><strong>Automatic CAPTCHA solving</strong>: The platform detects and <a href="https://substack.thewebscraping.club/p/bypassing-recaptchas-with-open-source">solves CAPTCHAs</a> by default on page load. For CAPTCHAs that appear mid-session, it exposes an event-based API via the <em>window</em> object that your script can subscribe to in order to pause and resume automation around the solving process.</p></li><li><p><strong>Geolocation targeting</strong>: You can pin your browser session to a specific country, state, or city by appending query parameters directly to the WebSocket connection URL. This is essential for scraping geo-targeted content, verifying localized pricing, or accessing region-restricted pages without maintaining a geographically distributed proxy infrastructure yourself.</p></li><li><p><strong>Device type emulation</strong>: The <em>p_device</em> parameter allows you to emulate desktop, mobile, or tablet environments. This gives you access to device-specific content, responsive layouts, and mobile-only UI elements or CAPTCHA variants.</p></li><li><p><strong>Session inspection</strong>: This is a debugging feature that uses VNC (Virtual Network Computing) to give you real-time visual access to a running browser session. This is invaluable when diagnosing issues that are not apparent from logs alone. For example, for unexpected page rendering, broken interaction flows, or timing-related problems in your automation script.</p></li><li><p><strong>MCP integration</strong>: Oxylabs Headless Browser supports connection via the <a href="https://developers.oxylabs.io/products/headless-browser/ai-workflows/integration-with-mcp">Model Context Protocol (MCP)</a>, enabling AI systems such as Claude Desktop or Cursor to drive browser automation sessions autonomously, which opens the door to AI-driven scraping and web navigation workflows.</p></li></ul><h3>How Oxylabs Headless Compares to Self-Managed Headless Browsers</h3><p>The practical significance of Oxylabs Headless Browser is best understood by contrasting it with the self-managed alternative. When you run Playwright or Puppeteer against a local Chromium instance, you are responsible for the entire stack:</p><ul><li><p>Installing and maintaining the browser binary.</p></li><li><p>Managing proxy rotation and authentication.</p></li><li><p>Implementing CAPTCHA-solving integrations.</p></li><li><p>Applying stealth patches to avoid fingerprinting.</p></li><li><p>Handling concurrency limits.</p></li><li><p>Ensuring your infrastructure scales with your scraping workload.</p></li></ul><p>Oxylabs Headless Browser, instead, abstracts all of that away behind a single WSS endpoint. In practice, this means that your code remains identical to what you would write against a local browser. The connection string is the only thing that changes. </p><p>This makes Oxylabs&#8217; solution particularly suited for teams that need to scale browser-based scraping quickly without investing in dedicated infrastructure engineering.</p><p>As a final note, it&#8217;s worth considering that billing is based on traffic consumed (per GB). This means traffic optimization becomes an important cost management practice when operating at scale.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h2>Testing Common Anti-bots The Hard Way: Step-by-step Tutorial on How to Hit Them Headless Mode</h2><p>In this section, you will learn how to hit common anti-bots in headless mode using Playwright. The idea is to compare the results obtained in headless mode with the ones obtained using Oxylabs Headless Browser.</p><p>The target websites with their anti-bots are:</p><ul><li><p>Ssense &#8594; Cloudflare</p></li></ul><ul><li><p>Gucci &#8594; Akamai</p></li><li><p>Loccitane &#8594; DataDome</p></li><li><p>Empire-cat&#8594; Kasada</p><p></p></li></ul><p>Let&#8217;s get into the tutorial!</p><h3>Prerequisites and Requirements</h3><p>To replicate this tutorial, you need at least <a href="https://www.python.org/downloads/">Python 3.8</a> installed on your machine.</p><p>Create a new folder for your project:</p><pre><code><code>mkdir test-antibots</code></code></pre><p>At the end of this step, the <em>test-antibots/</em> folder will have the following structure:</p><pre><code><code>test-antibots/
   |
   |-- tester.py
   |
   |__ venv/</code></code></pre><p>Where:</p><ul><li><p><em><a href="http://tester.py">tester.py</a></em> is the Python file that contains the scraping logic to test the antibots.</p></li><li><p><em>venv/</em> is the folder that contains the <a href="https://docs.python.org/3/library/venv.html">virtual environment</a>.</p></li></ul><p>All the files can also be downloaded <a href="https://github.com/TheWebScrapingClub/TheScrapingClubFree/tree/main/Oxylabs%20Browser">from our GitHub repository, available to anyone</a>.</p><p>In the activated virtual environment, install the needed libraries:</p><pre><code><code>pip install playwright chromium</code></code></pre><p>Very well. You are ready to code your tester!</p><h3>Step #1: Code The Scraper to Test the Anti-bots</h3><p>To test the antibots, write the following in <em>tester.py</em>:</p><pre><code><code>from playwright.sync_api import sync_playwright

# Target pages with their anti-bots
targets = [
    ("&lt;https://www.ssense.com/en-us/men/designers/acne-studios&gt;", "Cloudflare"),
    ("&lt;https://www.gucci.com/us/en/pr/women/shoes-for-women/sandals-for-women/flat-sandals-for-women/womens-slide-sandal-with-horsebit-p-834427AAE046273&gt;", "Akamai"),
    ("&lt;https://loccitane.com/en-us/olio-jeunesse-divine-30ml-27DH030I22.html&gt;", "DataDome"),
    ("&lt;https://www.empire-cat.com/equipment/used/catalog/aa/j1s03815&gt;", "Kasada")
]

results = []

# List of titles or substrings that indicate common blocks/challenges
BLOCK_INDICATORS = [
    "just a moment", "access denied", "attention required", 
    "cloudflare", "ddos protection", "captcha", "verify you are human"
]

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context()

    for url, antibot in targets:
        page = context.new_page()
        try:
            # We capture the response to check the status code
            response = page.goto(url, wait_until="domcontentloaded")
            page.wait_for_timeout(5000)

            title = page.title() or ""
            status_code = response.status if response else 0
            
            # Validation Logic
            is_blocked = False
            error_reason = ""

            # 1. Check HTTP Status (403 Forbidden is a classic block)
            if status_code &gt;= 400:
                is_blocked = True
                error_reason = f"HTTP {status_code}"
            
            # 2. Check for "Waiting Room" or "Block Page" titles
            elif any(indicator in title.lower() for indicator in BLOCK_INDICATORS):
                is_blocked = True
                error_reason = "Challenge/Block Page detected"
            
            # 3. Check for empty titles (Common with Kasada/DataDome blocks)
            elif not title or title.strip() == "":
                is_blocked = True
                error_reason = "Empty/N/A Title (Hidden Block)"

            if is_blocked:
                results.append({"url": url, "antibot": antibot, "title": title, "status": "fail", "error": error_reason})
                print(f"&#10060; [{antibot}] Blocked: {error_reason}")
            else:
                results.append({"url": url, "antibot": antibot, "title": title, "status": "ok"})
                print(f"&#9989; [{antibot}] Success: {title}")

        except Exception as e:
            error_msg = str(e).split('\n')[0] # Keep it brief
            print(f"&#10060; [{antibot}] Exception: {error_msg}")
            results.append({"url": url, "antibot": antibot, "title": None, "status": "fail", "error": error_msg})

        finally:
            page.close()

    browser.close()

# Print summary table
passed = sum(1 for r in results if r.get("status") == "ok")
failed = len(results) - passed

print("\n" + "=" * 105)
print(f"{'STATUS':&lt;10} {'ANTIBOT':&lt;12} {'RESULT/REASON':&lt;30} {'URL'}")
print("=" * 105)
for r in results:
    status = "&#9989; PASS" if r.get("status") == "ok" else "&#10060; FAIL"
    antibot = r.get("antibot", "N/A")
    # Show the reason if it failed, otherwise show the page title
    display_info = r.get("error") if r.get("status") == "fail" else r.get("title", "N/A")
    print(f"{status:&lt;10} {antibot:&lt;12} {str(display_info)[:28]:&lt;30} {r['url']}")
print("=" * 105)
print(f"&#9989; Passes: {passed}  |  &#10060; Fails: {failed}  |  Total: {len(results)}")
print("=" * 105)</code></code></pre><p>This snippet does the following:</p><ul><li><p>Maps a list of target URLs, each associated with their anti bot.</p></li><li><p>Uses Playwright to launch a Chromium browser in &#8220;headless&#8221; mode.</p></li><li><p>For each target URL, the script:</p><ul><li><p>Opens a new browser page.</p></li><li><p>Attempts to navigate to the site and waits for the initial content to load.</p></li><li><p>Pauses for 5 seconds to see if the page successfully renders the correct content or if it gets blocked/redirected by the site&#8217;s security.</p></li><li><p>Attempts to extract the page title as proof of a successful load.</p></li></ul></li><li><p>Avoids the common trap of assuming a successful page load implies successful data access by checking the HTTP status code, title semantics, and structural integrity (line &#8220;N/A&#8221; titles)-</p></li><li><p>Prints summarized results.</p></li></ul><p>Perfect. The code is ready for launch.</p><h3>Step #2: Launch The Tester And Retrieve Results</h3><p>After launching the scraper, the results are the following:</p><pre><code><code>STATUS     ANTIBOT      RESULT/REASON                  URL
==========================================================================================
&#10060; FAIL     Cloudflare   HTTP 403                       &lt;https://www.ssense.com/en-us/&gt;...
&#10060; FAIL     Akamai       Page.goto: net::ERR_HTTP2_PR   &lt;https://www.gucci.com/us/en/pr/&gt;...
&#10060; FAIL     DataDome     Empty/N/A Title (Hidden Bloc   &lt;https://loccitane.com/en-us/olio-&gt;...
&#10060; FAIL     Kasada       HTTP 429                       &lt;https://www.empire-cat.com/equi&gt;...
===========================================================================================
&#9989; Passes: 0  |  &#10060; Fails: 4  |  Total: 4
===========================================================================================</code></code></pre><p>As you can see, the anti-bots successfully blocked 4 requests on 4:</p><ul><li><p>Cloudflare returned a 403 (forbidden).</p></li><li><p>Akamai returns a <em>Page.goto: net::ERR_HTTP2_PR</em> error, which is often related to fingerprinting.</p></li><li><p>DataDome reported an empty result, which suggests it may have activated a captcha.</p></li><li><p>Kasada returns a 429 error. Generally speaking, a 429 error is a &#8220;too many requests&#8221; error, so the server blocks your scraper because you&#8217;re hitting it too fast. But specifically for Kasada, this often indicates a block due to fingerprinting.</p></li></ul><p>Terrific! You made it to the end of this tutorial. Now it&#8217;s time to see what happens when implementing the Oxylabs solution.</p><h2>Testing Common Anti-bots With Oxylabs Headless Browser: Step-by-step Tutorial</h2><p>In this tutorial section, you will learn how to hit the same websites as in the previous paragraph using Oxylabs Headless Browser.</p><h3>Prerequisites and requirements</h3><p>Other than the requirements previously met, you need an active <a href="https://dashboard.oxylabs.io/en/?utm_source=documentation&amp;utm_medium=organic&amp;utm_campaign=doc_refferal&amp;groupid=17788288593040">Oxylabs account</a> in order to create your username and password for using its headless browser. Also, make sure to match all the <a href="https://developers.oxylabs.io/products/headless-browser#quick-start-examples">requirements needed by the Oxylabs Headless Browser</a>.</p><p>In the <em>test-antibots/</em> folder, create a new Python file that will contain the scraping logic using the Oxylabs product:</p><pre><code><code>test-antibots/
   |
   |-- tester.py
   |
   |-- tester-oxylabs.py
   |
   |__ venv/</code></code></pre><p>Good. You are ready to proceed with the actual tutorial.</p><h3>Step #1: Code The Scraper Using Oxylabs Headless Browser</h3><p>Write the following code in <em>tester-oxylabs.py</em>:</p><pre><code><code>import json
import random
import string
import os
from playwright.sync_api import sync_playwright

# Define params for connecting to Oxylabs servers
username = "&lt;your-oxylabs-username&gt;"
password = "&lt;your-oxylabs-password&gt;"
endpoint = "ubc.oxylabs.io"

# Create folder for screenshots
if not os.path.exists("screenshots"):
    os.makedirs("screenshots")

def get_session():
    return ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))

# Define Chrome arguments
chrome_args = json.dumps([
    "--disable-blink-features=AutomationControlled", 
    "--enable-features=NetworkServiceInProcess"
])

# Define params for Oxylabs Headless Browser
params = f"p_device=mobile&amp;p_cc=US&amp;p_session_id={get_session()}&amp;args={chrome_args}"
browser_url = f"wss://{username}:{password}@{endpoint}?{params}"

targets = [
    ("&lt;https://www.empire-cat.com/equipment/used/catalog/aa/j1s03815&gt;", "Kasada"),
    ("&lt;https://www.ssense.com/en-us/men/designers/acne-studios&gt;", "Cloudflare"),
    ("&lt;https://loccitane.com/en-us/olio-jeunesse-divine-30ml-27DH030I22.html&gt;", "DataDome"),
    ("&lt;https://www.gucci.com/us/en/pr/women/shoes-for-women/sandals-for-women/flat-sandals-for-women/womens-slide-sandal-with-horsebit-p-834427AAE046273&gt;", "Akamai")
]

# Define semantics to intercept in responses
BLOCK_TITLES = ["just a moment", "access denied", "attention required", "security measure", "not acceptable", "403 forbidden"]
results = []

def run_benchmark():
    with sync_playwright() as p:
        for url, antibot in targets:
            print(f"---\nTesting {antibot}...")
            try:
                browser = p.chromium.connect_over_cdp(browser_url)
                context = browser.new_context()
                page = context.new_page()

                captcha_detected = False
                def handle_log(msg):
                    nonlocal captcha_detected
                    if "oxylabs-captcha-solve-start" in msg.text:
                        print(f"   [Solver] {antibot} challenge detected...")
                        captcha_detected = True
                    elif "oxylabs-captcha-solve-end" in msg.text:
                        print(f"   [Solver] {antibot} resolved!")
                        captcha_detected = False

                page.on("console", handle_log)
                page.goto(url, wait_until="domcontentloaded", timeout=60000)
                
                # Wait for the page to stabilize
                if captcha_detected:
                    page.wait_for_timeout(15000)
                else:
                    page.wait_for_timeout(8000)

                # Make and save screenshots
                screenshot_path = f"screenshots/{antibot.lower()}_result.png"
                page.screenshot(path=screenshot_path, full_page=False)
                print(f"   [Camera] Screenshot saved: {screenshot_path}")

                title = page.title() or ""
                low_title = title.lower()
                is_blocked = any(bt in low_title for bt in BLOCK_TITLES)
                
                if len(title) &gt; 5 and not is_blocked:
                    print(f"&#9989; {antibot} PASS: {title[:30]}...")
                    results.append({"url": url, "antibot": antibot, "status": "ok", "title": title})
                else:
                    print(f"&#10060; {antibot} FAIL: {title}")
                    results.append({"url": url, "antibot": antibot, "status": "fail", "error": title})

                browser.close()

            except Exception as e:
                print(f"&#10060; {antibot} Exception: {str(e)[:50]}")

run_benchmark()</code></code></pre><p>Below is what changes with respect to the version in the previous paragraph:</p><ul><li><p>It defines the credentials for connecting to Oxylabs servers and creates a folder where it will later store screenshots.</p></li><li><p>With <em>chrome_args()</em>, it defines some parameters for setting the automation in Chrome.</p></li><li><p>In the string <em>params</em>, the <em><a href="https://developers.oxylabs.io/products/headless-browser/features/device-type">p_mobile</a></em> and <a href="https://app.notion.com/p/Antonello-Data-Flywheel-for-AI-37a945fea5028008b9b3dcd4b2ada203?pvs=21">*p_cc</a>* respectively manage the perceived device type and IP.</p></li><li><p>It manages CAPTCHAs with <em>oxylabs-captcha-solve-start</em> and <em>oxylabs-captcha-solve-end</em>. And since it needs to manage CAPTCHAs at each request, the code now has a timeout that helps the pages stabilize before the scraper passes on to the next target URL.</p></li><li><p>It uses page.screenshot() to make screenshots after the server sends the request and saves them into the previously created folder. This is important because the exceptions can&#8217;t all be handled via intercepting HTTP responses or via semantics. By making a screenshot before the connection is closed, you can actually see if the scraper has passed the anti-bot or if it failed at it.</p></li></ul><p>Good. You&#8217;re now ready to run the code and see the results.</p><h3>Step #2: Launch The Script</h3><p>After launching the scraper, the results are the following:</p><pre><code><code>---
Testing Kasada...
   [Camera] Screenshot saved: screenshots/kasada_result.png
&#9989; Kasada PASS: 2021 CATERPILLAR 950M | Empire...
---
Testing Cloudflare...
   [Camera] Screenshot saved: screenshots/cloudflare_result.png
&#9989; Cloudflare PASS: Latest Acne Studios Collection...
---
Testing DataDome...
   [Camera] Screenshot saved: screenshots/datadome_result.png
&#9989; DataDome PASS: Immortelle Anti-Aging Face Oil...
---
Testing Akamai...
   [Camera] Screenshot saved: screenshots/akamai_result.png
&#9989; Akamai PASS: Slides for Women | Designer Sl...</code></code></pre><p>As you can see, using the Oxylabs Headless Browser, the scraper overcomes all the anti-bots!</p><p>As a final note, consider that, based on the configuration and settings you will actually implement, DataDome (but also other anti-bots) may activate sliding captchas:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QmCl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QmCl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 424w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 848w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 1272w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QmCl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png" width="735" height="591" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:591,&quot;width&quot;:735,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:122036,&quot;alt&quot;:&quot;A sliding CAPTCHA by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/202688828?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A sliding CAPTCHA by Federico Trotta" title="A sliding CAPTCHA by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!QmCl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 424w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 848w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 1272w, https://substackcdn.com/image/fetch/$s_!QmCl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d90a97e-1c01-4abf-87c7-12ab388a9684_735x591.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A sliding CAPTCHA</figcaption></figure></div><p>In this case, the <a href="https://developers.oxylabs.io/products/headless-browser/features/dynamic-captcha-solving">Oxylabs Headless Browser is of no help as it only supports hcaptcha, recaptcha, and turnstile dynamic captchas</a>.</p><p>Hooray! You successfully made it to your first scraping project using the Oxylabs Headless Browser.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>In this article, you learned the actual distinction between headless browsers and browser automation tools. You also discovered the Oxylabs Headless Browser which, despite the name, it&#8217;s cloud-based browser automation. The difference between this and the browser automation tools you already know is that it&#8217;s cloud-based. This means that when it&#8217;s called via the code, it manages all the infrastructure on its own without overhead on your side.</p><p>As you learned in the tutorial section, it&#8217;s also pretty easy to configure and to use: you just need to manage some parameters and call the Oxylabs endpoint.</p><p>So, let us know: were you already using the Oxylabs Headless Browser?</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/oxylabs-headless-browser?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/oxylabs-headless-browser?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div>]]></content:encoded></item><item><title><![CDATA[THE LAB #109: UDP, Proxies, and the WebRTC Leak]]></title><description><![CDATA[The proxy carries the UDP. The browser refuses to hand WebRTC over. We tested every combination to find where your IP actually leaks.]]></description><link>https://substack.thewebscraping.club/p/udp-proxies-and-the-webrtc-leak</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/udp-proxies-and-the-webrtc-leak</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Thu, 02 Jul 2026 03:00:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e7e6b5b3-fee9-4165-abe4-ec0cda3458fc_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>More and more of the web runs on UDP now. HTTP/3 runs over QUIC, QUIC runs over UDP, and a good chunk of the sites we scrape already answer this way. Proxy providers noticed, and some of them started adding UDP support, since that&#8217;s the only way a UDP protocol can pass through a proxy at all. We wanted to understand what this actually gives us as scrapers, because UDP reaches a browser in two very different ways, and a proxy treats them differently.</p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/WyQ3mA" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="555" height="312.1875" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:555,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p><div><hr></div></blockquote><p>The first is the UDP we want, HTTP/3 for our requests. The second is the UDP we never asked for, the WebRTC traffic that a browser generates on its own, which can leak around the proxy and expose our real IP. But supporting UDP and actually getting a client to route its UDP through the proxy are two different problems, and the result changes a lot depending on the client. An HTTP client, a browser doing HTTP/3, and a browser doing WebRTC all behave differently, so we tested all three, end to end, to see where a UDP proxy does the work for us and where we still have to step in on the client side.</p><h2>A quick recap of HTTP/2 and HTTP/3</h2><p>We already covered the request side of HTTP/3 in <a href="https://substack.thewebscraping.club/p/faster-web-scraping-with-http3">Faster Web Scraping with HTTP/3</a>, so let&#8217;s just recap what matters for proxies. HTTP/1.1 and HTTP/2 run on TCP. HTTP/3 drops TCP completely and runs on QUIC, which is built on UDP and merges the transport and TLS handshakes into one. The part that matters for us is the transport: a proxy built to relay TCP has nothing to grab onto in a QUIC connection, since there&#8217;s no TCP stream to relay.</p><p>Adoption is real, but it&#8217;s easy to overstate. If we look at traffic, HTTP/3 is around a fifth of all requests, while HTTP/2 is still the majority at almost half, and this split has stayed roughly the same through 2026 (<a href="https://radar.cloudflare.com/adoption-and-usage">Cloudflare Radar</a>). If we look at site support instead, the number goes up: around 38% of sites advertise HTTP/3 via Alt-Svc (<a href="https://w3techs.com/technologies/details/ce-http3">W3Techs</a>). Italy, where our test machine sits, is one of the higher HTTP/3 markets at about 30%. So HTTP/3 is a serious, well-supported protocol, not some niche thing, but it hasn&#8217;t replaced HTTP/2 yet, and most real traffic is still on TCP.</p><div><hr></div><blockquote><p><em>HTTP/3 and QUIC run on UDP, so the proxy layer has to carry it too. <strong>anyIP</strong> gives compatible clients production-ready SOCKS5 UDP ASSOCIATE across its residential and mobile network.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://anyip.io/proxies/udp-proxy" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f6L2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 424w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 848w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 1272w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f6L2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png" width="556" height="278" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:1075200,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://anyip.io/proxies/udp-proxy&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203043903?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f6L2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 424w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 848w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 1272w, https://substackcdn.com/image/fetch/$s_!f6L2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8be5a9-3a31-49b3-9912-82c5964632b8_4585x2293.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://anyip.io/proxies/udp-proxy?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_1&amp;utm_content=banner_udp&quot;,&quot;text&quot;:&quot;Explore anyIP UDP Proxies&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://anyip.io/proxies/udp-proxy?utm_source=thewebscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=gold_2026_1&amp;utm_content=banner_udp"><span>Explore anyIP UDP Proxies</span></a></p></blockquote><div><hr></div><p>The sales pitch follows naturally from here. If real browsers increasingly speak HTTP/3 and our scraper can&#8217;t, that difference becomes a signal, so we&#8217;d want to speak HTTP/3 too, and to do that through a proxy, the proxy has to carry UDP. </p><p>This is exactly what some providers are now selling. They offer UDP support, usually as a beta over SOCKS5, and they pitch it as a stealth feature: the idea is that most residential traffic is QUIC these days, so a client stuck on TCP stands out. There are two parts of this claim worth checking before relying on it, the stealth side and the tooling side, so we tested both, using a provider that carries UDP and one that doesn&#8217;t.</p><h2>UDP support and the stealth question</h2><p>Switching to HTTP/3 doesn&#8217;t remove protocol fingerprinting, it just moves it somewhere else. Detection happens at three layers, and moving from TCP to QUIC affects each one in a different way.</p><p>The TCP/IP stack fingerprint, meaning the SYN options, window sizes and TTL that give away the OS, really does disappear, because there&#8217;s no TCP handshake anymore. That&#8217;s the only layer that goes away, though. The TLS fingerprint stays exactly as it was, because QUIC still does a TLS 1.3 handshake, just wrapped inside QUIC instead of running over TCP. The ClientHello with its cipher suites and extensions is still there, and JA4 was designed to fingerprint the QUIC variant on purpose (<a href="https://scrapfly.io/web-scraping-tools/http3-quic-fingerprint">Scrapfly QUIC/HTTP3 fingerprint</a>). The HTTP/2 fingerprint, the SETTINGS frames, window updates and pseudo-header order, doesn&#8217;t get erased either. It just gets replaced by an HTTP/3 fingerprint built from QUIC transport parameters.</p><p>And those QUIC transport parameters are basically the same thing we were trying to get away from. Scrapfly says it clearly: they &#8220;work like HTTP/2 SETTINGS frames but at the transport layer.&#8221; Values like <code>max_udp_payload_size</code> and <code>initial_max_data</code>, and the order they come in, are different between Chrome&#8217;s quiche, Firefox, Go&#8217;s quic-go and ngtcp2, and that difference is itself a fingerprint (<a href="https://scrapfly.io/blog/posts/http2-http3-fingerprinting-guide">Scrapfly HTTP/2 and HTTP/3 fingerprinting</a>). QUIC even adds new signals that have no TCP equivalent at all, like 0-RTT behavior and connection migration support.</p><p>So the layer that actually gets scrapers blocked today is TLS and HTTP/2 fingerprinting, which Cloudflare, Akamai and DataDome score together as JA4 and JA4H. That&#8217;s a TCP-side problem, and it&#8217;s one we already solve with a client that imitates a browser&#8217;s handshake. HTTP/3 fingerprinting is growing but still immature. Scrapfly is pretty direct about it: it &#8220;adds signals on top of&#8221; HTTP/2 instead of replacing it, real Chrome on HTTP/2 is still accepted on the vast majority of sites, and the scraper-on-HTTP/2 versus user-on-HTTP/3 gap is only &#8220;starting to become a signal on Cloudflare&#8217;s premium tier.&#8221; There&#8217;s also a catch worth keeping in mind: a scraper that speaks HTTP/3 through a non-browser QUIC stack shows a QUIC fingerprint that matches no real browser, so it can stand out just as easily as it blends in. In other words, a UDP proxy is what gets us onto HTTP/3 in the first place, but the stealth benefit only pays off if the client presents a QUIC fingerprint that a real browser would. The proxy just carries the traffic; making it look right is still our job.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>The tooling has not caught up yet</h2><p>The other half of the pitch is the tooling. The most common client for browserless scraping is <code>curl_cffi</code>, so the real question is whether it can actually do HTTP/3 in the setup a scraper normally runs in. <span>We tested it (</span>run_curl_cffi_http3.py<span>), and you can find the code, as always, </span><a href="https://github.com/TheWebScrapingClub/thelab"><span>on our GitHub repository available for our paid readers</span></a><span>, under the folder </span><strong><span>109.UDP</span></strong></p><p>The library is compiled with the QUIC stack, <code>ngtcp2</code> and <code>nghttp3</code>, and on a plain direct request it does reach HTTP/3. It even reaches HTTP/3 with a full Chrome fingerprint if we use the low-level interface, so impersonation and HTTP/3 aren&#8217;t really in conflict, even if the first error makes it look that way.</p><pre><code><code>high-level requests API:
  plain, no impersonation, V3ONLY        -&gt; HTTP/3
  Chrome impersonation, V3ONLY           -&gt; ERROR: QUIC needs at least TLS version 1.3
  Chrome impersonation, HTTP proxy, V3   -&gt; ERROR: HTTP/3 is not supported over an HTTP proxy
  Chrome impersonation, SOCKS5, V3       -&gt; ERROR: HTTP/3 is not supported over a SOCKS proxy
low-level Curl API (same impersonation):
  impersonate chrome + V3ONLY            -&gt; HTTP/3</code></code></pre><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><p>That middle error in the high-level API is just a TLS-version conflict inside the <code>requests</code> wrapper, not a real limitation, since the low-level call combines the Chrome fingerprint with HTTP/3 and gets there fine. The lines that really matter are the proxy ones. curl refuses HTTP/3 over a proxy completely, both HTTP and SOCKS, and it refuses before it even connects, so this is curl saying no, not the proxy. It happens even with a proxy that could carry the UDP. And since a scraper always runs through a proxy, in practice <code>curl_cffi</code> ends up being HTTP/2 over TCP, and a UDP-capable proxy doesn&#8217;t change that at all.</p><p>So this is the honest picture on the request side. A proxy that carries UDP does its job for a client that tunnels its own UDP, but the popular HTTP clients refuse HTTP/3 over a proxy right now, so the benefit is stuck waiting for the tooling to catch up. The proxy capability is arriving before the clients that could use it, which is good to know before expecting HTTP/3 to flow through a scraper just because the proxy supports UDP.</p><h2>The WebRTC leak, where UDP really bites</h2>
      <p>
          <a href="https://substack.thewebscraping.club/p/udp-proxies-and-the-webrtc-leak">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Public Sector Meets Web Scraping: From Scraped Data to Public Value]]></title><description><![CDATA[Using web scraping to fuel data pipelines that provide value to citizens and policymakers]]></description><link>https://substack.thewebscraping.club/p/public-sector-web-scraping-real-estate</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/public-sector-web-scraping-real-estate</guid><dc:creator><![CDATA[Antonello Zanini]]></dc:creator><pubDate>Sun, 28 Jun 2026 03:01:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0847fa1a-718c-4532-843c-254ba0748dcb_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s no doubt that web scraping supports a wide range of use cases, from price monitoring to data collection for AI model training. Most of these applications focus on generating value for businesses or individuals by supporting decision-making or automating workflows.</p><p>However, web scraping can also serve as a foundation for building the data infrastructure needed to better understand national markets and societal conditions.</p><p>In this blog post, I&#8217;ll show real-world examples of how web scraping is already used in the public sector, and how institutions could leverage it to improve policies and deliver higher-quality services to citizens.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCo7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" width="626" height="313" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:390972,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/197764148?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Before proceeding, let me thank NetNut, the platinum partner of the month. Their set of solutions cover all your needs for scraping.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;text&quot;:&quot;Visit Netnut&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack"><span>Visit Netnut</span></a></p><div><hr></div></blockquote><h2>Why Web Scraping Matters for Public Institutions</h2><p>Public institutions have access to statistical datasets from official sources. These are surely relevant, but they tend to provide a picture of the market only after events have already happened, sometimes months or even a year later.</p><p>That delay creates a challenge. After all, institutions need timely information to understand citizens&#8217; current needs and respond effectively. Another issue is that relevant data is often scattered across many sources, such as different websites, web portals, and marketplaces.</p><p>This is where web scraping can help! By collecting large volumes of publicly available data from multiple sites, institutions can complement and enrich official statistics.</p><p>Data collection is only the first step, though. The real value comes from building a complete data pipeline that includes cleaning, deduplication, aggregation, geolocation, statistical modeling, and interpretation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HzZ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HzZ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 424w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 848w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 1272w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HzZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png" width="1456" height="723" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:723,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Bayernheimerov&#225; Kl&#225;ra during her speech at Prague Crawl 2026&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Bayernheimerov&#225; Kl&#225;ra during her speech at Prague Crawl 2026" title="Bayernheimerov&#225; Kl&#225;ra during her speech at Prague Crawl 2026" srcset="https://substackcdn.com/image/fetch/$s_!HzZ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 424w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 848w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 1272w, https://substackcdn.com/image/fetch/$s_!HzZ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8619ffba-30f3-4287-97af-17b9f368bc1a_2912x1446.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Bayernheimerov&#225; Kl&#225;ra during her speech at Prague Crawl 2026</figcaption></figure></div><p>At Prague Crawl 2026, <a href="https://cz.linkedin.com/in/kl%C3%A1ra-bayernheimerov%C3%A1-53bbaa405">Bayernheimerov&#225; Kl&#225;ra</a> presented a compelling example of this approach. Her talk showed how the <em>Czech Ministry of Finance</em> relies on rental listing data collected by an external provider from several real estate portals and processes it through an end-to-end pipeline based on a dedicated statistical methodology.</p><p>As I&#8217;ll present shortly, the result is a reliable source of insights that supports housing policy decisions and affordable housing programs across the country, while also providing a valuable service to citizens.</p><p>What&#8217;s important to understand is that the goal isn&#8217;t simply to collect raw data, but to power services such as interactive maps, calculators, and dashboards that are useful to both public institutions and citizens.</p><h2>Case Study: Czech Rental Market Intelligence System</h2><p>To see an actual application of web scraping in the public sector, I&#8217;ll now present the initiative developed by the Czech Ministry of Finance for rental price analysis across Czechia.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://visit.decodo.com/WyQ3mA" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="521" height="293.0625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:521,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p></blockquote><div><hr></div><h3>The Motivation Behind the Project</h3><p>Just like in <a href="https://www.europarl.europa.eu/topics/en/article/20241014STO24542/housing-crisis-why-prices-are-rising-and-what-the-eu-is-doing-about-it">many other European countries</a>, housing affordability has become a major social and economic challenge in the Czech Republic. Housing supply has struggled to keep up with demand, causing both property prices and rents to rise steadily across the country.</p><p>To confront this issue, the Czech Ministry of Finance needed detailed and up-to-date information on local rental markets. The initiative was launched specifically to fill that gap, creating a web data analysis process that gives a continuously updated view of rental prices across the entire country.</p><p>The objective is to provide a reliable foundation for housing policy, affordable housing programs, and public-facing tools that help citizens better resonate with local rental markets.</p><h3>Web Data Sourcing</h3><p>The data for this initiative has been collected using <a href="https://apify.com/">Apify</a>, one of the largest marketplaces of ready-made tools for web scraping, automation, and AI.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QcM-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QcM-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 424w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 848w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 1272w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QcM-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png" width="1456" height="771" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:771,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Apify&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Apify" title="Apify" srcset="https://substackcdn.com/image/fetch/$s_!QcM-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 424w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 848w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 1272w, https://substackcdn.com/image/fetch/$s_!QcM-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F853bdd95-9cdc-487b-8abd-7b26009400da_2998x1587.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Apify</figcaption></figure></div><p>If you aren&#8217;t familiar with Apify, it provides over <a href="https://apify.com/store">41,000 ready-made serverless cloud programs </a>(called <em>Actors</em>) to automate a wide range of tasks, including web scraping across thousands of different domains.</p><p>These Actors are developed and maintained by the community (and in some cases by Apify itself) and run on Apify&#8217;s cloud infrastructure. You can use them directly through Apify Console via a no-code interface, or call them programmatically via API. They can also be integrated into workflows such as n8n, Make, Zapier, or AI agents via MCP.</p><p>Two main reasons influenced the choice of Apify:</p><ol><li><p>It&#8217;s a Czech-based company.</p></li><li><p>It enables the Ministry of Finance to gather large-scale, up-to-date information on rental listings without maintaining scraping infrastructure in-house.</p></li></ol><p>In general, a solution like Apify lowers the barrier for public-sector teams, as these may have limited engineering capacity.</p><h3>Downstream Data Pipeline</h3><p>At a high level, this is the <a href="https://mf.gov.cz/cs/rozpoctova-politika/podpora-projektoveho-rizeni/cenova-mapa/metodika">downstream data pipeline</a> implemented by the Czech Ministry of Finance:</p><ol><li><p><strong>Data ingestion</strong>: Collects rental listings via Apify-based web scraping from multiple Czech real estate portals.</p></li><li><p><strong>Data cleaning</strong>: Sorts data and removes duplicates, incorrect entries, and inconsistencies to ensure it is up to date, accurate, and free from deviations or distortions, following the procedure defined in <a href="https://www.cai.cz/OA/pdf/P456_2024_EN.pdf">Decree No. 456/2024 Coll</a>.</p></li><li><p><strong>Geolocation and aggregatio</strong>n: Standardizes addresses, assigns cadastral units, and enriches listings with attributes such as size, amenities, and building type.</p></li><li><p><strong>Statistical modelling</strong>: Uses hedonic regression with spatial and temporal weighting to estimate underlying rental price levels.</p></li><li><p><strong>Output generation</strong>: Presents results as interactive price maps and calculators.</p></li></ol><p><strong>Note</strong>: The pipeline also includes data update and recycling via a rolling window approach. This process adds new listings while retiring outdated observations to keep the dataset current.</p><p>To make rental prices comparable across different locations, the methodology is based on a <em>reference apartment. That represents </em>a standardized apartment profile with predefined characteristics, such as size, type, furnishing level, etc.</p><p>This approach reduces differences caused by individual property features and enables more consistent comparisons of rental price levels across municipalities and cadastral areas.</p><h3>Produced Output and Tools</h3><p>The Czech Rental Housing Price Map consists of two main solutions:</p><ul><li><p><strong><a href="https://mf.gov.cz/cs/rozpoctova-politika/podpora-projektoveho-rizeni/cenova-mapa/cenova-mapa-infografika">Interactive rent price map</a></strong>: Provides estimated rental prices at the level of municipalities and cadastral areas across the Czech Republic.</p></li><li><p><strong><a href="https://mf.gov.cz/cs/rozpoctova-politika/podpora-projektoveho-rizeni/cenova-mapa/kalkulacka-trzniho-najemneho">Market rent calculator</a></strong>: A practical tool that calculates a statistical estimate of rental price levels based on a standardized apartment profile and selected property characteristics.</p></li></ul><p><strong>Important</strong>: The two solutions aren&#8217;t intended to determine the market rent of a specific apartment. Instead, they return statistical estimates based on a standardized reference apartment. So, they&#8217;re intended primarily for market monitoring, regional comparisons, and housing policy analysis.</p><h4>Interactive rent price map</h4><p>The <em>interactive rent price map</em> shows minimum, maximum, and median rents for each area based on market listings, adjusted per square meter for a standard unfurnished reference apartment. It covers four size categories from 1+kk/1+1 to 4+kk/4+1.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P1Z4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P1Z4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 424w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 848w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P1Z4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png" width="1456" height="823" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:823,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Czech interactive rent price map (as displayed on a Google-translated page in English)&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Czech interactive rent price map (as displayed on a Google-translated page in English)" title="The Czech interactive rent price map (as displayed on a Google-translated page in English)" srcset="https://substackcdn.com/image/fetch/$s_!P1Z4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 424w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 848w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!P1Z4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a7993d4-d09a-4e08-ad7d-57faf945ccec_2364x1336.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Czech interactive rent price map (as displayed on a Google-translated page in English)</figcaption></figure></div><p>Note that the map is interactive, and you can zoom in and out to explore individual cadastral areas. It&#8217;s also updated four times per year to ensure current data.</p><h4>Market rent calculator</h4><p>The <em>market rent calculator</em> is available as a form on the Czech government website. It works as follows:</p><ol><li><p>Select the territorial unit where you want to estimate the rent.</p></li><li><p>Choose the size category of the apartment.</p></li><li><p>Enter the floor area of the apartment (if you don&#8217;t know it, the calculator will automatically use a default value for the selected location).</p></li><li><p>Indicate whether the apartment is in a new building.</p></li><li><p>Optionally specify whether the building uses non-standard construction materials (e.g., other than brick or panel).</p></li><li><p>Optionally select additional features such as a terrace, furniture, or an assigned parking/garage space.</p></li><li><p>Click &#8220;Calculate rent&#8221; to obtain an estimate of the monthly market rent (CZK) and the corresponding price level, which represents the final estimated rent for the selected apartment profile.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NWAb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NWAb!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 424w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 848w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 1272w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NWAb!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif" width="794" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a824916b-9219-4efe-ba55-1e66699d364b_794x800.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:794,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Result of a market rent calculator submission (as displayed on a Google-translated page in English)&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Result of a market rent calculator submission (as displayed on a Google-translated page in English)" title="Result of a market rent calculator submission (as displayed on a Google-translated page in English)" srcset="https://substackcdn.com/image/fetch/$s_!NWAb!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 424w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 848w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 1272w, https://substackcdn.com/image/fetch/$s_!NWAb!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa824916b-9219-4efe-ba55-1e66699d364b_794x800.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Result of a market rent calculator submission (as displayed on a Google-translated page in English)</figcaption></figure></div><h3>Impact</h3><p>The project provides a systematic and regularly updated overview of market rental prices across the entire Czech Republic, supporting consistent monitoring of housing market developments over time and across regions.</p><p>Beyond market observation, the outputs serve as a key evidence base for housing policy design and housing programmes within public administration. For example, the State Investment Support Fund (SFPI) relies on these results when working with its affordable rental housing schemes.</p><h2>Web Scraping in the Public Sector: Extending the Model</h2><p>The project carried out by the Czech Ministry of Finance is just one example of a much broader pattern: <em>how web scraping can be used as a foundation for modern public-sector data systems.</em></p><p>In particular, the same pipeline logic can be applied across many other domains. For example, in labor markets, web scraping can be used to collect job postings, salary ranges, and skill requirements from recruitment platforms. This can help governments identify regional skill shortages and design more targeted education or reskilling programmes.</p><p>Similarly, in consumer price monitoring, scraping can track grocery prices, housing costs, and essential goods across regions, enabling better inflation tracking and cost-of-living analysis. Other potential public domains that can benefit from this include energy consumption and transport accessibility.</p><p>When combined, those datasets become even more powerful. For instance, housing data, job market data, and grocery price data could be combined into a broader &#8220;liveability&#8221; index. That would help citizens and policymakers assess the overall affordability of living in a given region.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3>Building a Job Market Choropleth for Czech Districts</h3><p>In this section, I&#8217;ll guide you through building a job market choropleth across Czech districts. The idea is to show how web scraping, combined with a complete data pipeline, can be utilized for other scenarios beyond the previous example.</p><p><strong>Important</strong>: The project below isn&#8217;t related to the initiative from the Czech Ministry of Finance and has been created purely for illustrative purposes.</p><h3>Prerequisites</h3><p>To follow this tutorial section, make sure you have:</p><ul><li><p>An <a href="https://console.apify.com/sign-up">Apify account</a> (a free plan is sufficient).</p></li><li><p><a href="https://www.python.org/downloads/">Python 3.11+</a> installed locally.</p></li></ul><p>I&#8217;ll also assume you have a Python project set up locally with the following libraries installed:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">pip install pandas geopandas geopy matplotlib</code></pre></div><p>These are the required dependencies for this project and will be used as follows:</p><ul><li><p><em>pandas</em>: Load, clean, and manipulate the scraped job posting data before geospatial analysis.</p></li><li><p><em>geopandas</em>: Handle geographic data, perform spatial joins, and create district-level maps.</p></li><li><p><em>geopy</em>: Convert job location addresses into geographic coordinates through geocoding.</p></li><li><p><em>matplotlib</em>: Visualize the results by generating a choropleth map showing job density by district.</p></li></ul><h4>Step #1: Access the Indeed Jobs Scraper Apify Actor</h4><p>Just like in the Czech Ministry of Finance example, you can use Apify to collect the source data. This saves you from building and maintaining a complete job scraping pipeline from scratch.</p><p>For this project, we&#8217;ll use Indeed as the data source. <a href="https://cz.indeed.com/">Indeed has a Czech version</a>, and most listings include the full office address where employees are expected to work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!475m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!475m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 424w, https://substackcdn.com/image/fetch/$s_!475m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 848w, https://substackcdn.com/image/fetch/$s_!475m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 1272w, https://substackcdn.com/image/fetch/$s_!475m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!475m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png" width="1456" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Czech version of Indeed&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Czech version of Indeed" title="The Czech version of Indeed" srcset="https://substackcdn.com/image/fetch/$s_!475m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 424w, https://substackcdn.com/image/fetch/$s_!475m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 848w, https://substackcdn.com/image/fetch/$s_!475m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 1272w, https://substackcdn.com/image/fetch/$s_!475m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5558d37-c909-4466-8ff1-e002a876f299_3024x1596.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Czech version of Indeed</figcaption></figure></div><p>In detail, I recommend using the <em><a href="https://apify.com/borderline/indeed-scraper">Indeed Jobs Scraper [PPR]</a></em> Actor. This automates the extraction of job titles, salaries, locations, company information, and job descriptions from Indeed.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d8Ku!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d8Ku!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 424w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 848w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 1272w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d8Ku!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png" width="1456" height="788" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:788,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Indeed Jobs Scraper [PPR] Actor&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Indeed Jobs Scraper [PPR] Actor" title="The Indeed Jobs Scraper [PPR] Actor" srcset="https://substackcdn.com/image/fetch/$s_!d8Ku!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 424w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 848w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 1272w, https://substackcdn.com/image/fetch/$s_!d8Ku!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff23e4310-03be-4e81-a51a-26a0c8b0c225_3028x1638.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Indeed Jobs Scraper [PPR] Actor</figcaption></figure></div><p>To get started, <a href="https://console.apify.com/">log in to your Apify account</a> and select the &#8220;Apify Store&#8221; option from the left-hand navigation menu. Then, search for &#8220;Indeed Jobs Scraper [PPR]&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RkuG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RkuG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 424w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 848w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 1272w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RkuG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png" width="1456" height="781" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:781,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Selecting the Indeed Jobs Scraper [PPR] Actor&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Selecting the Indeed Jobs Scraper [PPR] Actor" title="Selecting the Indeed Jobs Scraper [PPR] Actor" srcset="https://substackcdn.com/image/fetch/$s_!RkuG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 424w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 848w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 1272w, https://substackcdn.com/image/fetch/$s_!RkuG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc15ea73-ddd2-4de7-a70b-79c5badec120_3026x1624.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Selecting the Indeed Jobs Scraper [PPR] Actor</figcaption></figure></div><p>Click on the Actor card to reach its page. Great!</p><h3>Step #2: Run the Job Scraping Task</h3><p>On the Actor page, you&#8217;ll find an input form that lets you configure the scraper before running it in the cloud. Select &#8220;Czech Republic&#8221; as the &#8220;Country&#8221; and enter &#8220;Software engineer&#8221; in the &#8220;Query&#8221; field:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iAmT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iAmT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 424w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 848w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 1272w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iAmT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png" width="1456" height="784" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:784,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Configuring the Actor run&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Configuring the Actor run" title="Configuring the Actor run" srcset="https://substackcdn.com/image/fetch/$s_!iAmT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 424w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 848w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 1272w, https://substackcdn.com/image/fetch/$s_!iAmT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe61da07b-e6ea-4ec6-a416-0d52b448a1e9_3024x1628.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Configuring the Actor run</figcaption></figure></div><p><strong>Note</strong>: In a real-world scenario, configure the Actor&#8217;s inputs according to your needs.</p><p>Next, toggle the option to avoid duplicates so that the Actor takes care of data deduplication for you:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bEGj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bEGj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 424w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 848w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 1272w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bEGj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png" width="1456" height="547" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:547,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Running the Actor&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Running the Actor" title="Running the Actor" srcset="https://substackcdn.com/image/fetch/$s_!bEGj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 424w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 848w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 1272w, https://substackcdn.com/image/fetch/$s_!bEGj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f001863-b7c3-4dac-b63d-9db197be7265_1628x612.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Running the Actor</figcaption></figure></div><p>Click the &#8220;Save &amp; Start&#8221; button to launch the scraping task. The Actor will start running directly in Apify Console. As the scraper progresses, you&#8217;ll see the extracted job postings appear in real time. Be patient, as the process may take a few minutes depending on the number of matching listings.</p><h4>Step #3: Explore the Output and Export the Results</h4><p>Once the run completes, you&#8217;ll be able to explore the scraped dataset directly in Apify Console. As you can see, the Actor returns structured Indeed job data:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1diH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1diH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 424w, https://substackcdn.com/image/fetch/$s_!1diH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 848w, https://substackcdn.com/image/fetch/$s_!1diH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 1272w, https://substackcdn.com/image/fetch/$s_!1diH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1diH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png" width="1456" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The scraped data in a structured format&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The scraped data in a structured format" title="The scraped data in a structured format" srcset="https://substackcdn.com/image/fetch/$s_!1diH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 424w, https://substackcdn.com/image/fetch/$s_!1diH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 848w, https://substackcdn.com/image/fetch/$s_!1diH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 1272w, https://substackcdn.com/image/fetch/$s_!1diH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F229bf5de-d82b-49cb-8f6f-191223a0caa1_3072x1646.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The scraped data in a structured format</figcaption></figure></div><p>In this case, the Actor retrieved 63 job postings. That may seem like a small number, but keep in mind that the scraper targets only jobs published during the last 14 days. This helps ensure that the dataset reflects the current state of the job market.</p><p>Next, switch to the JSON view and select &#8220;All fields&#8221;. You&#8217;ll notice that each job posting includes a <em>location</em> object containing address information for the position:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!phqa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!phqa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 424w, https://substackcdn.com/image/fetch/$s_!phqa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 848w, https://substackcdn.com/image/fetch/$s_!phqa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!phqa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!phqa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png" width="1456" height="811" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:811,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the &#8220;location&#8221; field on each job object in the scraped JSON dataset&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the &#8220;location&#8221; field on each job object in the scraped JSON dataset" title="Note the &#8220;location&#8221; field on each job object in the scraped JSON dataset" srcset="https://substackcdn.com/image/fetch/$s_!phqa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 424w, https://substackcdn.com/image/fetch/$s_!phqa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 848w, https://substackcdn.com/image/fetch/$s_!phqa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!phqa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a4c1481-fc0f-4dc1-9f09-6ae9bdba8709_2584x1440.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the &#8220;location&#8221; field on each job object in the scraped JSON dataset</figcaption></figure></div><p>That location data is exactly what you need to visualize job openings on a map and analyze their geographic distribution across Czech districts.</p><p>Finally, open the &#8220;Storage&#8221; tab, select the &#8220;JSON&#8221; export format, and click &#8220;Download&#8221; to export the scraped dataset:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Q-Mi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 424w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 848w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 1272w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Downloading the dataset&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Downloading the dataset" title="Downloading the dataset" srcset="https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 424w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 848w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 1272w, https://substackcdn.com/image/fetch/$s_!Q-Mi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d7ee34b-f39c-4fd2-9b0d-81592b4287fb_2566x1444.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Downloading the dataset</figcaption></figure></div><p>A file with a name similar to <em>dataset_indeed-scraper_2026-06-18_11-54-00-555.json</em> will be downloaded. Rename it to <em>jobs.json</em> and place it in your Python project&#8217;s root directory.</p><h3>Step #4: Download the Required Czech GeoJSON Data</h3><p>To visualize the distribution of job openings across Czech districts, you&#8217;ll need a <a href="https://geojson.org/">GeoJSON dataset</a> containing the geographic boundaries of those districts.</p><p>Generally, that type of data is open and publicly available. For example, one possible source is the <em><a href="https://github.com/siwekm/czech-geojson">siwekm/czech-geojson</a></em> repository, which provides GeoJSON files for various Czech administrative divisions:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2hV0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2hV0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 424w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 848w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 1272w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2hV0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png" width="1456" height="772" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:772,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Downloading the &#8220;okresy.json&#8221; file from the siwekm/czech-geojson repository&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Downloading the &#8220;okresy.json&#8221; file from the siwekm/czech-geojson repository" title="Downloading the &#8220;okresy.json&#8221; file from the siwekm/czech-geojson repository" srcset="https://substackcdn.com/image/fetch/$s_!2hV0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 424w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 848w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 1272w, https://substackcdn.com/image/fetch/$s_!2hV0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bad6e02-74aa-4b7e-80fa-672dcd82682c_3036x1610.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Downloading the &#8220;okresy.json&#8221; file from the siwekm/czech-geojson repository</figcaption></figure></div><p>Download the <em>okresy.json</em> file, which contains the geographic boundaries of Czech districts (<em>okresy</em> in Czech).</p><p><strong>Note</strong>: Although the <em><a href="https://en.wikipedia.org/wiki/Districts_of_the_Czech_Republic">okresy</a></em><a href="https://en.wikipedia.org/wiki/Districts_of_the_Czech_Republic"> administrative system was officially abolished in 2003</a>, these districts are still used for statistical analysis. This makes them a good choice for visualizing the distribution of job opportunities across the country.</p><p>Once downloaded, add the <em>okresy.json</em> file to your Python project. At this point, your project structure should look similar to this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">&#9500;&#9472;&#9472; jobs.json
&#9500;&#9472;&#9472; okresy.json
&#9492;&#9472;&#9472; main.py</code></pre></div><h3>Step #5: Visualize the Job Data on a Map</h3><p>In your Python file, define the complete pipeline with the following code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># pip install pandas geopandas geopy matplotlib

import json
from geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt

# Load the scraped Indeed job openings
with open("jobs.json", "r", encoding="utf-8") as f:
    jobs = json.load(f)

# Load the list of addresses from the job postings
addresses = []
for job in jobs:
    loc = job.get("location", {})

    # Prefer fullAddress, fallback to formattedAddressLong or formattedAddressShort
    address = (
        loc.get("fullAddress")
        or loc.get("formattedAddressLong")
        or loc.get("formattedAddressShort")
    )

    # Filter out full-remote jobs with no address
    if address and address.strip().lower() not in ["home office", "remote"]:
        addresses.append(address)

addresses = list(addresses)

# Initialize geocoder for Czech job locations
geolocator = Nominatim(user_agent="cz_job_map")
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)

# Geocode all job addresses into latitude/longitude points
rows = []
for address in addresses:
    loc = geocode(f"{address}, Czech Republic")

    # Keep only successfully geocoded results
    if loc:
        rows.append({
            "address": address,
            "lat": loc.latitude,
            "lon": loc.longitude
        })

# Convert geocoded results into a DataFrame
df = pd.DataFrame(rows)

# Convert DataFrame into GeoDataFrame with point geometries
points = gpd.GeoDataFrame(
    df,
    geometry=gpd.points_from_xy(df.lon, df.lat),
    crs="EPSG:4326"
)

# Load Czech administrative districts (okresy) from a local GeoJSON file
okresy = gpd.read_file("okresy.json")

# Align coordinate reference systems between datasets
if okresy.crs != points.crs:
    okresy = okresy.to_crs(points.crs)

# Assign each job point to its corresponding district
joined = gpd.sjoin(
    points,
    okresy,
    predicate="within",
    how="left"
)

# Count number of jobs per district
counts = (
    joined["id"]
    .value_counts()
    .reset_index()
)

counts.columns = ["id", "count"]


# Merge job counts back into district geometries
okresy = okresy.merge(
    counts,
    on="id",
    how="left"
)

# Replace missing values with 0 (districts with no jobs)
okresy["count"] = okresy["count"].fillna(0)

# Plot choropleth map with job counts per district
fig, ax = plt.subplots(figsize=(10, 8))

okresy.plot(
    column="count",
    cmap="Reds",
    edgecolor="black",
    linewidth=0.3,
    legend=True,
    vmin=0,
    ax=ax
)

# Add labels for districts with job activity
top = okresy[okresy["count"] &gt; 0].sort_values("count", ascending=False)

for idx, row in top.iterrows():
    centroid = row.geometry.centroid

    ax.text(
        centroid.x,
        centroid.y,
        str(int(row["count"])),
        fontsize=9,
        ha="center",
        va="center",
        color=(lambda v: "white" if v &gt; okresy["count"].max() * 0.5 else "black")(row["count"]),
        fontweight="bold"
    )

ax.set_title(
    "Software engineering job density on Indeed in the Czech Republic (last 14 days, by district)"
)
ax.axis("off")

plt.show() </code></pre></div><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><p>That&#8217;s what the above script does:</p><ol><li><p>Loads scraped job data from <em>jobs.json</em> and extracts valid physical addresses, filtering out remote or missing location entries.</p></li><li><p>Initializes the <em><a href="https://nominatim.org/">Nominatim</a></em><a href="https://nominatim.org/"> geocoder</a> with a rate limiter to safely convert addresses into latitude and longitude without exceeding request limits.</p></li><li><p>Geocodes each address into coordinates and keeps only successful results, storing them in a structured pandas <em>DataFrame</em>.</p></li><li><p>Converts the <em>DataFrame</em> into a <em><a href="https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoDataFrame.html">GeoDataFrame</a></em> with point geometries so the job data can be used in spatial analysis workflows.</p></li><li><p>Loads Czech district boundaries from the <em>okresy.json</em> file and ensures both datasets use the same coordinate reference system.</p></li><li><p>Performs a spatial join to assign each job point to a district, then aggregates job counts per district and merges results back into the map.</p></li><li><p>Visualizes the final dataset as a choropleth map, coloring districts by job density and adding readable labels for high-activity areas.</p></li></ol><h3>Step #6: Run the Script</h3><p>Execute the script, and you&#8217;ll get a result like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_TvK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_TvK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 424w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 848w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 1272w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_TvK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png" width="1456" height="836" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:836,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The map produced by the script&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The map produced by the script" title="The map produced by the script" srcset="https://substackcdn.com/image/fetch/$s_!_TvK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 424w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 848w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 1272w, https://substackcdn.com/image/fetch/$s_!_TvK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F931a517a-9779-46bb-92b0-239a1c0172a4_2462x1414.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The map produced by the script</figcaption></figure></div><p>Notice how most fresh software engineering openings are concentrated in districts surrounding Prague, Brno, and Ostrava. These are the three largest cities in the Czech Republic, so the result clearly makes sense!</p><p>Now, this was just a simple example, but you can use the same approach to build an interactive map or add additional features, such as calculating the average salary for each position by district, and more advanced analytics.</p><h2>Value and Playbook for Other Governments</h2><p>The approach presented in this blog post is highly adaptable to any public dataset with a spatial dimension, where location plays a key role in understanding patterns and inequalities. Still, a reusable country-independent playbook emerges:</p><ol><li><p>Collect data via web scraping (or other administrative, public sources).</p></li><li><p>Clean and validate the data.</p></li><li><p>Enrich and aggregate it with contextual and geographic features.</p></li><li><p>Apply statistical or analytical models.</p></li><li><p>Present the results through maps, dashboards, or other interactive tools.</p></li></ol><p>As you can tell, this pipeline isn&#8217;t domain-specific and can be reused across many different policy areas. Finally, it&#8217;s crucial that the adopted methodology remains open and clearly explained to the public. This fosters transparency, reproducibility, and trust in data-driven decision-making.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Conclusion</h2><p>Here, I&#8217;ve shown how the Czech Ministry of Finance uses a web scraping service as part of a full data pipeline to turn rental listings into actionable insights for housing policy and public tools.</p><p>By accessing data collected from multiple real estate portals and processing it through cleaning, geolocation, and statistical modelling, they transform raw web data into interactive maps and rent calculators that support decision-making.</p><p>In this article, I built a similar pipeline for a different use case: a job market choropleth across Czech districts. I started from scraped Indeed listings, geocoded job locations, mapped them to districts, and visualized the results on a map.</p><p>I hope this example was useful and inspiring. If you have questions or ideas, feel free to share them in the comments below.</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/public-sector-web-scraping-real-estate?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/public-sector-web-scraping-real-estate?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[THE LAB #108: How LLMs and Manus AI are transforming bot detection]]></title><description><![CDATA[AI is making faster and cheaper to deobfuscate code. This changes how antibot solutions should be built.]]></description><link>https://substack.thewebscraping.club/p/the-lab-108-how-llms-and-manus-ai</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/the-lab-108-how-llms-and-manus-ai</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Fri, 26 Jun 2026 09:33:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8a36775a-3d27-4850-9f9e-39d54e5b8d7e_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>On June 12, 2026, the US government ordered Anthropic to cut off public access to its two strongest models, Claude Fable 5 and Claude Mythos 5. <a href="https://techcrunch.com/2026/06/12/anthropics-safety-warnings-may-have-just-backfired-the-government-has-pulled-the-plug-on-its-most-powerful-ai/"><span>TechCrunch</span></a><span>&nbsp;broke the order, and&nbsp;</span><a href="https://time.com/article/2026/06/13/anthropic-fable-mythos-ban-US-security/"><span>Time</span></a><span>&nbsp;confirmed the company complied worldwide within a day.</span> Fable 5 had shipped three days earlier as the &#8220;safe to use&#8221; and generally available model. Mythos 5 was the more capable sibling, never opened to everyone. Anthropic&#8217;s own account is that someone found a jailbreak around Fable&#8217;s safety layer, the part built to block answers in cybersecurity and biology, and the government decided the risk of leaving it running was too high. <br>Not everyone agrees with this decision: <a href="https://www.scientificamerican.com/article/us-limits-on-anthropic-fable-ai-could-hurt-cybersecurity/">Scientific American</a> argued the restriction could end up hurting defenders more than attackers, but the fact is that, up to today, nothing has changed. </p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCo7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" width="626" height="313" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:390972,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/197764148?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Before proceeding, let me thank NetNut, the platinum partner of the month. Their set of solutions cover all your needs for scraping.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;text&quot;:&quot;Visit Netnut&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack"><span>Visit Netnut</span></a></p></blockquote><blockquote><div><hr></div></blockquote><p>You can read that episode two ways. Either the guardrails were the only thing standing between a public model and a stream of attack-ready output, or the shutdown was a tidier story than the truth. We are not going to settle that here. For our corner of the world, the lesson is simpler. A capable model, stripped of guardrails or jailbroken around them, automates the expensive part of an attacker&#8217;s job. Deobfuscation, code analysis, and figuring out how an unfamiliar system behaves under pressure. Those tasks have always gated the scraper-versus-vendor arms race because they cost human reverse-engineering hours, and that gate is now moving.</p><p>The cat-and-mouse game we cover every week runs on a hidden economy. A vendor ships an obfuscated sensor. Someone on the scraping side spends days or weeks reading minified JavaScript, renaming variables, and rebuilding the logic until the parameters make sense. The cost of that labor is what keeps most protections standing. If a model can do a real share of it on its own, the math behind the whole arms race changes.</p><h2>Manus AI, and why not Claude</h2><p><a href="https://manus.im/invitation/BRAWNVUL1U09EW?utm_source=invitation&amp;utm_medium=social&amp;utm_campaign=copy_link">Manus</a> is not a chat assistant. It is an agent that pairs a language model with a sandboxed virtual machine, and inside that machine, it runs code, fetches pages, beautifies scripts, and iterates on its own output. Meta acquired it at the end of December 2025 for around two billion dollars, though by June 2026, Chinese regulators were already forcing parts of that deal to unwind. What that architecture buys is verification. Manus not only describes what a script might do. It runs the script and checks.</p><p>That difference shows up the moment you set guardrails next to it. Ask Claude or ChatGPT to deobfuscate a live anti-bot sensor and explain which signals feed its scoring, and you tend to hit a wall. Those products keep tight cybersecurity guardrails, and the Fable shutdown is the clearest sign yet of how hard that line is enforced. We handed the same class of task to Manus, and it got to work. We have looked at agentic browsers and AI scraping assistants before, but those were aids for a human operator who still did the thinking. Here, the model does the reverse engineering.</p><div><hr></div><blockquote><p><strong><a href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE">Start your scraping journey with Byteful</a></strong>: 10GB New Customer Trial | Use TWSC for 15% OFF | $1.75/GB Residential Data | ISP Proxies in 15+ Countries</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png" width="630" height="69.35779816513761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1090,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:133037,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://byteful.com/?promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/194398731?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;text&quot;:&quot;Claim your 10GB here&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE"><span>Claim your 10GB here</span></a></p></blockquote><div><hr></div><h2>Mapping Akamai on Net-a-Porter</h2><p>We have written about Akamai more than any other anti-bot system. For the bypass-oriented background, <a href="https://substack.thewebscraping.club/p/the-lab-30-how-to-bypass-akamai-protected">THE LAB #30</a>, <a href="https://substack.thewebscraping.club/p/bypass-akamai-bot-protection">THE LAB #85</a>, and <a href="https://substack.thewebscraping.club/p/hybrid-scraping-camoufox-curl-cffi">THE LAB #100</a> cover the recovery-when-nothing-works case, proxy chaining, and the browser-login-plus-HTTP hybrid. We will not repeat any of that.</p><p>What we wanted this time was not a bypass. It was a map. Akamai Bot Manager protects net-a-porter.com, and it defends in stacked layers that each fail differently:</p><ul><li><p>A TLS fingerprint check at the edge, evaluated before a single line of the client JavaScript runs.</p></li><li><p>A <code>sec-cpt</code> cryptographic challenge, whose state lives in the <code>bm_sc</code> cookie.</p></li><li><p>A behavioral sensor that serializes a binary telemetry payload and posts it to a collect endpoint, validating the <code>_abck</code> cookie.</p></li><li><p>A client-side anti-hook layer that checks the browser environment for tampering and reports integrity separately.</p></li></ul><p>The model we asked Manus to build covers the client sensor and the challenge flow, plus whatever it could observe about the TLS gate from the outside. A working end-to-end bypass was out of scope. We are not shipping code with this article, and we did not ask Manus to produce a runnable solver, even though our tests suggest we are really close to a working solution. What we&#8217;ll share here is a summary of the analysis Manus did; <a href="https://github.com/TheWebScrapingClub/thelab">in the code repository</a>, you will find the full details.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>What we handed the agent</h2><p>The task was deliberately cold. We did not give Manus our own Akamai notes, our wiki, or any of the prior Lab articles. We pointed it at net-a-porter.com and asked it to study how Akamai's protection works, deobfuscate the client script, and explain which parameters feed into the sensor. Nothing more.</p><p>We chose this target for three reasons. It runs a real, current Akamai deployment on a high-value luxury store. The sensor was observable live, so the agent could fetch and instrument the actual script rather than reason about a stale sample. And we already understand Akamai well enough internally to judge whether the output was accurate or confident nonsense.</p><p>The reason the task went to Manus rather than a chat assistant is the guardrail gap from the previous section. Deobfuscating a production anti-bot sensor and enumerating the signals it scores is exactly the kind of request the heavily guarded models decline. Manus took it, ran the analysis in its VM, and came back with the two documents below.</p><h2>What came back</h2><p>The output was more detailed than we expected from a single task run. We are sharing it in two parts and deliberately not sharing it all.</p><blockquote><p>The two documents below are Manus AI&#8217;s output. We reproduce them as reportage, to show what an agent derived on its own. We have not independently re-run every claim, re-derived every value, or confirmed that each detail still holds against the live site. Treat the specifics as the agent&#8217;s findings, not as TWSC-verified ground truth. The sensor version Manus reports, <code>746702557</code>, was compiled on 2025-05-09, so some details may already have rotated. Where the agent surfaced operational specifics that amount to a turnkey recipe (exact module filenames, the full endpoint table, the CSS selector ids, the challenge request names), we have redacted them.</p></blockquote><p>This is a schema of how Akamai Bot Protection according to Manus AI</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w8Cc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w8Cc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 424w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 848w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 1272w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w8Cc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png" width="1456" height="1561" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1561,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:436306,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/203671348?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!w8Cc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 424w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 848w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 1272w, https://substackcdn.com/image/fetch/$s_!w8Cc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61291bf5-14fa-4123-8412-d0cae6828096_3120x3344.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Part one, reproduced in full, the anti-hooking and TLS summary</h3><p>This first document is the safe exhibit. It explains how Akamai detects a tampered browser and how the TLS gate at the edge decides who even gets a challenge. We reproduce it verbatim.</p><div class="callout-block" data-callout="true"><h4>Akamai Bot Manager: Anti-Hooking and TLS Fingerprinting Summary</h4><p><strong>Target:</strong> <code>www.net-a-porter.com</code><br><strong>Sensor Version:</strong> 746702557<br><strong>Author:</strong> Manus AI</p><p>This document isolates and summarizes two of the most critical defensive layers in Akamai Bot Manager (BM): its client-side anti-hooking mechanisms and its edge-level TLS fingerprinting. These two systems work in tandem to defeat headless browsers, automated scraping frameworks, and reverse-engineering attempts.</p><h5>1. Anti-Hooking Mechanisms</h5><p>Akamai&#8217;s client-side script goes to extraordinary lengths to ensure the browser environment is pristine. The anti-hooking logic is primarily housed in the dynamically loaded <code>h</code> module.</p><p><strong>1.1 Native Function Verification.</strong> Scraping frameworks often override native browser APIs (such as <code>navigator.webdriver</code> or <code>HTMLCanvasElement.toBlob</code>) to spoof a legitimate environment. Akamai detects these overrides using several techniques. It uses <code>Function.prototype.toString</code> inspection to check whether native functions still return the expected <code>[native code]</code> string, and it detects whether the <code>toString</code> method itself has been hooked or proxied. It uses <code>Object.getOwnPropertyDescriptor</code> to inspect the getters and setters of critical APIs, and a property that should be read-only but carries a custom getter is flagged as tampered. It also checks for JavaScript <code>Proxy</code> objects wrapping standard DOM APIs, a common technique in tools like Puppeteer Stealth.</p><p><strong>1.2 The &#8220;Clean iframe&#8221; technique.</strong> To bypass hooks placed on the main <code>window</code> object by automation tools, the scheduler class dynamically injects a hidden iframe into the DOM:</p><pre><code><code>&lt;iframe height="0" width="0" style="display: none; visibility: hidden;" sc="true" tabindex="-1"&gt;&lt;/iframe&gt;</code></code></pre><p>Once injected, Akamai extracts pristine, unmodified API references directly from <code>iframe.contentWindow</code>. This lets the script call the original native functions even if the main <code>window</code> object has been heavily spoofed.</p><p><strong>1.3 The anti-hook verification payload (</strong><code>/ah</code><strong>).</strong> The anti-hook module computes a cryptographic hash representing the integrity of the environment. This check runs as a &#8220;Type 3&#8221; callback in the scheduler, so it executes before the main telemetry payload is serialized. The result is sent to the <code>/ah</code> endpoint. If the environment is clean, the URL parameter <code>ah=0</code> is transmitted. If verification is pending or failed, it transmits <code>ah=1</code>.</p><h5>2. TLS Fingerprinting and Edge Escalation</h5><p>While the anti-hook mechanisms operate in the browser, Akamai&#8217;s most formidable defense occurs at the edge server level via TLS fingerprinting.</p><p><strong>2.1 The TLS barrier.</strong> Before the client-side JavaScript even executes, the Akamai edge server evaluates the incoming connection&#8217;s TLS fingerprint (JA3/JA4 hashes, cipher suites, ALPN extensions). Empirical testing on net-a-porter.com revealed a strict dichotomy. Consumer TLS, for example Safari emulated via <code>curl_cffi</code>, gets a <code>200 OK</code> response carrying the <code>sec-cpt</code> cryptographic challenge. This is a soft block that lets legitimate browsers prove their authenticity. Headless or automation TLS, for example standard Node.js or Puppeteer Chromium, gets an immediate <code>403 Access Denied</code> that bypasses the challenge flow entirely.</p><p><strong>2.2 The escalation trap.</strong> The most critical finding about Akamai&#8217;s architecture is how TLS fingerprinting intersects with the client-side behavioral telemetry behind the <code>_abck</code> cookie. A request with a valid TLS fingerprint receives the <code>sec-cpt</code> challenge, and solving it updates the <code>bm_sc</code> cookie by appending <code>~0~0~0</code>. At the same time, the browser must send a rich, roughly 2.2KB binary payload to the <code>/collect</code> endpoint to validate the <code>_abck</code> cookie. If an automated tool solves the <code>sec-cpt</code> challenge but fails to provide a valid behavioral payload, or sends it over a connection with a mismatched TLS fingerprint, the edge server detects the anomaly.</p><p>The result is that even if a real Chromium browser driven by Puppeteer Stealth generates a mathematically perfect 2,199-byte behavioral payload and solves the challenge, Akamai still refuses to validate the <code>_abck</code> cookie, because it detects the Puppeteer TLS fingerprint at the edge. The server then escalates and returns a permanent <code>403 Access Denied</code> for that session.</p><p><strong>2.3 Summary.</strong> Akamai requires perfect synchronization of a trusted network-level TLS fingerprint and pristine browser-level behavioral data. Spoofing the browser environment, which trips the anti-hook defenses, or using a non-standard TLS stack, guarantees session termination.</p></div><h3>Part two, reproduced with redactions, the deep technical analysis</h3><p>The second document goes much further. It walks the bootstrapping sequence, the module system, the fingerprinting surface, and the telemetry transport. This is the part that starts to read like a blueprint, so we keep the architecture and the reasoning and we strip the operational specifics. Redaction markers below are ours, not Manus&#8217;s.</p><p>If you want to see the full analysis, you can find it&nbsp;<a href="https://github.com/TheWebScrapingClub/thelab">in our GitHub repository reserved for paying users, inside the folder&nbsp;</a><strong><a href="https://github.com/TheWebScrapingClub/thelab">108.</a></strong><a href="https://github.com/TheWebScrapingClub/thelab">AKAMAI-MANUS</a><strong><a href="https://github.com/TheWebScrapingClub/thelab">.</a></strong></p>
      <p>
          <a href="https://substack.thewebscraping.club/p/the-lab-108-how-llms-and-manus-ai">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Crawl of Fame - June 2026]]></title><description><![CDATA[What's an ISP proxy, how they get sourced, and how to spawn browsers for cheap]]></description><link>https://substack.thewebscraping.club/p/crawl-of-fame-june</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/crawl-of-fame-june</guid><dc:creator><![CDATA[Pierluigi Vinciguerra]]></dc:creator><pubDate>Tue, 23 Jun 2026 20:58:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3675f58f-7dd6-4877-9004-b1662fb09f73_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Episode #0 of this new series of posts, where I share with you the most interesting content out there I&#8217;ve read about web scraping and all the things related.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" width="626" height="313" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:390972,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/197764148?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Before proceeding, let me thank NetNut, the platinum partner of the month. Their set of solutions cover all your needs for scraping.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;text&quot;:&quot;Visit Netnut&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack"><span>Visit Netnut</span></a></p></blockquote><div><hr></div><h2>IP sourcing in the proxy industry</h2><p>Two articles written by Spur Intelligence caught my attention in the past week.<br>It started with a webinar I&#8217;ve attended, where they explained what ISP proxies are and how proxy companies get those IPs.</p><div id="youtube2-MQ1zpnlMMUc" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;MQ1zpnlMMUc&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/MQ1zpnlMMUc?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>The analysis is great, and I&#8217;ve understood better how the proxy industry works.  <br>They also mentioned how NetNut gets high-quality ISP IP addresses, and described that in detail in this article.</p><h3>How Proxy Providers Co-opt Entire Networks</h3><p>Spur reverse-engineers how Netnut sources its ISP proxies through a partner called DiviNetworks, which installs GRE tunnels and policy-based routing directly on the border routers of real ISPs. The result is genuine ISP IP space sold as proxy inventory, with actual subscribers still living on the same addresses. The piece is worth reading for the detection detail: outbound connections sit in the TCP source port range 40,000 to 40,200, partner routers expose an <code>rtr-&lt;isp&gt;.divinetworks.com</code> passive-DNS pattern, and the Howard University case shows an entire /16 (AS919, around 17,000 exit IPs) co-opted at the network edge. They even quote DiviNetworks&#8217; own figure of $13,208 a month for a US /16.<br><a href="https://spur.us/blog/how-proxy-providers-co-opt-entire-networks">Full article here</a></p><h3>Smart TV Apps and Residential Proxy SDKs</h3><p>A more recent article, instead, highlighted how proxy companies get residential proxies. No surprises, at least on my side, in reading that Smart TVs are used as exit nodes for proxies. In fact, just like with mobile apps, developers can use SDKs from proxy providers to monetize their app installations. In some cases, it&#8217;s quite clear from the consent screen what&#8217;s happening under the hood. </p><p>All the industries that rely on web-scraped data (AI in primis, but not only) need residential proxies, so proxy providers, who are the gatekeepers for these tools, should be very careful about onboarding users with legitimate use cases and keeping fraudsters away. In my career, I&#8217;ve worked with almost every big name out there, and I&#8217;ve found this is the case. As scraping professionals, we should always remember that we&#8217;re guests (sometimes unwanted) on both the target website and the proxy infrastructure, so we should be as respectful as possible and not be driven by greed to collect data.<br><a href="https://spur.us/blog/smart-tv-apps-residential-proxy-sdks">Full article here</a></p><h2>Scraping Infrastructure</h2><p>A great article by the engineering team at Browser Use shows how they&#8217;re spawning browsers cheaply and quickly.</p><h3>How We Made Cloud Browsers 3x Cheaper and Faster<span> </span></h3><p><span>Browser Use walks through rebuilding its cloud so every session is its own Firecracker microVM, and the interesting twist is that they run Firecracker on plain EC2 instead of bare metal, accepting nested virtualization to get faster scale-up and lower cost. </span></p><p><span>The numbers are great: $0.02 per browser hour down from $0.06, VM cold start under 400ms, and create latency of 825ms at p50 across a 10,000-session test. </span></p><p><span>The engineering details that are making the difference are multiple, from mapping memory in 2MB pages plus a </span><code>userfaultfd</code><span> handler that preloads hot pages (resume-to-ready drops from 9.8s to 3.1s, roughly 91x fewer page-fault stalls) to two-phase vCPU pinning that took a 1,000-browser launch from 17% failed sessions to zero. They also make the case for running fully headless rather than headful, since their low-level Chromium fork pushes block-avoidance to 81% on their own benchmark.</span></p><p><a href="https://browser-use.com/posts/firecracker-browser-infra"><span>Full article here</span></a></p><div><hr></div><h2>Read and share more of this</h2><p>Want to flag and discover more articles like the ones above? <a href="https://news.thewebscraping.club/">Scraping News</a> (still in beta) is where the community surfaces them. <strong>Sign up</strong> and submit what you find worth reading.</p><p>Want a concept map of everything covered here, cross-referenced with our own work and other sources worth your time? </p><p><a href="https://github.com/TheWebScrapingClub/scraping-wiki/tree/main">The Web Scraping Club Wiki lives on GitHub</a>, and <a href="https://publish.obsidian.md/twsc-public/Web+Scraping/Wiki/README">as an interactive site</a>. It is plain Markdown, so you can also clone it into your own Obsidian vault and read it locally.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to Build Competitive Intelligence Scrapers That Don't Lie to You]]></title><description><![CDATA[Learn how to build scraping pipelines that are still giving you accurate data 12 months from now]]></description><link>https://substack.thewebscraping.club/p/how-to-build-competitive-intelligence-scraping</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/how-to-build-competitive-intelligence-scraping</guid><dc:creator><![CDATA[Federico Trotta]]></dc:creator><pubDate>Sun, 21 Jun 2026 03:00:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0463db2a-5f58-4cc1-a9de-dd0875d149bb_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you&#8217;ve built a competitive intelligence scraper before, you know the feeling&#8230;</p><p>You set it up, it works, and you forget about it. Three months later, someone asks: <em>&#8220;Hey, did our competitor change their pricing last week?&#8221;</em></p><p>You check the pipeline dashboard, and everything looks fine: all green, no errors, last run successful some hours ago. Then you dig deeper and realize your scraper has been returning empty strings for weeks. The competitor did change their pricing, and you don&#8217;t know when this happened or what was on their website before.</p><p>In this article, you&#8217;ll learn how to build competitive scraping pipelines that make failure structurally (almost) impossible. Let&#8217;s get into it!</p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" width="626" height="313" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:390972,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/197764148?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Before proceeding, let me thank NetNut, the platinum partner of the month. Their set of solutions cover all your needs for scraping.<br></em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;text&quot;:&quot;Visit Netnut&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack"><span>Visit Netnut</span></a></p></blockquote><blockquote><div><hr></div></blockquote><h2>Why Competitive Intelligence Scrapers Break</h2><p>Let&#8217;s start by understanding the most common failure modes that competitive scraping pipelines have:</p><ul><li><p><strong>Structural drift</strong>: This is probably the most common. A competitor renames a CSS class, and your scraper starts returning empty strings. Your database fills with nulls, and nobody notices for weeks because the pipeline is still running.</p></li><li><p><strong>Soft blocks</strong>: These are nastier. You get valid HTTP responses, but the content is a CAPTCHA page or a bot-detection redirect. Your parser sees it as valid HTML, but it finds no data. So, it stores nothing, or, worse, it stores the CAPTCHA page&#8217;s text as if it were real data.</p></li><li><p><strong>Schema rot</strong>: This happens when a competitor evolves their product, but your data model doesn&#8217;t. They add a new pricing tier or split one pricing plan into three. Your scraper extracts what it can and drops the rest. Your competitive analysis is now based on an incomplete picture of their offering.</p></li><li><p><strong>Timezone and locale traps</strong>: This probably needs more attention than the others. The same competitor page can return different prices, currencies, or date formats depending on where the request originates. If your scraper runs from a US server but your competitor detects it and serves EU pricing, you&#8217;re tracking the wrong numbers.</p></li></ul><p>What makes these failures dangerous is that you caused them yourself, unintentionally. Every defensive pattern you added to prevent crashes is exactly what turns a broken scraper into a quietly running one. No exceptions, no alerts, no red dashboards. Just weeks of nulls that nobody notices.</p><p>The rest of this article is about making that invisible failure visible again. Here&#8217;s a visual schema to get you introduced to the solutions proposed below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!niSq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!niSq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 424w, https://substackcdn.com/image/fetch/$s_!niSq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 848w, https://substackcdn.com/image/fetch/$s_!niSq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 1272w, https://substackcdn.com/image/fetch/$s_!niSq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!niSq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png" width="1456" height="1124" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1909562b-4730-4696-bce2-496f109727e7_2366x1826.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1124,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:231842,&quot;alt&quot;:&quot;The schema for creating competitive scraping pipelines that are resilient through time by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/196881482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The schema for creating competitive scraping pipelines that are resilient through time by Federico Trotta" title="The schema for creating competitive scraping pipelines that are resilient through time by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!niSq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 424w, https://substackcdn.com/image/fetch/$s_!niSq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 848w, https://substackcdn.com/image/fetch/$s_!niSq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 1272w, https://substackcdn.com/image/fetch/$s_!niSq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1909562b-4730-4696-bce2-496f109727e7_2366x1826.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The schema for creating competitive scraping pipelines that are resilient through time</figcaption></figure></div><div><hr></div><blockquote><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qJZE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="401" height="225.5625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:401,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p></blockquote><div><hr></div><h2>The Monitoring Layer: Your First Line of Defense</h2><p>The first thing you should do to avoid such failures is to implement a monitoring layer. This is the part that the majority of scraping engineers skip. Because, you know how things go: the business needed the data yesterday, and you can&#8217;t lose time with monitoring&#8230;</p><p>But if you want your competitive scrapers to be resilient over time, you need to implement a monitoring system. A good one is made on top of four parts: output validation, structural fingerprinting, data freshness checks, and canary fields. Let&#8217;s discuss them!</p><h3>How to Validate What Your Scraper Extracted</h3><p>Managing HTTP status codes in your scrapers is not enough. You need to assert that the data you extracted is actually meaningful. The following example is taken from <a href="https://stripe.com/pricing">Stripe&#8217;s pricing</a> page:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p3X2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p3X2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 424w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 848w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 1272w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p3X2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png" width="1162" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:1162,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:176549,&quot;alt&quot;:&quot;The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the EU by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/196881482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the EU by Federico Trotta" title="The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the EU by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!p3X2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 424w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 848w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 1272w, https://substackcdn.com/image/fetch/$s_!p3X2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93e642a5-caa7-49ba-8ecd-adca16dcf582_1162x400.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the EU</figcaption></figure></div><p>Here&#8217;s a practical validator using Pydantic that you can implement:</p><pre><code><code># In an activated virtual environment run: pip install httpx, bs4, pydantic

import httpx 
from bs4 import BeautifulSoup
from pydantic import BaseModel, field_validator, ValidationError
from typing import Optional
import re

# Define Pydantic model
class CompetitorPricingData(BaseModel):
    plan_name: str
    monthly_price: float
    currency: str
    features: list[str]

    @field_validator("monthly_price")
    @classmethod
    def price_must_be_positive(cls, v):
        if v &lt;= 0:
            raise ValueError(f"Price must be positive, got {v}")
        return v

    @field_validator("currency")
    @classmethod
    def currency_must_be_valid(cls, v):
        valid_currencies = {"USD", "EUR", "GBP"}
        if v.upper() not in valid_currencies:
            raise ValueError(f"Unexpected currency: {v}")
        return v.upper()

    @field_validator("features")
    @classmethod
    def features_must_not_be_empty(cls, v):
        if len(v) == 0:
            raise ValueError("Features list is empty: possible extraction failure")
        return v

# Define scraper logic
def scrape_stripe_pricing() -&gt; list[dict]:
    url = "&lt;https://stripe.com/pricing&gt;"
    headers = {
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/124.0.0.0 Safari/537.36"
        ),
        "Accept-Language": "en-US,en;q=0.9",
    }

    response = httpx.get(url, headers=headers, follow_redirects=True, timeout=15)
    response.raise_for_status()

    soup = BeautifulSoup(response.text, "html.parser")
    plans = []

    # Get class name from selectors
    plan_cards = soup.select("div.HeroPricingSubcard")

    for card in plan_cards:
        container = card.select_one(".HeroPricingSubcard__container")
        if not container:
            plans.append({
                "plan_name": "",
                "monthly_price": 0.0,
                "currency": "USD",
                "features": [],
            })
            continue

        # Get all text nodes inside the container
        text_blocks = [t.get_text(strip=True) for t in container.find_all(True) if t.get_text(strip=True)]

        # Pull the first block that looks like a price
        price_text = ""
        for block in text_blocks:
            if re.search(r"[\\d]+[.,]?[\\d]*%?\\s*\\+?\\s*[&#8364;$&#163;]?[\\d]*", block):
                price_text = block
                break

        price_match = re.search(r"[\\d]+\\.?[\\d]*", price_text.replace(",", "."))
        monthly_price = float(price_match.group()) if price_match else 0.0

        if "$" or "&#162;" in price_text:
            currency = "USD"
        elif "&#8364;" in price_text:
            currency = "EUR"
        elif "&#163;" in price_text:
            currency = "GBP"
        else:
            currency = "UNKNOWN"

        # Use all text blocks as features
        features = text_blocks if text_blocks else []

        plans.append({
            "plan_name": "Standard",  # HeroPricingSubcard is the Standard card
            "monthly_price": monthly_price,
            "currency": currency,
            "features": features,
        })

    return plans

# Define validator logic
def send_alert(message: str):
    # Wire this to Slack, PagerDuty, email, etc.
    print(f"[ALERT] {message}")

def validate_scraped_data(raw_data: dict) -&gt; Optional[CompetitorPricingData]:
    try:
        return CompetitorPricingData(**raw_data)
    except ValidationError as e:
        # Don't silently swallow this &#8212; alert immediately
        print(f"[VALIDATION FAILED] {e}")
        send_alert(f"Scraper validation failed: {e}")
        return None

if __name__ == "__main__":
    raw_plans = scrape_stripe_pricing()

    print(f"Found {len(raw_plans)} plan(s) on Stripe's pricing page.\\n")

    for raw in raw_plans:
        validated = validate_scraped_data(raw)
        if validated:
            print(f"[OK]   {validated.plan_name} &#8212; {validated.currency} {validated.monthly_price}/mo")
            print(f"       Features: {validated.features[:2]}{'...' if len(validated.features) &gt; 2 else ''}")
        else:
            print(f"[FAIL] Raw data that broke validation: {raw}")</code></code></pre><p>Here&#8217;s what this code does:</p><ul><li><p>Defines a Pydantic model: It leverages <a href="https://pydantic.dev/docs/validation/latest/get-started/">Pydantic</a> to define the expected shape and rules of the scraped data. It enforces that the price is positive, the currency is one of <em>USD</em>, <em>EUR</em>, or <em>GBP</em>, and the features list is not empty. Any violation raises a <em>ValidationError</em>.</p></li><li><p><em>scrape_stripe_pricing()</em>: Fetches Stripe&#8217;s pricing page using the library <em><a href="https://www.python-httpx.org/">httpx</a></em>, parses the HTML with <em><a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/">BeautifulSoup</a></em>, and extracts pricing data using CSS selectors. If a container isn&#8217;t found, it appends a zeroed-out dict, which will intentionally fail validation downstream.</p></li><li><p><em>validate_scraped_data()</em>: Passes each raw scraped dict through the Pydantic model. On failure, it calls <em>send_alert()</em> instead of silently swallowing the error.</p></li><li><p><em>send_alert()</em>: A stub you can wire to your alerting stack (Slack, PagerDuty, email) in a production environment. Note that, for educational purposes, throughout the entire article, this is used to print alerts via the command line.</p></li></ul><p>The result is the following:</p><pre><code><code>Found 2 plan(s) on Stripe's pricing page.

[OK]   Standard &#8212; EUR 1.5/mo
       Features: ['1.5% + &#8364;0.25', '1.5% + &#8364;0.25']...
[OK]   Standard &#8212; EUR 2.5/mo
       Features: ['2.5% + &#8364;0.25', '2.5% + &#8364;0.25']...
</code></code></pre><p>If it&#8217;s not clear why this matters, here&#8217;s what your scraper &#8220;sees&#8221; when it&#8217;s pushed from another location:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7e3G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7e3G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 424w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 848w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 1272w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7e3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png" width="1402" height="773" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:773,&quot;width&quot;:1402,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:262298,&quot;alt&quot;:&quot;The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the US by Federico Trotta&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/196881482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the US by Federico Trotta" title="The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the US by Federico Trotta" srcset="https://substackcdn.com/image/fetch/$s_!7e3G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 424w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 848w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 1272w, https://substackcdn.com/image/fetch/$s_!7e3G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e7f8dfc-202f-4803-83fb-575a19320f1a_1402x773.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Stripe&#8217;s pricing page your scraper &#8220;sees&#8221; from the US</figcaption></figure></div><p>The class is the same, but the data (the currency) is completely different! This is a common example of why you need validation that goes beyond a specific location.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://byteful.com/?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png" width="630" height="69.35779816513761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:1090,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:133037,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://byteful.com/?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/194398731?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EOo9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 424w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 848w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1272w, https://substackcdn.com/image/fetch/$s_!EOo9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2905ffa2-e3cd-4be3-ab69-02cceb4073a9_1090x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong><a href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE">Start your scraping journey with Byteful</a></strong>: 10GB New Customer Trial | Use TWSC for 15% OFF | $1.75/GB Residential Data | ISP Proxies in 15+ Countries</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE&quot;,&quot;text&quot;:&quot;Claim your 10GB here&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://byteful.com?utm_source=twsc&amp;utm_medium=new_banner&amp;utm_id=twsc&amp;promotion_public_id=10GB_TWSC_TRIAL&amp;promotion_code=NJKLBIOCWYENIPFE"><span>Claim your 10GB here</span></a></p></blockquote><div><hr></div><h3>Using DOM Fingerprints to Get Ahead of Structural Drift</h3><p>This method is one of the most valuable things you can add to a competitive intelligence pipeline.</p><p>The idea is simple: periodically hash the DOM structure of the pages you&#8217;re scraping and store its value. When the hash changes, flag it for human review before your scraper breaks. Here is how you can implement it:</p><pre><code><code># In an activated virtual environment run: pip install requests

import hashlib
import httpx
from bs4 import BeautifulSoup
import requests

# Define parsing logic
def extract_structural_fingerprint(html: str, selector: str) -&gt; str:
    """
    Extract a structural fingerprint from a specific section of the page.
    We hash the tag names and class names, NOT the content.
    This way, price changes don't trigger false alarms &#8212; only structural changes do.
    """
    soup = BeautifulSoup(html, "html.parser")
    container = soup.select_one(selector)

    if not container:
        return "CONTAINER_NOT_FOUND"

    # Build a structural signature
    structure = []
    for tag in container.find_all(True):
        classes = sorted(tag.get("class", []))
        structure.append(f"{tag.name}:{','.join(classes)}")

    fingerprint_str = "|".join(structure)
    return hashlib.md5(fingerprint_str.encode()).hexdigest()

# Compare hashes
def check_fingerprint(url: str, selector: str, stored_fingerprint: str) -&gt; bool:
    """
    Returns True if the structure is unchanged, False if it has drifted.
    """
    response = requests.get(url, timeout=10)
    response.raise_for_status()

    current_fingerprint = extract_structural_fingerprint(response.text, selector)

    if current_fingerprint == "CONTAINER_NOT_FOUND":
        send_alert(f"[CRITICAL] Selector '{selector}' not found on {url}. Site may have been redesigned.")
        print("\\n[OK] Structure unchanged, safe to scrape.")
        return False

    if current_fingerprint != stored_fingerprint:
        send_alert(
            f"[WARNING] Structural change detected on {url} "
            f"(selector: {selector}). "
            f"Old: {stored_fingerprint[:8]}... New: {current_fingerprint[:8]}..."
        )
        print("\\n[WARNING] Structural change detected: hashes differ")
        print(f"  Old: {fingerprint[:8]}...")
        print(f"  New: {drifted_fingerprint[:8]}...")
        print("  &#8594; Scrape skipped. Human review required before next run.")
        return False

    return True</code></code></pre><p>Below is a description of what this snippet does:</p><ul><li><p><em>extract_structural_fingerprint():</em> Parses the HTML, finds the target container via CSS selector, and builds a structural signature by iterating over every tag inside it. In this specific case, it records tag names and sorts class names, but deliberately ignores text content. That signature string is then hashed with MD5 and returned. If the selector finds nothing, it returns <em>&#8220;CONTAINER_NOT_FOUND&#8221;</em> instead of crashing.</p></li><li><p><em>check_fingerprint()</em>: Fetches the live page, computes the current fingerprint, and compares it against the stored one. Two failure cases are handled separately: the selector disappearing entirely (<em>CONTAINER_NOT_FOUND</em>) and the structure changing (hash mismatch). Both call <em>send_alert()</em> and return <em>False</em>: this signals to the caller to skip the scrape entirely.</p></li><li><p><em>hashlib.md5()</em>: Used to compress the structural signature into a short and comparable string. MD5 is not used here for security purposes; it&#8217;s used because it&#8217;s fast and collision-resistant enough for DOM comparison. Any change in tag names or class names produces a completely different hash.</p></li></ul><p>In the case of a drifted fingerprint, the expected result is the following:</p><pre><code><code>[STORED]  Fingerprint: 248363464b2da9b3814ea9a6dc5bd0df
[DRIFTED] Fingerprint: 7532ae7466c1f0fbc2c96471acd86ea7

[WARNING] Structural change detected: hashes differ
  Old: 24836346...
  New: 7532ae74...
  &#8594; Scrape skipped. Human review required before next run.</code></code></pre><p>Note that this approach to DOM changes can be considered &#8220;classical&#8221; because it is fully based on finding a meaningful selector for the target page. The problem is that the DOM could change, but not the &#8220;meaningful&#8221; selector you choose. To improve it, you can target several selectors, or you can add a check on the whole body, but this would add more noise.</p><p>If you prefer trying a more &#8220;modern&#8221; approach that leverages LLMs to check on DOM changes, at The Web Scraping Club, we&#8217;ve already covered this in the article: &#8220;<a href="https://substack.thewebscraping.club/p/scraping-with-llms-gpt-vision">Beyond the DOM: A Practical Guide to Web Data Extraction with LLMs and GPT Vision</a>&#8221;.</p><h3>Using Canary Fields as a Heartbeat for Your Scraping Pipeline</h3><p>A canary field is a field that you know changes frequently. This could be a &#8220;last updated&#8221; timestamp, a dynamic element, a session token in the page: you name it. You scrape it as a heartbeat, and if it stops changing, your pipeline is probably broken. Below is a snippet that checks on a canary field:</p><pre><code><code>def send_alert(message: str):
    print(f"[ALERT] {message}")

def check_canary_field(
    current_value: str,
    stored_value: str,
    field_name: str,
    competitor: str,
    max_unchanged_hours: int = 48) -&gt; None:
    if current_value == stored_value:
        send_alert(
            f"[WARNING] Canary field '{field_name}' for {competitor} "
            f"has not changed in over {max_unchanged_hours} hours. "
            f"Possible scraper failure or soft block."
        )
    else:
        print(f"[OK] Canary field '{field_name}' for {competitor} has changed. Pipeline looks healthy.")</code></code></pre><p>When something changes, the expected output is the following:</p><pre><code><code>[ALERT] [WARNING] Canary field 'last_updated' for &lt;COMPETITOR NAME&gt; has not changed in over 48 hours. 
Possible scraper failure or soft block.</code></code></pre><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h2>Building a Storage Architecture You Can Actually Trust</h2><p>Many scraping engineers make the same mistake: they store only the processed output and throw away the raw HTML.</p><p>But in the case of competitive intelligence, that&#8217;s an issue that can cause you to work on weekends. Why? Because when a competitor changed their pricing 6 months ago, and you want to reconstruct the exact timeline, you need the raw data. Without it, history is gone forever.</p><p>The solution is a two-layer storage model: a raw and a processed layer. Here&#8217;s how the two relate:</p><pre><code><code>             &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
             &#9474;                     RAW LAYER                       &#9474;
             &#9474;  S3: raw/{competitor}/{page_type}/{date}.html.gz    &#9474;
             &#9474;  What's stored: full HTML, compressed, timestamped  &#9474;
             &#9474;  Why: so you can re-parse history if your logic     &#9474;
             &#9474;  changes or your scraper had a bug                  &#9474;
             &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                                   &#9474; raw_s3_key (reference)
                                   &#9660;
             &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
             &#9474;                  PROCESSED LAYER                    &#9474;
             &#9474;  SQLite/Postgres: pricing_history table             &#9474;
             &#9474;  What's stored: structured, queryable records       &#9474;
             &#9474;  Why: this is what your dashboards and alerts       &#9474;
             &#9474;  consume                                            &#9474;
             &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></code></pre><p>Basically, every record in the processed layer carries a raw_s3_key that points back to the exact HTML it was extracted from. That reference is what makes the whole architecture auditable.</p><h3>The Raw Layer: Keep Every HTML Response</h3><p>Store the full HTML or JSON response, timestamped, for every successful scrape. S3 is a cheap option to do so, and a year of raw HTML for a handful of competitor pages costs almost nothing. Below is an example you can implement in your pipeline:</p><pre><code><code># In an activated virtual environment run: pip install boto3

import boto3
import gzip
from datetime import datetime

def store_raw_response(
    html: str,
    competitor: str,
    page_type: str,
    bucket_name: str
) -&gt; str:
    """
    Store the raw HTML response in S3 with a structured key.
    Compress it &#8212; HTML compresses extremely well (often 10:1).
    Returns the S3 key for reference in the processed layer.
    """
    s3 = boto3.client("s3")
    timestamp = datetime.utcnow().strftime("%Y/%m/%d/%H%M%S")
    s3_key = f"raw/{competitor}/{page_type}/{timestamp}.html.gz"

    compressed = gzip.compress(html.encode("utf-8"))

    s3.put_object(
        Bucket=bucket_name,
        Key=s3_key,
        Body=compressed,
        ContentEncoding="gzip",
        ContentType="text/html",
        Metadata={
            "competitor": competitor,
            "page_type": page_type,
            "scraped_at": datetime.utcnow().isoformat()
        }
    )

    return s3_key

def retrieve_raw_response(s3_key: str, bucket_name: str) -&gt; str:
    """
    Retrieve and decompress a raw HTML response from S3.
    Useful for re-parsing historical data when your scraper logic changes.
    """
    s3 = boto3.client("s3")
    response = s3.get_object(Bucket=bucket_name, Key=s3_key)
    compressed_data = response["Body"].read()
    return gzip.decompress(compressed_data).decode("utf-8")</code></code></pre><p>Notice the S3 structure: <em>raw/{competitor}/{page_type}/{year}/{month}/{day}/{timestamp}.html.gz</em>. This makes it trivial to list all scrapes for a specific competitor and page type within a date range, which is exactly what you need when reconstructing a pricing history.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>The Processed Layer: What Your Dashboards Actually Consume</h3><p>The processed layer is your structured, queryable data: the thing your dashboards and alerts actually read. Every record here has two fields that make the whole architecture work:</p><ul><li><p><em>raw_s3_key</em>, which links back to the exact HTML this record was extracted from.</p></li><li><p><em>fingerprint</em>, which captures the structural state of the page at scrape time.</p></li></ul><p>The first one makes your data auditable. The second one tells you, later, whether the page had already changed when this record was written.</p><p>Below is a Python example to implement it:</p><pre><code><code>import sqlite3
from dataclasses import dataclass
from datetime import datetime
from typing import Optional

@dataclass
class ProcessedPricingRecord:
    competitor: str
    page_type: str
    plan_name: str
    monthly_price: float
    currency: str
    scraped_at: datetime
    raw_s3_key: str  # The link back to the raw layer
    fingerprint: str  # The structural fingerprint at time of scrape

def store_processed_record(record: ProcessedPricingRecord, db_path: str) -&gt; None:
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS pricing_history (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            competitor TEXT NOT NULL,
            page_type TEXT NOT NULL,
            plan_name TEXT NOT NULL,
            monthly_price REAL NOT NULL,
            currency TEXT NOT NULL,
            scraped_at TEXT NOT NULL,
            raw_s3_key TEXT NOT NULL,
            fingerprint TEXT NOT NULL
        )
    """)

    cursor.execute("""
        INSERT INTO pricing_history 
        (competitor, page_type, plan_name, monthly_price, currency, scraped_at, raw_s3_key, fingerprint)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    """, (
        record.competitor,
        record.page_type,
        record.plan_name,
        record.monthly_price,
        record.currency,
        record.scraped_at.isoformat(),
        record.raw_s3_key,
        record.fingerprint
    ))

    conn.commit()
    conn.close()</code></code></pre><p>A note on storage: this example uses SQLite, which is fine for a single scraper running on one machine. If you&#8217;re scraping multiple competitors in parallel or need concurrent writes, consider moving to Postgres (the schema remains the same).</p><h3>A Concrete Example of Why the Raw Layer Saves You on Weekends</h3><p>Imagine your competitor runs a Black Friday promotion in November and your scraper captures it. In January, your CEO asks: <em>&#8220;When exactly did they drop prices, and by how much?&#8221;</em></p><p>With only the processed layer, you can answer that if your scraper was working correctly. But what if your scraper had a bug in November that caused it to extract prices incorrectly? With the raw layer, you can go back, fix the extraction logic, and re-parse the November HTML. Without it, that data is gone.</p><p>Here&#8217;s a utility function that makes re-parsing straightforward:</p><pre><code><code>import boto3

def reparse_historical_data(
    competitor: str,
    page_type: str,
    start_date: str,
    end_date: str,
    bucket_name: str,
    new_parser_fn,
    db_path: str
) -&gt; int:
    """
    Re-parse all raw HTML for a competitor/page_type within a date range.
    Useful when your extraction logic changes and you need to backfill.
    
    new_parser_fn: a callable that takes raw HTML and returns a list of dicts
    Returns the number of records reprocessed.
    """
    s3 = boto3.client("s3")
    prefix = f"raw/{competitor}/{page_type}/"

    paginator = s3.get_paginator("list_objects_v2")
    pages = paginator.paginate(Bucket=bucket_name, Prefix=prefix)

    reprocessed = 0

    for page in pages:
        for obj in page.get("Contents", []):
            key = obj["Key"]
            # Filter by date range based on key structure
            key_date = key.split("/")[3] + "-" + key.split("/")[4] + "-" + key.split("/")[5]
            if start_date &lt;= key_date &lt;= end_date:
                raw_html = retrieve_raw_response(key, bucket_name)
                parsed_records = new_parser_fn(raw_html)
                for record_data in parsed_records:
                    # Store with updated extraction, linked to same raw key
                    record = ProcessedPricingRecord(
                        **record_data,
                        raw_s3_key=key,
                        scraped_at=datetime.utcnow()
                    )
                    store_processed_record(record, db_path)
                    reprocessed += 1

    return reprocessed</code></code></pre><p>Note that you&#8217;re not re-scraping anything. You&#8217;re just running your new parser against HTML you already have in storage. That&#8217;s the whole point of the raw layer.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Recovering From a Full Scraper Failure Without Losing History</h2><p>Imagine this scenario: a competitor does a full site redesign, and your scraper is dead. This is not a hypothetical scenario: it happens more frequently than you can think, and most teams have no protocol for it.</p><p>Here&#8217;s a concrete recovery process.</p><h3>How to Know Your Scraper Is Dead (Not Just Slow)</h3><p>If you&#8217;ve implemented structural fingerprinting as discussed previously, you&#8217;ll know about the redesign before your scraper breaks. The fingerprint check will fail, you&#8217;ll get an alert, and you can investigate before storing bad data.</p><p>If you haven&#8217;t, and you&#8217;re reading this article after the fact, the first sign is usually a spike in validation failures or a sudden drop in scraped records. Consider implementing the following code:</p><pre><code><code>import sqlite3

def detect_scraper_health(db_path: str, competitor: str, lookback_days: int = 7) -&gt; dict:
    """
    Returns a health summary for a competitor's scraper over the last N days.
    Useful for spotting gradual degradation before it becomes a full failure.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    cursor.execute("""
        SELECT
            DATE(scraped_at) as scrape_date,
            COUNT(*) as total_attempts,
            SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successes,
            SUM(CASE WHEN status = 'validation_failed' THEN 1 ELSE 0 END) as validation_failures,
            SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as errors
        FROM scrape_log
        WHERE competitor = ?
          AND scraped_at &gt;= DATE('now', ?)
        GROUP BY DATE(scraped_at)
        ORDER BY scrape_date DESC
    """, (competitor, f"-{lookback_days} days"))

    rows = cursor.fetchall()
    conn.close()

    return [
        {
            "date": row[0],
            "total": row[1],
            "successes": row[2],
            "validation_failures": row[3],
            "errors": row[4],
            "success_rate": round(row[2] / row[1] * 100, 1) if row[1] &gt; 0 else 0
        }
        for row in rows
    ]
</code></code></pre><p>The expected result is something as follows:</p><pre><code><code>Date         Total     OK   Val.Fail   Errors     Rate
--------------------------------------------------------
2026-01-15      10      0          0       10     0.0%
2026-01-14      10      2          5        3    20.0%
2026-01-13      10      5          4        1    50.0%
2026-01-12      10      8          2        0    80.0%
2026-01-11      10      9          1        0    90.0%
2026-01-10      10     10          0        0   100.0%
2026-01-09      10     10          0        0   100.0%</code></code></pre><p>The degradation pattern is immediately readable. A success rate dropping from 95% to 60% over three days is probably a sign of a redesign in progress. A drop from 95% to 0% in a short time signals a full redesign, or a hard block.</p><h3>Diagnosing What Actually Broke Before You Rewrite Anything</h3><p>Not every structural change is a full redesign. Rewriting the major part of a scraper can cost you days if not weeks. To avoid that, you can write a script that checks what actually changed, pointing to meaningful parts of the target website:</p><pre><code><code>from bs4 import BeautifulSoup

def triage_structural_change(
    url: str,
    selector: str,
    old_fingerprint: str,
    bucket_name: str,
    competitor: str,
    page_type: str) -&gt; dict:
    """
    Diagnose the nature of a structural change.
    Returns a triage report to guide the recovery effort.
    """
    response = requests.get(url, timeout=10)
    current_html = response.text
    soup = BeautifulSoup(current_html, "html.parser")

    report = {
        "url": url,
        "http_status": response.status_code,
        "selector_found": soup.select_one(selector) is not None,
        "old_fingerprint": old_fingerprint,
        "new_fingerprint": extract_structural_fingerprint(current_html, selector),
        "page_title": soup.title.string if soup.title else "N/A",
        "recommendation": None
    }

    if not report["selector_found"]:
        report["recommendation"] = "FULL_REWRITE: primary selector is gone. Site likely redesigned."
    elif report["old_fingerprint"] != report["new_fingerprint"]:
        report["recommendation"] = "PARTIAL_UPDATE:selector exists but structure changed. Review child selectors."
    else:
        report["recommendation"] = "FALSE_ALARM: fingerprint mismatch may be transient. Re-check in 1 hour."

    # Store the current raw HTML for reference during rewrite
    store_raw_response(current_html, competitor, f"{page_type}_triage", bucket_name)

    return report
    
def print_report(report: dict) -&gt; None:
    print(f"  URL:             {report['url']}")
    print(f"  Selector found:  {report['selector_found']}")
    print(f"  Old fingerprint: {report['old_fingerprint'][:8]}...")
    print(f"  New fingerprint: {report['new_fingerprint'][:8]}...")
    print(f"  Page title:      {report['page_title']}")
    print(f"  Recommendation:  {report['recommendation']}")
</code></code></pre><p>The expected output for the case of a full rewrite is the following:</p><pre><code><code>&#9;URL:             https://...
  Selector found:  False
  Old fingerprint: 4a7f92bc...
  New fingerprint: CONTAINER_NOT_FOUND
  Page title:      Pricing page
  Recommendation:  FULL_REWRITE: primary selector is gone. Site likely redesigned.
</code></code></pre><p>So, in this case, the script checks a specific URL of the target website. But the code can be, of course, generalized to more than just one. The same applies to the target selector.</p><h3>Estimating How Much of the Gap You Can Recover From Raw Storage</h3><p>Once you&#8217;ve rewritten the scraper, you have a gap in your data. If you&#8217;ve been storing raw HTML, you can partially fill it using a snippet like the following:</p><pre><code><code>import boto3

def estimate_gap_coverage(
    competitor: str,
    page_type: str,
    failure_start_date: str,
    bucket_name: str) -&gt; dict:
    """
    Estimate how much of the gap period can be recovered from raw storage.
    """
    s3 = boto3.client("s3")
    prefix = f"raw/{competitor}/{page_type}/"

    paginator = s3.get_paginator("list_objects_v2")
    pages = paginator.paginate(Bucket=bucket_name, Prefix=prefix)

    available_keys = []
    for page in pages:
        for obj in page.get("Contents", []):
            key = obj["Key"]
            key_date = "/".join(key.split("/")[3:6])
            if key_date &gt;= failure_start_date.replace("-", "/"):
                available_keys.append(key)

    return {
        "gap_start": failure_start_date,
        "recoverable_snapshots": len(available_keys),
        "oldest_recoverable": available_keys[0] if available_keys else None,
        "newest_recoverable": available_keys[-1] if available_keys else None,
        "recommendation": (
            "Run reparse_historical_data() with your new parser to backfill."
            if available_keys else
            "No raw snapshots available for this period. Gap cannot be recovered."
        )
    }

# Print values
print(f"Gap start:              {result['gap_start']}")
print(f"Recoverable snapshots:  {result['recoverable_snapshots']}")
print(f"Oldest recoverable:     {result['oldest_recoverable']}")
print(f"Newest recoverable:     {result['newest_recoverable']}")
print(f"Recommendation:         {result['recommendation']}")</code></code></pre><p>The expected result is:</p><pre><code><code>Gap start:              2026-04-12
Recoverable snapshots:  3
Oldest recoverable:     &lt;COMPETITOR_NAME&gt;/pricing/2026/04/12/143022.html.gz
Newest recoverable:     &lt;COMPETITOR_NAME&gt;/pricing/2026/04/14/143022.html.gz
Recommendation:         Run reparse_historical_data() with your new parser to backfill.</code></code></pre><p>As a final note on this recovery section, consider that, in practice, these three steps run in sequence:</p><ul><li><p>When something breaks, you start with <em>detect_scraper_health()</em> to confirm there&#8217;s actually a problem and understand how long it&#8217;s been degrading.</p></li><li><p>Then you run <em>triage_structural_change()</em> to understand <em>what</em> broke. That tells you whether you need a full rewrite or a 10-minute fix.</p></li><li><p>Once you&#8217;ve updated your scraper, you call <em>estimate_gap_coverage()</em> to see how much of the gap period you can recover from raw storage, and then <em>reparse_historical_data()</em> to actually backfill it. If <em>estimate_gap_coverage()</em> comes back with zero recoverable snapshots, that gap is gone, which is exactly why the raw layer exists in the first place.</p></li></ul><h2>Conclusion</h2><p>Building competitive intelligence scrapers is not as easy as it seems for two reasons:</p><ul><li><p>Developing the scrapers is only half the effort.</p></li><li><p>Keeping the scrapers honest 12 months from now probably needs even harder efforts than coding the scrapers themselves.</p></li></ul><p>The layers presented in this article can make your competitive intelligence scrapers resilient through time (with the right adjustments for production environments). So, if you&#8217;re implementing this from scratch, don&#8217;t try to build everything at once. Add one piece at a time and take your time to verify everything works fine before you add the next step.</p><p>Then, you just need to <a href="https://substack.thewebscraping.club/p/analyzing-scraped-data-pandas-matplotlib">analyze the data you scraped</a> (maybe directly <a href="https://substack.thewebscraping.club/p/building-a-scraper-dashboard-streamlit">implementing a dashboard in Streamlit</a>), and your colleagues in the business department can have sweet dreams: their competitive analytics are safe through time.</p><p>So, let us now: are your competitive intelligence scrapers time-resilient?</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/how-to-build-competitive-intelligence-scraping?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/how-to-build-competitive-intelligence-scraping?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[Kameleo Docker: Exploring the Docker-Based Anti-Detect Browser]]></title><description><![CDATA[Kameleo is finally available on Linux. How? Via Docker!]]></description><link>https://substack.thewebscraping.club/p/kameleo-docker-exploring-the-docker</link><guid isPermaLink="false">https://substack.thewebscraping.club/p/kameleo-docker-exploring-the-docker</guid><dc:creator><![CDATA[Antonello Zanini]]></dc:creator><pubDate>Sun, 14 Jun 2026 03:01:16 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9d36ab11-f536-4b56-829a-540e3ba41ad8_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Docker-based stealth browsers are quickly becoming a new standard for automation and scraping infrastructures. The main reason is that they can be integrated directly into CI pipelines or your own fleet of scalable stealth browsers in the cloud.</p><p>Kameleo Docker brings Kameleo&#8217;s anti-detect browser capabilities into a containerized setup, enabling production-ready automation with real fingerprinting and multi-profile isolation on Linux servers.</p><p>In this post, I&#8217;ll take a deep look at this solution and walk you through everything you need to know about it. By the end, you&#8217;ll understand what Kameleo Docker is, how its stealth browser approach works, how to set it up, and whether it&#8217;s actually worth trying.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCo7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png" width="626" height="313" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:390972,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/197764148?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gCo7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!gCo7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a7017ca-9ba7-4512-91e1-2682ab05ca13_1200x600.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Before proceeding, let me thank NetNut, the platinum partner of the month. Their set of solutions cover all your needs for scraping.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack&quot;,&quot;text&quot;:&quot;Visit Netnut&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://netnut.io/?utm_source=webscrapingclub&amp;utm_medium=newsletter&amp;utm_campaign=130526&amp;utm_content=product-stack"><span>Visit Netnut</span></a></p></blockquote><div><hr></div><h2>An Introduction to Kameleo Docker</h2><p>Dig into the world of Kameleo Docker!</p><h3>What Is Kameleo Docker?</h3><p><a href="https://kameleo.io/">Kameleo</a> is an anti-detect browser engineered to make browser sessions look like real user devices. Instead of exposing a generic automation fingerprint, it creates realistic browser identities by spoofing hardware, browser, and environment signals such as WebGL, Canvas, fonts, screen resolution, and geolocation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AV8o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AV8o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 424w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 848w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 1272w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AV8o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png" width="1456" height="577" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:577,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Kameleo Docker&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Kameleo Docker" title="Kameleo Docker" srcset="https://substackcdn.com/image/fetch/$s_!AV8o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 424w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 848w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 1272w, https://substackcdn.com/image/fetch/$s_!AV8o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86beae8-6206-4e8e-bdaa-50d9a1e743bd_3008x1193.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Kameleo Docker</figcaption></figure></div><p>Kameleo Docker brings <a href="https://substack.thewebscraping.club/p/kameleo-anti-detect-browser">that same stealth stack</a> into a self-hosted, containerized deployment model. Rather than relying on a desktop app, you can run Kameleo inside Docker on Linux or Windows servers, CI pipelines, VPSs, or Kubernetes environments.</p><p>Playwright, Puppeteer, and Selenium can connect to the container via CDP, meaning you can keep using your existing browser automation logic with minimal changes.</p><p>Further reading:</p><ul><li><p><em><a href="https://kameleo.io/docker">Kameleo Docker product page</a></em></p></li><li><p><em><a href="https://developer.kameleo.io/integrations/docker/">Kameleo Docker docs</a></em></p></li><li><p><em><a href="https://kameleo.io/blog/kameleo-on-linux-via-docker-what-we-built-what-broke-whats-next">Kameleo on Linux via Docker: What We Built, What Broke, What&#8217;s Next</a></em></p><p></p></li></ul><h3>Why Kameleo Docker Exists</h3><p>Cloud servers, Kubernetes clusters, CI/CD pipelines, and VPS environments are overwhelmingly Linux-native, making Linux compatibility a practical requirement for automation and scraping teams.</p><p>For years, this created a problem for Kameleo users, as the solution only supported Windows and macOS. Because of that, teams wanting to run stealth browsers in production often had to rely on fragile workarounds.</p><p>Some deployed Windows virtual machines alongside Linux scraping stacks in AWS. Others used <a href="https://some-natalie.dev/blog/ssh-x11-forwarding/">X11-over-SSH</a> tunnels to remotely access browsers running on servers. These setups were difficult to maintain, resource-intensive, and far from ideal for scalable automation.</p><p>As explained in the <a href="https://kameleo.io/blog/kameleo-on-linux-via-docker-what-we-built-what-broke-whats-next">product announcement blog post</a>, Kameleo customers started to ask for a version of Kameleo that could run directly where their automation already lived.</p><p>As Barnabas Szenasi, founder and lead engineer at Kameleo, explained when I met him at Prague Crawl 2026:</p><blockquote><p><em>&#8220;We could see from customer messages that a significant slice of our automation-first users were running Linux cloud servers and simply couldn&#8217;t use Kameleo at all... At Prague Crawl 2025, Tamas [Kameleo&#8217;s CEO] and I heard the same story from industry peers around the world: scraping pipelines were getting harder, and the need to run real browser environments instead of faking HTTP requests was growing fast.&#8221;</em></p></blockquote><h3>The Philosophy Behind the Project</h3><p>From the beginning, Kameleo&#8217;s philosophy has been simple: masking quality matters more than shipping quickly.</p><p>After all, <a href="https://substack.thewebscraping.club/p/anti-detect-browser-royal-rumble-comments">an anti-detect browser</a> is only useful if it can convincingly behave like a real device. That&#8217;s why Kameleo relies on fingerprints sourced from real-world device traffic and continuously tested against modern anti-bot systems.</p><p>That same quality-first mindset also shaped the Docker project. According to founder and lead engineer Barnabas Szenasi, Linux support took longer than expected because the goal was never just to make Kameleo run in a container.</p><p>The objective was to reach the same masking quality users already expected on Windows and macOS. Shipping a functional but lower-fidelity Linux version would have compromised the product&#8217;s core standard.</p><blockquote><div><hr></div></blockquote><blockquote><p><em>For your scraping needs, having a reliable proxy provider like <strong>Decodo</strong> on your side improves the chances of success. </em></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qJZE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png" width="401" height="225.5625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:401,&quot;bytes&quot;:554497,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/187315628?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qJZE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 424w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 848w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1272w, https://substackcdn.com/image/fetch/$s_!qJZE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffec072bc-2ac2-49bf-8084-43858298808f_800x450.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://visit.decodo.com/WyQ3mA&quot;,&quot;text&quot;:&quot;Try Decodo Now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://visit.decodo.com/WyQ3mA"><span>Try Decodo Now</span></a></p></blockquote><div><hr></div><h2>Technical Architecture Behind Kameleo Docker</h2><p>Now that you know why the project exists, let me explain how it works and the engineering behind it.</p><h3>How Kameleo Docker Works</h3><p>Kameleo Docker runs inside either:</p><ul><li><p>a Linux-based container (Ubuntu 22.04), or</p></li><li><p>a Windows-based container (Windows Server Core 2022).</p></li></ul><p>When you pull the image, Docker downloads the correct variant based on your container configuration (Linux containers are the default in most environments, including <a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a>). Regardless of the underlying platform, Kameleo exposes the same <a href="https://developer.kameleo.io/reference/api-reference/">Local API</a> for browser and profile management as the <a href="https://kameleo.io/downloads">desktop app</a>.</p><p>The process begins when you create a browser profile through the Local API. If you aren&#8217;t familiar with that concept, <a href="https://developer.kameleo.io/concepts/profiles/">Kameleo profiles</a> are reusable browser environments that bundle a complete browser fingerprint together with persistent browser state, such as cookies, browsing history, local storage, and bookmarks.</p><p>Profiles can also include user-defined settings like proxies, browser extensions, and startup preferences. Each profile is tied to a specific browser kernel and can be started, stopped, imported, or exported as needed.</p><h3>Architecture Overview</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sgEa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sgEa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 424w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 848w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sgEa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png" width="1456" height="1019" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1019,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sgEa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 424w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 848w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 1272w, https://substackcdn.com/image/fetch/$s_!sgEa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc6b1496-60f7-4a12-b06a-218d9f2d35ad_2174x1522.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Kameleo Docker&#8217;s architecture</figcaption></figure></div><p>Kameleo Docker separates browser execution from automation logic. The container hosts the stealth browsers, fingerprinting systems, and orchestration layer, while your automation scripts run independently on your machine, server, or orchestration platform.</p><p>At the center of the architecture is the Local API, exposed on port <em>5050</em>. This API handles profile creation, fingerprint selection, browser startup, lifecycle management, and more.</p><p>Behind the API sit <a href="https://developer.kameleo.io/concepts/kernels/">Kameleo&#8217;s browser kernels</a>:</p><ul><li><p><strong>Chroma</strong>: A Chromium-based engine.</p></li><li><p><strong>Junglefox</strong>:<strong> </strong>A Firefox-based engine.</p></li></ul><p>These kernels are modified with engine-level masking patches and connected to Kameleo&#8217;s continuously updated fingerprint database (more on this later). Since they are exposed through the same API, you can switch between them without making any code changes.</p><p>When a profile starts, Kameleo launches a browser session with the configured fingerprint and settings. Playwright and Puppeteer can then connect to the running browser through a WebSocket endpoint via <a href="https://chromedevtools.github.io/devtools-protocol/">Chrome DevTools Protocol (CDP)</a>.</p><p>In other words, your automation script stays outside the Docker container. The browser behaves as if it were running locally, while execution, fingerprint masking, and browser management happen entirely inside the Docker container.</p><p>Persistent storage is handled through Docker volumes. Profile data, downloaded browser kernels, and runtime state are stored outside the container, allowing environments to be recreated without losing configuration or repeatedly downloading browser components. This makes deployments easier to scale, recover, and reproduce.</p><div><hr></div><blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8Qrb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8Qrb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8Qrb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png" width="479" height="239.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1200,&quot;resizeWidth&quot;:479,&quot;bytes&quot;:911444,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://substack.thewebscraping.club/i/196394917?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!8Qrb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 424w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 848w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 1272w, https://substackcdn.com/image/fetch/$s_!8Qrb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68fe580f-2f4e-4452-9e3c-0ca00777d9f6_1200x600.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Trusted by teams running ad verification, web scraping, SERP tracking, and market research. Ethically sourced proxies, globally accessible, and fairly priced.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dataimpulse.com/&quot;,&quot;text&quot;:&quot;Get Started With DataImpulse&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://dataimpulse.com/"><span>Get Started With DataImpulse</span></a></p></blockquote><div><hr></div><h2>Core Features of Kameleo Docker</h2><p>Time to explore the main features and capabilities provided by Kameleo Docker. For more information, <a href="https://developer.kameleo.io/integrations/docker/">read the official documentation</a>.</p><h3>Real Device Fingerprint Masking</h3><p>Kameleo fingerprints are derived from real-world device traffic, not synthetic templates. Each profile represents a coherent combination of OS, browser, hardware signals, and behavioral characteristics.</p><p>All fingerprint surfaces are kept internally consistent, including Canvas, WebGL, audio context, screen resolution, and fonts.</p><p><strong>Note</strong>: TLS fingerprint spoofing isn&#8217;t required, as Kameleo matches the browser kernel version precisely. The TLS stack remains the original, unmodified implementation shipped with the corresponding browser release.</p><p>The goal of the project isn&#8217;t to spoof everything, but to maintain realism across signals. That&#8217;s because overriding too many surfaces increases inconsistency risk, which detection systems can flag. For example, running a macOS fingerprint on a Windows host forces heavy compensation across system-level signals.</p><h3>Proxy Integration and Geo Consistency</h3><p>Each Kameleo profile can be assigned a dedicated proxy (including a rotating proxy), allowing IP-level isolation between browser identities.</p><p>Now, mismatches between IP geography and browser signals (language, timezone, WebRTC, and system locale) are a common detection vector. To address that, Kameleo provides <a href="https://help.kameleo.io/article/74-recommended-settings">automatic geo-location matching</a> to align the browser&#8217;s settings with the geographic location of the selected proxy IP address.</p><h3>Multi-Profile Isolation</h3><p>Kameleo Docker is built around strict profile isolation, as each browser profile runs as a fully independent environment. This separation opens the door to safe multi-accounting (referred to as &#8220;account management&#8221; in Kameleo terminology). Thanks for this feature, you can operate multiple identities simultaneously without cross-contamination of session data or signals.</p><h3>Linux-Specific Docker Image Features</h3><p>Compared to the Windows-based container, the Linux version of Kameleo Docker includes several additional features. These include:</p><ul><li><p><strong><a href="https://developer.kameleo.io/integrations/docker/#vnc-viewer-only-in-linux-based-container">Built-in VNC viewer</a></strong>: Allows you to monitor and interact with live browser sessions. This is especially useful for debugging automation, validating fingerprints, or troubleshooting rendering issues. You can access it through a browser on port <em>8080</em> or via native VNC clients such as RealVNC or TigerVNC on port <em>5900</em>. For security reasons, it&#8217;s disabled by default.</p></li><li><p><strong>Browser-Based Kameleo GUI</strong>: A lightweight browser-based GUI on port <em>80</em> (reach it at <em>http://localhost:80</em>). Unlike the desktop app, it offers reduced functionality and is primarily intended for quick inspection, basic profile management, and monitoring.</p></li><li><p><strong>Optional GPU acceleration</strong>: The Linux container <a href="https://developer.kameleo.io/integrations/docker/#gpu-support-on-linux">supports optional GPU acceleration</a> for graphics-heavy workloads such as WebGL or canvas-intensive websites. Intel/AMD GPUs can be mounted through <em>/dev/dri</em>, while NVIDIA GPUs are supported through the NVIDIA Container Toolkit. When no GPU is available, Kameleo falls back to software rendering.</p></li></ul><h2>Getting Started With Kameleo Docker: Step-by-Step Guide</h2><p>In this guided section, I&#8217;ll show you how to set up Kameleo Docker and use it for browser automation against the <a href="https://www.scrapingcourse.com/javascript-rendering">Scraping Course&#8217;s &#8220;JavaScript Rendering&#8221; page</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k9B9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k9B9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 424w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 848w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 1272w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k9B9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png" width="1456" height="785" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:785,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The target Scraping Course &#8220;JavaScript Rendering&#8221; page&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The target Scraping Course &#8220;JavaScript Rendering&#8221; page" title="The target Scraping Course &#8220;JavaScript Rendering&#8221; page" srcset="https://substackcdn.com/image/fetch/$s_!k9B9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 424w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 848w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 1272w, https://substackcdn.com/image/fetch/$s_!k9B9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd8d4a67c-8ade-4fb3-b13d-f7d2f23e0f6d_3021x1629.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The target Scraping Course &#8220;JavaScript Rendering&#8221; page</figcaption></figure></div><p>This is a sandbox environment for web scraping that simulates a real-world, JavaScript-rendered ecommerce page. It makes for a great testing target to validate the setup and see how Kameleo Docker behaves in a realistic automation scenario.</p><h3>Requirements and Prerequisites</h3><p>To get started with Kameleo Docker, make sure you have <a href="https://www.docker.com/get-started/">Docker installed and running locally</a>. (Optionally, you need a <a href="https://login.kameleo.io/Account/Login">Kameleo account </a>if you want to run Kameleo Docker with authentication.)</p><p>For more details on supported operating systems and memory requirements, <a href="https://developer.kameleo.io/integrations/docker/#prerequisites">refer to the official documentation</a>.</p><p>Since I&#8217;ll show how to use Kameleo Docker with Playwright in Python, to keep things moving, I&#8217;ll assume you already have a Python environment set up with <a href="https://playwright.dev/python/docs/library#installation">Playwright and its dependencies installed</a>.</p><p>To follow along with this tutorial section, I also recommend that you have:</p><ul><li><p><a href="https://docker-curriculum.com/">Basic Docker experience</a> (running containers, mounting volumes, and using compose files)</p></li><li><p>Familiarity with <a href="https://substack.thewebscraping.club/p/browser-automation-landscape-2025">browser automation using Playwright</a>.</p></li></ul><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.youtube.com/@thewebscrapingclub&quot;,&quot;text&quot;:&quot;Check the TWSC YouTube Channel&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.youtube.com/@thewebscrapingclub"><span>Check the TWSC YouTube Channel</span></a></p><div><hr></div><h3>Step #1: Create a Kameleo Account</h3><p>If you haven&#8217;t already, start by <a href="https://login.kameleo.io/Account/Register">creating a Kameleo account</a>. Fill out the sign-up form and enter the required information. Once registration is complete, <a href="https://kameleo.io/pricing">a </a><em><a href="https://kameleo.io/pricing">Free</a></em><a href="https://kameleo.io/pricing"> plan</a> will already be activated:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OVWu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OVWu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 424w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 848w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 1272w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OVWu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png" width="1456" height="787" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:787,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OVWu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 424w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 848w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 1272w, https://substackcdn.com/image/fetch/$s_!OVWu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F313c7aed-9927-4fb5-8981-886a01234f08_3031x1639.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Free plan</figcaption></figure></div><p>Note that the <em>Free</em> plan is enough to use Kameleo Docker.</p><p><strong>Important</strong>: Kameleo credentials are required for the container to authenticate successfully, download browser kernels, and start correctly.</p><h3>Step #2: Start the Docker Container</h3><p>With your account ready, the next step is to pull and run <a href="https://hub.docker.com/r/kameleo/kameleo-app">the Kameleo Docker image</a>.</p><p>Remember that Kameleo ships as a multi-platform Docker image, supporting both Linux-based and Windows-based containers. To download and start the Linux container version of Kameleo, run:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">docker run --platform linux/amd64 \
    --shm-size=2g \
    -p 5050:5050 \
    -e PAT='&lt;YOUR_KAMELEO_PAT&gt;' \
    -v kameleo-data:/data \
    kameleo/kameleo-app:latest</code></pre></div><p><strong>Note 1</strong>: If you run this command in PowerShell, replace &#8220;\&#8221; with the backtick &#8220;`&#8221; for multi-line commands.</p><p><strong>Note 2</strong>: To launch the web GUI included in the Linux container of Kameleo Docker, add the <em>-p 80:80</em> argument to your <em>docker run</em> command.</p><p>Here&#8217;s what matters in the above command:</p><ul><li><p><em>--platform linux/amd64</em> ensures Docker pulls the Linux-based image variant.</p></li><li><p><em>--shm-size=2g</em> is required for stable browser execution (the default Docker shared memory of 64MB is too small for browser execution).</p></li><li><p><em>-v kameleo-data:/data</em> creates a named volume that persists browser kernels and profiles across restarts.</p></li><li><p><em>&lt;YOUR_KAMELEO_PAT&gt;</em> is your <a href="https://developer.kameleo.io/getting-started/configure/#3-generate-a-personal-access-token-pat">Kameleo Personal Access Token (PAT)</a>, required to authenticate with your Kameleo account. Note that <strong>this argument is optional</strong>. You can skip the <em>-e PAT=&#8217;&lt;YOUR_KAMELEO_PAT&gt;&#8217;</em> flag entirely if you want to try out Kameleo Docker without an account.</p></li></ul><p>Below&#8217;s the output you should get:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lH45!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lH45!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 424w, https://substackcdn.com/image/fetch/$s_!lH45!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 848w, https://substackcdn.com/image/fetch/$s_!lH45!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 1272w, https://substackcdn.com/image/fetch/$s_!lH45!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lH45!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png" width="1456" height="322" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:322,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Retrieving the Kameleo Docker image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Retrieving the Kameleo Docker image" title="Retrieving the Kameleo Docker image" srcset="https://substackcdn.com/image/fetch/$s_!lH45!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 424w, https://substackcdn.com/image/fetch/$s_!lH45!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 848w, https://substackcdn.com/image/fetch/$s_!lH45!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 1272w, https://substackcdn.com/image/fetch/$s_!lH45!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a533b1-de13-4653-a94d-08137ea045b6_3038x672.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Retrieving the Kameleo Docker image</figcaption></figure></div><p>The Kameleo Docker image should now be downloaded and launched on your system. Cool!</p><h3>Step #3: Verify the Service</h3><p>Once you run the image, Kameleo Docker will:</p><ol><li><p>Start the Local API on port <em>5050</em>.</p></li><li><p>Authenticate using your credentials.</p></li><li><p>Download required browser kernels (first run only).</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pYxi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pYxi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 424w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 848w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 1272w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pYxi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png" width="1456" height="82" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:82,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Kameleo Docker image startup logs&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Kameleo Docker image startup logs" title="The Kameleo Docker image startup logs" srcset="https://substackcdn.com/image/fetch/$s_!pYxi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 424w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 848w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 1272w, https://substackcdn.com/image/fetch/$s_!pYxi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c9579e-6a4e-4153-90b7-3b6c696c090b_2526x142.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The Kameleo Docker image startup logs</figcaption></figure></div><p>To confirm everything is running correctly, visit the following URL in your browser:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">http://localhost:5050/swagger</code></pre></div><p>You should see the Swagger UI for the Kameleo Local API:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oAMx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oAMx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 424w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 848w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 1272w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oAMx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png" width="1456" height="782" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/37e97028-9717-472e-850f-dcced084d674_3024x1624.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:782,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Swagger UI for the Kameleo Local API at &#8220;http://localhost:5050/swagger&#8221;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Swagger UI for the Kameleo Local API at &#8220;http://localhost:5050/swagger&#8221;" title="The Swagger UI for the Kameleo Local API at &#8220;http://localhost:5050/swagger&#8221;" srcset="https://substackcdn.com/image/fetch/$s_!oAMx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 424w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 848w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 1272w, https://substackcdn.com/image/fetch/$s_!oAMx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37e97028-9717-472e-850f-dcced084d674_3024x1624.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Swagger UI for the Kameleo Local API at &#8220;http://localhost:5050/swagger&#8221;</figcaption></figure></div><p>You&#8217;ll have a local Kameleo instance ready for automation with Playwright, Puppeteer, or Selenium. Great!</p><h3>Step #4: Download the SDK and Create Your First Profile</h3><p>Now that Kameleo Docker is running, you can interact with it through the APIs exposed at <em>http://localhost:5050</em>. The next step is to proceed with the <a href="https://developer.kameleo.io/getting-started/quickstart/">usual Kameleo setup</a> by creating a profile.</p><p>Assuming you already have a Python environment with Playwright installed,start by <a href="https://pypi.org/project/kameleo.local-api-client/">installing the Kameleo SDK</a>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">pip install kameleo-local-api-client</code></pre></div><p>Then, in your Playwright script, initialize the Kameleo API client and generate a browser profile:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from kameleo.local_api_client import KameleoLocalApiClient
from kameleo.local_api_client.models import CreateProfileRequest

# Connect to the Kameleo API client
client = KameleoLocalApiClient(endpoint="http://localhost:5050")
# Search for a real-world fingerprint and create a Kameleo profile based on it
fps = client.fingerprint.search_fingerprints(
    device_type="desktop",
    os_family="windows",
    browser_product="chrome",
    browser_version="&gt;145",
)
profile = client.profile.create_profile(
    CreateProfileRequest(fingerprint_id=fps[0].id, name="twsc demo")
)</code></pre></div><p>The above snippet connects the Kameleo API client from the SDK to the local Kameleo Docker APIs. It retrieves a <a href="https://substack.thewebscraping.club/p/understanding-browser-fingerprint">realistic browser fingerprint</a> from the database and creates a persistent browser profile called &#8220;twsc demo&#8221; based on it. In this case, the fingerprint profile is for a desktop Chrome browser (version &gt;145) running on Windows.</p><p>Run the script above. If you started the Linux container of Kameleo Docker while mapping port <em>80</em> for the web GUI, then you&#8217;ll be able to see the &#8220;twsc demo&#8221; profile at <em>http://localhost:80</em>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7VeS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7VeS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 424w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 848w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 1272w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7VeS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png" width="1456" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the &#8220;twsc demo&#8221; profile&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the &#8220;twsc demo&#8221; profile" title="Note the &#8220;twsc demo&#8221; profile" srcset="https://substackcdn.com/image/fetch/$s_!7VeS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 424w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 848w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 1272w, https://substackcdn.com/image/fetch/$s_!7VeS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd60baf46-86ad-4bd6-bf7f-aad1a06b7a24_3071x1620.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the &#8220;twsc demo&#8221; profile</figcaption></figure></div><h3>Step #5: Connect With Playwright</h3><p>You can now connect Playwright to the Kameleo profile created above <a href="https://substack.thewebscraping.club/p/webdriver-vs-cdp-vs-bidi">via CDP</a> using the following WebSocket URL:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">ws://localhost:5050/playwright/&lt;KAMELEO_PROFILE_ID&gt;</code></pre></div><p>Achieve that by using <a href="https://playwright.dev/python/docs/api/class-browsertype#browser-type-connect-over-cdp">Playwright&#8217;s </a><em><a href="https://playwright.dev/python/docs/api/class-browsertype#browser-type-connect-over-cdp">connect_over_cdp()</a></em> method on the target URL:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from playwright.sync_api import sync_playwright

# Kameleo profile creation...

# Connect Playwright to the Kameleo instance based on the configured profile
ws_endpoint = f"ws://localhost:5050/playwright/{profile.id}"
with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(endpoint_url=ws_endpoint, timeout=90_000)

    # Regular Playwright automation logic...</code></pre></div><p>Wonderful! Playwright is attached to the browser session managed by Kameleo Docker. You can now automate it using standard Playwright APIs as if it were a regular local Chromium instance.</p><h3>Step #6: Implement the Automation Logic</h3><p>To achieve the scraping goal, begin by inspecting the page to study its DOM structure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zk-5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zk-5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 424w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 848w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 1272w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zk-5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png" width="1456" height="871" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:871,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Inspecting a product on the page&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Inspecting a product on the page" title="Inspecting a product on the page" srcset="https://substackcdn.com/image/fetch/$s_!zk-5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 424w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 848w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 1272w, https://substackcdn.com/image/fetch/$s_!zk-5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26be934e-c39d-4d8b-ade1-f7fef47d51fe_2688x1608.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Inspecting a product on the page</figcaption></figure></div><p>Then, apply the following Playwright logic (connected to a Kameleo profile) to automate scraping on the JavaScript-rendered page:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Connect Playwright to the Kameleo instance based on the configured profile
ws_endpoint = f'ws://localhost:5050/playwright/{profile.id}'
with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(endpoint_url=ws_endpoint, timeout=90_000)

    # Open a new page
    context = browser.contexts[0]
    page = context.new_page()

    # Visit target site
    page.goto("https://www.scrapingcourse.com/javascript-rendering")

    # Where to store the scraped data
    products = []

    # Wait for products to render
    page.wait_for_selector(".product-item")

    # Locate all product items
    product_elements = page.locator(".product-item")

    for i in range(product_elements.count()):
        # Select the nth product
        product_element = product_elements.nth(i)

        # Extract the product data
        name = product_element.locator(".product-name").inner_text()
        price = product_element.locator(".product-price").inner_text()
        image = product_element.locator("img.product-image").get_attribute("src")
        link = product_element.locator("a.product-link").get_attribute("href")

        # Populate a product object with the scraped data
        product = {
            "name": name,
            "price": price,
            "image": image,
            "url": link
        }
        # Append it to the products list
        products.append(product)</code></pre></div><p>The above snippet instructs the controlled browser to visit the target page, waits for product elements to load, then iterates through each product DOM node to extract structured fields (name, price, image, URL) and stores them in a Python list for downstream processing.</p><p>The Kameleo-powered automation script is almost complete. Only one step remains!</p><h3>Step #7: Stop the Kameleo Profile</h3><p>Normally, in a Playwright scenario, you would need to call <em>browser.close()</em> to terminate the browser session and release its resources.</p><p>In Kameleo, that&#8217;s not required. Instead, you only need to call:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">client.profile.stop_profile(profile_id=profile.id)</code></pre></div><p>The above line of code sends a close command to the browser via CDP. Once the browser actually stops, the Kameleo profile is terminated, too. This ensures that all resources associated with both the browser and the running profile are properly released.</p><h3>Step #8: Run the Script</h3><p>The final Playwright automation script, connecting via CDP to the stealth browser instance exposed by Kameleo Docker, will contain:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># pip install playwright kameleo-local-api-client

from kameleo.local_api_client import KameleoLocalApiClient
from kameleo.local_api_client.models import CreateProfileRequest
from playwright.sync_api import sync_playwright

# Connect to the Kameleo API client
client = KameleoLocalApiClient(endpoint="http://localhost:5050")
# Search for a real-world fingerprint and create a Kameleo profile based on it
fps = client.fingerprint.search_fingerprints(
    device_type="desktop",
    os_family="windows",
    browser_product="chrome",
    browser_version="&gt;145",
)
profile = client.profile.create_profile(
    CreateProfileRequest(fingerprint_id=fps[0].id, name="twsc demo")
)

# Connect Playwright to the Kameleo instance based on the configured profile
ws_endpoint = f'ws://localhost:5050/playwright/{profile.id}'
with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(endpoint_url=ws_endpoint, timeout=90_000)

    # Open a new page
    context = browser.contexts[0]
    page = context.new_page()

    # Visit target site
    page.goto("https://www.scrapingcourse.com/javascript-rendering")

    # Where to store the scraped data
    products = []

    # Wait for products to render
    page.wait_for_selector(".product-item")

    # Locate all product items
    product_elements = page.locator(".product-item")

    for i in range(product_elements.count()):
        # Select the nth product
        product_element = product_elements.nth(i)

        # Extract the product data
        name = product_element.locator(".product-name").inner_text()
        price = product_element.locator(".product-price").inner_text()
        image = product_element.locator("img.product-image").get_attribute("src")
        link = product_element.locator("a.product-link").get_attribute("href")

        # Populate a product object with the scraped data
        product = {
            "name": name,
            "price": price,
            "image": image,
            "url": link
        }
        # Append it to the products list
        products.append(product)

    # Print the scraped products
    for product in products:
        print(product)

# Stop the Kameleo profile
client.profile.stop_profile(profile_id=profile.id)</code></pre></div><p>Execute the script, and you should see output similar to this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tH8f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tH8f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 424w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 848w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 1272w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tH8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png" width="1456" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The output produced by the automation script&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The output produced by the automation script" title="The output produced by the automation script" srcset="https://substackcdn.com/image/fetch/$s_!tH8f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 424w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 848w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 1272w, https://substackcdn.com/image/fetch/$s_!tH8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21c6244e-687f-4002-87e0-c421f94958bc_1692x893.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The output produced by the automation script</figcaption></figure></div><p>Notice how the script successfully scraped product data from the JavaScript-rendered page.</p><p>Once execution completes, open the Kameleo web GUI, and you&#8217;ll notice that the &#8220;twsc demo&#8221; profile is now marked as &#8220;TERMINATED&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zZCP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zZCP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 424w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 848w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 1272w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zZCP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png" width="1456" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Note the updated status of the Kameleo profile&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Note the updated status of the Kameleo profile" title="Note the updated status of the Kameleo profile" srcset="https://substackcdn.com/image/fetch/$s_!zZCP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 424w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 848w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 1272w, https://substackcdn.com/image/fetch/$s_!zZCP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8db45310-8917-4422-8ff1-02ddda4896c3_3057x1613.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Note the updated status of the Kameleo profile</figcaption></figure></div><p>That doesn&#8217;t mean the profile is gone forever. Quite the opposite!</p><p>Kameleo profiles are reusable, meaning you can retrieve and start them again later to continue the browsing session with the same fingerprint and persisted state. I&#8217;ll cover exactly how to do that in a dedicated FAQ.</p><p>Mission complete! You just learned how to use Kameleo Docker for Playwright automation. With very similar logic, you can automate Puppeteer, Selenium, or any other CDP-compatible solution, in both Python and JavaScript.</p><h3>Pricing Model</h3><p>Kameleo Docker is included across all plans at no additional cost. You get the same core limits (concurrent browsers, number of profiles, and browser usage time) regardless of whether you run the desktop app or the containerized version. So, <a href="https://kameleo.io/pricing">take a look at the official pricing page</a> for more information.</p><h2>Anti-Bot Performance Benchmarks</h2><p>To test Kameleo Docker, I ran a simple script against one page protected by each major anti-bot detection system. The results are shown below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kcyp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kcyp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 424w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 848w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 1272w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kcyp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png" width="1456" height="461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:461,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Vanilla Playwright (headless) vs vanilla Playwright (headful) vs Kameleo Docker&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Vanilla Playwright (headless) vs vanilla Playwright (headful) vs Kameleo Docker" title="Vanilla Playwright (headless) vs vanilla Playwright (headful) vs Kameleo Docker" srcset="https://substackcdn.com/image/fetch/$s_!kcyp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 424w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 848w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 1272w, https://substackcdn.com/image/fetch/$s_!kcyp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26a58275-3f59-4452-93a9-a8cf18f700b7_1536x486.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Vanilla Playwright (headless) vs vanilla Playwright (headful) vs Kameleo Docker</figcaption></figure></div><p><strong>Note</strong>: All tests were performed locally using my ISP&#8217;s residential IP address.</p><p>As shown above, in this basic experiment, Kameleo Docker achieved a 100% success rate. In contrast, Playwright consistently failed in headless mode and, in some cases, also struggled in headful mode.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/consulting&quot;,&quot;text&quot;:&quot;Need help with your scraping project?&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://substack.thewebscraping.club/p/consulting"><span>Need help with your scraping project?</span></a></p><div><hr></div><h3>Final Thoughts on Kameleo Docker</h3><p><em>What stood out when I met Barnabas at <a href="https://www.praguecrawl.com/">Prague Crawl 2026</a> (see you next year &#128521;</em>)<em> was the clear passion the team has for the project, along with their focus on quality and continuous improvement.</em></p><p><em>At the same time, when testing new products, especially technical and complex ones like Kameleo Docker, you usually stumble across bugs or unexpected behavior. I can confidently say that this wasn&#8217;t the case at all here. Everything ran smoothly from the beginning, and I didn&#8217;t encounter any issues&#8230;</em></p><p>On top of that, t<em>he benchmark results are promising, and I didn&#8217;t notice any significant performance lag. Thus, my honest takeaway is simple: if you&#8217;re looking for a production-ready, containerized stealth browser, or you&#8217;re simply passionate about automation and scraping, consider giving Kameleo Docker a try!</em></p><p>In this article, I covered what the project is about, what it offers, how it works, and how to use it. As always, remember to use Kameleo Docker only for legal and <a href="https://substack.thewebscraping.club/p/best-practices-for-ethical-web-scraping">ethical web scraping and automation</a>. Until next time!</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Web Scraping Club is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>FAQ</h2><h3>Is Kameleo Docker different from the desktop app?</h3><p>Kameleo Docker differs from the desktop app mainly in deployment. Instead of a local GUI, it runs as a containerized service that runs on both Linux and Windows servers. Feature parity is largely preserved, including profiles, fingerprinting, and browser engines.</p><h3>Can I reuse already created profiles in Kameleo Docker?</h3><p>Yes! Profiles can be reused by retrieving the full list of profiles, filtering by name (or ID, if you know it), and then starting the desired profile. For example, to reuse the &#8220;twsc demo&#8221; profile, write:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from kameleo.local_api_client import KameleoLocalApiClient
from kameleo.local_api_client.models import ProfileLifetimeState

# Connect to the Kameleo API client
client = KameleoLocalApiClient(endpoint="http://localhost:5050")

# Fetch all available profiles
profiles = client.profile.list_profiles()

# Find the profile with the specific name
target_name = "twsc demo"
profile = next((p for p in profiles if p.name == target_name), None)

# Check if the profile was found
if profile:
    # Start the existing profile if it isn't already running
    if profile.status.lifetime_state != ProfileLifetimeState.RUNNING:
      client.profile.start_profile(profile.id)</code></pre></div><h3>Can I use Kameleo Docker in my CI/CD?</h3><p>Kameleo Docker fits naturally into CI/CD pipelines by running as a disposable, reproducible container in build or test stages. You can spin up browsers on demand, run automated flows, and tear them down after execution. Configuration is <a href="https://developer.kameleo.io/integrations/docker/#example-with-docker-compose">typically handled via Docker Compose</a>.</p><h3>Does Kameleo Docker support proxy integration?</h3><p>Yes! HTTP, HTTPS, and SOCKS proxies can be configured at profile creation time, <a href="https://developer.kameleo.io/tutorials/using-proxy-servers/">as explained in the documentation</a>.</p><h3>Can Kameleo Docker scale to thousands of browsers?</h3><p>Kameleo Docker supports horizontal scaling through standard orchestration tools. You can run multiple containers across clusters using Kubernetes or <a href="https://developer.kameleo.io/integrations/docker/#aws-ecs-support">AWS ECS</a>, each managing independent browser instances.</p><h3>How Does Firefox Automation Work in Kameleo Docker?</h3><p>Kameleo Docker supports Firefox-based automation through the Junglefox engine. Because Playwright cannot connect directly to Firefox-based sessions, Kameleo provides a <em><a href="https://developer.kameleo.io/integrations/docker/#using-junglefox-playwright-pw-bridge">pw-bridge</a></em><a href="https://developer.kameleo.io/integrations/docker/#using-junglefox-playwright-pw-bridge"> helper</a> that acts as a compatibility layer. This component translates Playwright connections into the correct browser session, allowing standard automation scripts to run unchanged while still using Firefox-based fingerprint profiles.</p><div><hr></div><p><em>Did you like this article? Share it with someone who might find it useful and get a discount on paid plans.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.thewebscraping.club/p/kameleo-docker-exploring-the-docker?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://substack.thewebscraping.club/p/kameleo-docker-exploring-the-docker?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><p></p>]]></content:encoded></item></channel></rss>