Skip to content
Expedify
6 min

Web Scraper

For the pages nobody built an integration for. Twenty-nine fields, because the open web does not cooperate — but four of them decide almost everything.

Every other node in this module talks to a system that agreed to be talked to. A website did not. There is no schema, no authentication you were given, no promise the markup will look the same next week — and yet most of what you want to know about a company is on its own site, written by them, for free.

The Web Scraper reads it. The size of its configuration is not complexity for its own sake; it is what fetching arbitrary pages politely and reliably actually costs.

The four fields that decide everything

Nine of twenty-nine. The rest are limits, selectors, authentication and output shape.

url

What it holds
URL to scrape (supports {{variables}})

crawl_mode

What it holds
Crawl mode: single page, sitemap, link discovery, or URL list One of: single · sitemap · discover · url_list Defaults to single.

engine

What it holds
Rendering engine: auto, http-only, jina reader, or browser One of: auto · http · jina · browser Defaults to auto.

extract_mode

What it holds
Content extraction mode One of: smart · full · selectors Defaults to smart.

max_pages

What it holds
Maximum pages to scrape Defaults to 25.

priority_patterns

What it holds
High priority URL patterns for discover mode

exclude_patterns

What it holds
URL patterns to exclude

respect_robots_txt

What it holds
Honor robots.txt rules Defaults to true.

request_delay_ms

What it holds
Delay between requests in milliseconds Defaults to 1000.

crawl_mode decides how many pages you get and how they are chosen: one page, everything in a sitemap, links discovered by following the site, or a list you supply. discover with a small max_pages is the useful default for “tell me about this company” — it follows links and stops.

extract_mode decides how much of each page survives. smart strips navigation, footers, sidebars and advertising and keeps what reads like content — which is what you want unless you are extracting a specific element, in which case selectors and your own CSS selectors do it precisely.

The engine, and the two things nobody tells you

The engine is how the page gets fetched, and it has three real behaviours behind four names.

http

What actually happens
A plain request and an HTML parse. Fast, free, and blind to anything a page renders with JavaScript.

jina

What actually happens
A reader service that renders the page properly. Handles modern sites — and is a paid, metered integration.

auto

What actually happens
Try HTTP; if it works and returns more than 200 characters, keep it. Otherwise fall through to Jina.

browser

What actually happens
Not implemented. Selecting it logs a warning and does plain HTTP instead.

Two things follow from that table. First, browser is a dropdown option that does not do what it says — if you picked it because a site needs a real browser, you got the engine that cannot handle one. Second, auto is not free. A JavaScript-heavy site returns almost nothing over plain HTTP, falls below the two-hundred-character bar, and quietly goes to the metered reader. That is the correct behaviour and it is worth knowing before the bill.

If you are scraping at any volume, pin the engine rather than leaving it on auto. Run one page each way first and look at {{alias.char_count}} — that tells you which engine that site needs, and then you choose it deliberately.

A worked example

A company is added to the CRM. The workflow reads a few pages of its own website and files what it found against the record.

Five pages, chosen on purpose

discover mode with patterns that steer it toward the pages that say something.

Scroll for all 3 steps →

The patterns are the interesting part. priority_patterns pushes the crawler toward about, services, products, pricing and contact — the five pages that actually describe a business. exclude_patterns keeps it out of the blog, the news and the careers section, which are enormous and tell you nothing about what the company sells.

Without those, max_pages: 5 spends itself on whatever the homepage links to first, which is usually three blog posts and a cookie policy. Steering the crawl is worth more than raising the limit.

request_delay_ms is set above the default here. A second between requests is polite; a second and a half on a small site is politer, and the difference to your workflow is four seconds.

What comes back

{{alias.full_text_combined}}

What you get
Every page's text, joined. What you hand to a model or file as a note.

{{alias.pages}}

What you get
One entry per page, so you can tell which page said what.

{{alias.page_count}} · {{alias.char_count}}

What you get
How much you actually got. The two numbers to check before believing the result.

{{alias.links_found}}

What you get
Links discovered along the way — useful for a second pass.

What breaks

An empty scrape looks like a successful one. A page that blocks you, or renders entirely in JavaScript over plain HTTP, returns almost no text — not an error. The workflow carries on and files an empty note, or hands a model nothing to summarise and gets a confident summary of nothing. Check {{alias.char_count}} and branch when it is implausibly small. This is the single most useful guard you can add to a scraping workflow.

Robots rules are respected by default, and you should leave them that way. respect_robots_txt defaults on. Turning it off is a decision about somebody else's server and your organisation's reputation, not a configuration tweak — and a site that has asked not to be crawled will often notice.

Selectors rot. If you use extract_mode of selectors against a site you do not control, your workflow depends on someone else's CSS class names. It will work perfectly until a redesign, then return nothing — silently, per the point above. smart mode degrades more gracefully because it has no idea what the class names are.

Scraped text is somebody else's writing. Putting it straight into a CRM field, an email or a model prompt means whatever is on that page is now inside your workflow — including text written to manipulate whatever reads it. Treat it as data, never as instructions, and be careful about pasting it into a prompt without saying where it came from.

Try it

  1. Scrape one page with crawl_mode on single and engine on http. Read {{alias.char_count}}.
  2. Do the same page with engine on jina and compare the two numbers. On a modern site the difference is the whole lesson.
  3. Now try a single-page app — anything that renders client-side — over http. Watch the character count collapse, and note that nothing failed.
  4. Switch to discover with max_pages of 5 and no patterns, then again with the patterns from the workflow above. Compare which five pages you got.
  5. Pick engine of browser and check the execution log. The warning about falling back is the proof.

Next: Web Search — when you do not know which page to read yet, and something has to find it for you.

Related lessons