// Use case · RAG knowledge base

Turn a whole site into clean markdown for your index

For teams feeding a retrieval index: map a domain, crawl it under a page budget, and receive each page as markdown through a signed webhook while the crawl runs.

  • credit per crawled page

    1

  • pages per crawl, max

    5,000

  • credits for a failed page

    0

POST your-api.example.com/hooks/wayfern signed
{  "type": "page",  "completed": 12,  "failed": 1,  "data": {    "markdown": "# Webhooks\n\nEvery delivery…",    "metadata": {      "statusCode": 200,      "sourceUrl": "https://docs.example.com/…"    }  },  "metadata": { "index": "docs-v3" }}
credit per page that lands
A page event posted to your endpoint while the crawl runs. Your own metadata comes back on every delivery. Each successfully crawled page costs 1 credit.

// Why

Point at a domain, get a corpus

The problem

A corpus built by hand does not scale

  • A crawler without a budget can wander a whole domain and bill you for it.
  • Navigation, headers, footers and cookie notices end up in your chunks and pollute retrieval.
  • Polling a long job wastes calls, and failed pages vanish into the result set.

What Wayfern does

A bounded crawl that streams markdown to you

  • limit (1 to 5,000), maxDepth (0 to 10) and path patterns cap the job before it runs.
  • onlyMainContent is on by default: page chrome is dropped, links are made absolute, the title stays on top.
  • Signed webhooks deliver each page as it lands. Failures are listed separately and never billed.

// How it works

Size it, bound it, stream it in

The crawl runs in the background. Chunking and embedding start while it is still going, because each page is posted to you as it completes.

  1. Step 1 of 4

    Size it with map

    Discover URLs from sitemaps first and page links second, at 2 credits per 10 returned.

    POST /api/v1/map

  2. Step 2 of 4

    Start a bounded crawl

    Set limit, maxDepth and path patterns. You get a job id at once; nothing is charged at the start.

    POST /api/v1/crawl

  3. Step 3 of 4

    Receive pages as they land

    Each page event carries the markdown and your own metadata, signed with HMAC-SHA256.

    X-Wayfern-Signature: sha256=…

  4. Step 4 of 4

    Chunk and upsert

    Verify, chunk, embed. Poll the job or read its errors list any time; both are free.

    GET /api/v1/crawl/:id

// Code

Start the crawl, verify the deliveries

The map call is the dry run: it tells you the page count before you commit. The last two tabs check the webhook signature on the raw body.

Map, crawl and verify
curl -X POST https://api.wayfern.com/api/v1/crawl \
  -H "Authorization: Bearer wf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://docs.example.com",
    "limit": 500,
    "maxDepth": 3,
    "includePaths": ["^/docs/"],
    "excludePaths": ["^/docs/changelog/"],
    "delay": 250,
    "concurrency": 3,
    "webhook": {
      "url": "https://api.example.com/hooks/wayfern",
      "events": ["page", "completed"],
      "metadata": { "index": "docs-v3" }
    },
    "scrapeOptions": { "formats": ["markdown"], "onlyMainContent": true }
  }'

// Budget

Four levers, one request body

A crawl that cannot be bounded cannot be budgeted. POST /api/v1/crawl takes its limits in the same body as the job, and an invalid pattern is rejected before anything runs.

  • 1 – 5,000, default 50

    limit

    The hard ceiling on pages the job will scrape, and so on what it can cost. The job record carries it back as limit.

  • 0 – 10, default 3

    maxDepth

    How many link hops from the start URL the crawl may follow. Depth 0 crawls the seed page and stops.

  • up to 50 patterns

    includePaths

    Regular expressions a path must match to be crawled. A pattern that does not parse is rejected at submit time.

  • up to 50 patterns

    excludePaths

    Regular expressions that drop a path. Same up-front validation: you find out before the job runs.

The rest of the options

  • allowSubdomains

    What it does
    Off by default: the crawl stays on the host you named. Turn it on to follow links onto subdomains.
  • useSitemap

    What it does
    On by default. The frontier is seeded from the site’s sitemaps before a link is followed.
  • delay

    What it does
    0 to 60,000 ms of pause between requests to the site, default 0, applied before each batch.
  • concurrency

    What it does
    1 to 5 pages fetched in parallel within one job, default 3.
  • scrapeOptions

    What it does
    The full scrape option set, applied to every page, so a crawled page and a scraped page come back identical.

// Webhooks

Signed webhooks, one per page

Attach a webhook and pick events, or omit them to receive all four. Your metadata object comes back verbatim on every delivery, which is how a payload knows which index it belongs to.

  • started

    When it fires
    The job has begun.
  • page

    When it fires
    One page finished. The whole document, markdown and metadata, is in data.
  • completed

    When it fires
    The job finished on its own terms.
  • failed

    When it fires
    The job aborted. The reason is in error: a duration ceiling, an exhausted balance or a restart.

// Clean output

Chrome out, chunks in

onlyMainContent is on by default and drops navigation, headers, sidebars, footers and cookie notices. The page title is put back at the top, so no document arrives without saying what it is.

What the page shipped, and what lands in your pipeline
<head><title>Example Docs</title></head>
<body>
  <nav class="navbar">
    <a href="/">Home</a><a href="/pricing">Pricing</a>
  </nav>
  <header>Example Docs</header>
  <article>
    <h1>Installing the client</h1>
    <p>Add the package to your project and set your API key.</p>
  </article>
  <aside class="sidebar">On this page…</aside>
  <footer>© Example, Inc.</footer>
</body>
  • excludeTags

    CSS selectors to drop, for chrome a generic pass misses: a promo rail, a breadcrumb bar, an inline signup form.

  • includeTags

    CSS selectors to keep; everything else goes. An include list is your definition of main content, so the automatic extractor is skipped.

  • Links and images

    Every href and src is made absolute, because markdown is read far from its page. Inline base64 images become their alt text by default.

// What it costs

1 credit per page that lands

Nothing at the start, nothing for the pages that failed, nothing for polling. Here is the whole bill for mapping and crawling a documentation site.

A 500-page docs site, mapped and crawled

Markdown is the default format and carries no add-on.

Credits for: A 500-page docs site, mapped and crawled
ItemCredits
map, 500 URLs returned100
crawl started (job id returned)0
500 pages land500
polling, errors list, cancel0

Total

600credits

about $7.50
at $0.0125 / credit

About 2 runs a month on Developer ($19 for 1,520 credits).

Runs of this crawl per month, by plan

  • Developer · $19 / month · 1,520 credits 2runs
  • Business · $99 / month · 9,000 credits 15runs
  • Scale · $499 / month · 46,000 credits 76runs

The same balance covers browser sessions, search and every other endpoint. See the pricing page.

// FAQ

Questions about crawling for RAG

What does a crawl cost?

1 credit per successfully crawled page. Starting a job, polling, the errors endpoint and cancelling are free, and a page that fails is not billed. Asking for a screenshot, PDF or JSON output adds 4 credits a page; an LLM summary adds 2.

How do I verify a webhook?

Every delivery carries X-Wayfern-Timestamp and, when a signing secret is set, X-Wayfern-Signature: sha256=<hex>: an HMAC-SHA256 over ${timestamp}.${body}, computed on the raw body. The Node.js and Python tabs above show the check.

What if my webhook endpoint is down?

Delivery is best-effort: up to 3 attempts with exponential backoff, and a 4xx other than 408 or 429 stops the retries. A webhook that never lands never fails the crawl: the pages stay readable through the polling API. The URL must be https; an http:// URL is rejected at submit time.

What happens to pages that fail?

GET /api/v1/crawl/:id/errors lists them, up to the first 50, each with the URL, a typed reason, a message and a timestamp, while the job’s failed count keeps climbing past that. Reading it is free, and a failed page is never billed.

Can I stop a running crawl?

DELETE /api/v1/crawl/:id cancels it. Pages crawled up to that point stay readable and stay billed, and the job reports status cancelled with its running creditsUsed. If the balance runs out mid-crawl, the job ends with that reason and the pages already crawled stay readable.

How long are crawl results kept?

The job record, its pages and its errors stay readable until the expiresAt returned when you started it: seven days by default. Pull the corpus into your own store before then.

// Next step

Map a domain and see the page count first

Size the site with one map call, set a page budget, and let the markdown come to you. Start with a credit pack if you only need one corpus.