Markdown Editor

Web Crawler System Design Template

Polite distributed crawler: URL frontier with per-host queues, RFC 9309 robots.txt, adaptive delay, URL-seen and simhash dedup, recrawl scheduling, trap budgets

System DesignFullRFC 9309 (2022); Mercator and IRLbot papers; docs/48 design standarddesignwebcrawlermath

How to use: Use it when designing or interviewing on a web crawler for search, archiving or a corpus. Fill the crawl purpose and the politeness policy first, then size the fetch rate and the URL-seen set. The main pitfall is treating bandwidth as the limit when per-host politeness and traps decide what you can crawl.

Preview

System Design: [Web crawler name]

Reference design for a polite, distributed web crawler that fetches and refreshes [1 billion] pages a month for a search index or a research corpus. It covers the URL frontier with priority and per-host politeness queues (after the Mercator design), URL and content deduplication including simhash near-duplicate detection, robots.txt handling under the Robots Exclusion Protocol (RFC 9309, September 2022), sitemaps, recrawl scheduling with HTTP conditional requests, and defences against crawler traps and spam (after IRLbot). It follows the structure of the System Design Document template, adds a 45-minute interview path, access-pattern and failure-mode tables and a cited "How real systems do it" box, and is pre-filled with a worked design to adapt. Replace every [bracketed] value and every row marked Example; values marked Example are assumptions, not benchmarks. Crawling, storing and reusing content can raise copyright, privacy and terms-of-service questions; this is a design format, not legal advice, so check the current official text and a qualified professional.

Document control

FieldValue
Document ID[SDD-CRAWL-001]
System / feature[Web crawler for the search index]
Version[0.1]
Status[Draft / In review / Approved / Implemented / Superseded]
Owner[@owner]
Author(s)[@author]
Reviewers[@reviewer-1], [@reviewer-2]
Last updatedYYYY-MM-DD
Classification[Internal]
DifficultyIntermediate
User-agent product token[ExampleBot]
Crawler information page[https://example.com/bot]
Related[Search indexing pipeline], [Legal review of crawl purpose], [ADR: URL-seen store]

Approvals

RoleNameDecisionDate
Tech lead[@name][Approved / Changes requested]YYYY-MM-DD
Staff / principal engineer[@name][Decision]YYYY-MM-DD
SRE / operations[@name][Decision]YYYY-MM-DD
Legal and privacy[@name][Decision]YYYY-MM-DD
Security[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft for design review
0.2YYYY-MM-DD[@name]Example: Replaced fixed 1 s host delay with adaptive delay based on response time
0.3YYYY-MM-DD[@name]Example: Added per-domain crawl budgets after a link-farm incident
1.0YYYY-MM-DD[@name]Example: Approved

Contents

1. Overview

1.1 Problem statement

[Example: The search index is fed by a single-machine crawler that fetches 40 million pages a month, revisits pages on a fixed 60-day cycle and keeps its URL set in memory. Index freshness complaints are rising, the crawler restarted from scratch twice last quarter after crashes, and one site owner blocked our address range after we sent bursts of parallel requests to a small server.]

1.2 Proposed solution

[Example: A distributed crawler partitions hosts across crawl nodes by a hash of the host name. On each node a URL frontier holds priority queues in front and per-host politeness queues behind, so no host ever sees more than one request at a time from us and the gap between requests adapts to how fast the host answers. Fetchers check a robots.txt cache that follows RFC 9309, use conditional requests for recrawls and store raw responses in WARC files. Extracted links pass a URL-seen check before entering the frontier; content passes exact and near-duplicate checks before indexing. A scheduler recrawls each page at an interval learned from how often it changes, and per-domain budgets stop traps and link farms from eating the crawl.]

1.3 Decisions requested from reviewers

IDQuestionRecommended optionSection
Q-01Example: How are URLs partitioned across nodes?By hash of host name, so each host's politeness state lives on one node7.1
Q-02Example: How fast may we crawl one host?One connection per host; wait max(1 s, 10 x last response time)7.3
Q-03Example: Exact or approximate URL-seen set?Exact fingerprint set on disk with a Bloom filter in front7.4
Q-04Example: What happens when robots.txt returns 5xx?Treat the site as fully disallowed, as RFC 9309 requires7.2
[Q-nn][Question][Option][Section]

1.4 45-minute interview path

Use this order when the document serves an interview or a short design review. The written sections below are the long form of each step.

MinutesCoverOutput on the whiteboard
0 to 5Scope: purpose, HTML only or more, freshness, politeness; below-the-line items (2.3)Purpose and three constraints
5 to 10Estimates: pages per second, bandwidth, storage, URL-seen set size (section 3)"Politeness, not bandwidth, is the limit" consequence
10 to 15Interfaces: seed and control API, output to the indexer (section 4)Two interfaces
15 to 25High-level design: frontier, fetcher, robots cache, parser, dedup, store (section 6)The crawl loop diagram
25 to 40One deep dive: frontier and politeness (default, 7.1 and 7.3), or deduplication (7.4), or recrawl scheduling (7.5)Options, choice, reason
40 to 45Failures (node loss, DNS outage, trap), the 10x row in section 10Two failure rows

Start the default deep dive with the naive answer, one first-in first-out queue shared by all fetchers. Show that relative links make long runs of URLs from the same host, so many fetchers hit one server at once. Then introduce the back queues with one host each and a heap ordered by the next allowed contact time.

2. Requirements

2.1 Core functional requirements

IDRequirementPriority
FR-01Example: Crawl HTML pages over HTTP and HTTPS starting from seed lists and sitemapsMust
FR-02Example: Obey robots.txt as specified in RFC 9309 for our product tokenMust
FR-03Example: At most one open connection per host; adaptive delay between requestsMust
FR-04Example: Never fetch the same URL twice in one crawl cycle unless it is due for recrawlMust
FR-05Example: Detect exact and near-duplicate content and keep one canonical copyMust
FR-06Example: Recrawl pages at an interval based on their observed change rateMust
FR-07Example: Store raw responses and extracted text for the indexerMust
FR-08Example: Honour noindex and nofollow robots meta tags and the X-Robots-Tag header in the indexerShould
FR-09Example: Let operators block a host or path within 10 minutesMust
[FR-nn][Requirement][Must / Should / Could]

2.2 Non-functional requirements

IDQualityTargetMeasured as
NFR-01ThroughputExample: 1 billion successful page fetches per 30 daysFetch counter
NFR-02PolitenessExample: Zero hosts with two concurrent connections from usConnection audit per host
NFR-03FreshnessExample: Median age of the indexed copy of top 10 million pages under 3 daysSampled recrawl comparison
NFR-04RecoverabilityExample: A node crash loses at most 10 minutes of crawl progressChaos test
NFR-05Duplicate wasteExample: Under 5% of fetches return content already storedContent-hash hit rate
NFR-06ComplaintsExample: Every site-owner complaint answered within 1 business dayTicket system
[NFR-nn][Quality][Target][Measurement]

2.3 Below the line (out of scope)

Name these explicitly so reviewers and interviewers do not pull the design toward them.

  • [Example: rendering JavaScript-heavy pages in a headless browser (separate render queue, later release)]
  • [Example: indexing, ranking and serving search results (see system-design/design-full-text-search)]
  • [Example: crawling behind logins or paywalls (never done by this crawler)]
  • [Example: images, video and PDF files (link recorded, not fetched)]
  • [Item deferred, with the release that will take it]

3. Capacity estimation

3.1 Assumptions

InputSymbolValueSource
Pages fetched per 30 daysNNExample: 1 billionIndex plan
Peak to average ratioffExample: 2Scheduler smoothing
Average HTML size, uncompressedssExample: 100 KBSample crawl
Stored size after compressionscs_{c}Example: 25 KBSample crawl, 4:1
Overhead for robots.txt, redirects, retriesooExample: 20%Sample crawl
Links extracted per pagellExample: 50Sample crawl
Known URLs (seen set)UUExample: 10 billionLink discovery estimate
Average fetch time including connectionttExample: 1 sSample crawl
Parse CPU per pageppExample: 5 msProfiling
Months of history kepthhExample: 6Index requirement

3.2 Fetch rate and bandwidth

Ravg=10930×86 400≈386 pages/s,Rpeak=2×386≈772 pages/sR_{avg} = \frac{10^{9}}{30 \times 86\,400} \approx 386 \ \text{pages/s}, \qquad R_{peak} = 2 \times 386 \approx 772 \ \text{pages/s}
Bavg=386×100 KB×1.2≈370 Mbit/s,Bpeak≈741 Mbit/sB_{avg} = 386 \times 100 \ \text{KB} \times 1.2 \approx 370 \ \text{Mbit/s}, \qquad B_{peak} \approx 741 \ \text{Mbit/s}

Consequence: one data-centre uplink of a few Gbit/s is enough. Bandwidth is not the hard constraint.

3.3 Concurrency and politeness

By Little's law, fetches in flight at peak are Rpeak×t=772×1 s≈772R_{peak} \times t = 772 \times 1 \ \text{s} \approx 772. Because each host gets at most one connection, at least 772 different hosts must be ready to fetch at any moment. Following the Mercator rule of thumb of three back queues per fetch slot, each crawl cluster keeps about 3×772=2 3163 \times 772 = 2\,316 active host queues.

The per-host limit also caps what one site can get: at one request per second, a site of 10 million pages needs 107/86 400≈11610^{7} / 86\,400 \approx 116 days for a full pass, longer than the 30-day cycle. At a 10 s gap (a response time of 1 s times 10) a host gets at most 8 640 pages a day. Consequence: large sites are crawled by priority and sitemaps, not exhaustively, and the frontier must hold a long backlog per host on disk.

3.4 Storage

Smonth=109×25 KB=25 TB,Stotal=25×6=150 TB→225 TB with erasure coding at 1.5xS_{month} = 10^{9} \times 25 \ \text{KB} = 25 \ \text{TB}, \qquad S_{total} = 25 \times 6 = 150 \ \text{TB} \rightarrow 225 \ \text{TB with erasure coding at 1.5x}

Frontier: about 150 bytes per queued URL with metadata; a backlog of 10910^{9} URLs is about 150 GB, so the frontier lives on disk with only the head of each queue in memory.

3.5 Deduplication sets

URL-seen set as exact 8-byte fingerprints: 1010×8 B=80 GB10^{10} \times 8 \ \text{B} = 80 \ \text{GB}, partitioned by host across nodes and kept on SSD.

A Bloom filter in front with a 1% false-positive rate needs −ln⁡(0.01)/(ln⁡2)2≈9.59-\ln(0.01) / (\ln 2)^{2} \approx 9.59 bits per URL and about 7 hash functions, so about 12 GB in memory. A false positive means a new URL is wrongly treated as seen and skipped, so the filter only short-cuts "seen" answers that the exact set then confirms (7.4).

Link checks: 386×50≈19 300386 \times 50 \approx 19\,300 lookups/s on average (38 600 at peak), about 1.67 billion a day. Consequence: batch lookups per node (sort and merge against the on-disk set, as IRLbot's DRUM does) instead of one random disk read per link.

Near-duplicate fingerprints: 64-bit simhash per page, 109×8 B=8 GB10^{9} \times 8 \ \text{B} = 8 \ \text{GB} per table; four permuted tables for a Hamming distance of 3 need 32 GB (7.4).

3.6 Summary

QuantityEstimateDesign consequence
Fetch rate~386 pages/s average, ~772 peakA small fetcher fleet with asynchronous I/O
Bandwidth~370 Mbit/s average, ~741 peakNot the bottleneck
Hosts in flightat least ~772, ~2 316 active queuesPer-host back queues with a ready-time heap
Large sites~116 days for 10 million pages at 1 request/sPriority and sitemaps, not full coverage
Storage~25 TB/month, ~225 TB for 6 months storedCompressed WARC in object storage
URL-seen80 GB exact, 12 GB Bloom filterHost-partitioned, batched checks
Parse CPU~3.9 cores at peakParsing is cheap; scale on I/O

4. API design

4.1 Control and output interfaces

InterfaceOperationPurpose
Control APIPOST /v1/seedsAdd seed URLs or sitemap URLs with a priority
Control APIPUT /v1/hosts/{host}/policyBlock, slow down or set a budget for a host
Control APIGET /v1/hosts/{host}/statusQueue length, last fetch, robots state for support
Control APIPOST /v1/recrawlForce recrawl of a URL list (operator only)
Output streamcrawl.fetched eventsOne event per stored response for the indexer
Output streamcrawl.removed eventsURL gone (404, 410) or newly disallowed

4.2 Fetch request sent to sites

The crawler identifies itself and uses conditional headers on recrawl (RFC 9110):

GET /news/2026/10/a-story HTTP/1.1
Host: www.example.org
User-Agent: Mozilla/5.0 (compatible; ExampleBot/1.0; +https://example.com/bot)
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
If-None-Match: "a7c3-5f1e"
If-Modified-Since: Tue, 27 Oct 2026 08:12:00 GMT

A 304 Not Modified answer costs a few hundred bytes instead of the page. A 429 or 503 with Retry-After pauses the host for at least that time.

4.3 Output event

Each stored response produces one event; the hash below is shortened for the example.

{"url": "https://www.example.org/news/2026/10/a-story", "canonical_url": "https://www.example.org/news/2026/10/a-story", "fetched_at": "2026-10-30T09:14:05Z", "status": 200, "content_type": "text/html", "warc_ref": {"file": "crawl-20261030-0912-n17.warc.gz", "offset": 18273645}, "content_sha256": "3b1f9c0d7e2a4b6c", "simhash": "9f3a5c7e01d2b4a6", "duplicate_of": null, "robots_meta": ["index", "follow"], "links_out": 47}

5. Data model

5.1 Entities

Host state drives politeness; URL state drives scheduling; content records point to raw bytes in WARC files.

5.2 Storage choices

DataStoreKeyMain queriesWhy
Frontier queuesDisk-backed queues per node, heads in memoryPriority level; hostNext URL for the next ready host150 GB backlog cannot live in memory
Host state and robots cacheIn-memory map per node, checkpointedhostIs this path allowed, when may we fetch nextNeeded on every fetch
URL-seen setSorted fingerprint files on SSD per node, Bloom filter in memoryurl_fp (8 bytes)Batch check and insert80 GB exact set, batched access
URL state for recrawlExample: Distributed key-value storeurl_fpDue URLs by time, change historySurvives node moves
Raw responsesWARC files in object storageFile and offsetIndexer reads, reprocessingStandard archive format, cheap storage
Content and simhash indexKey-value store and in-memory permuted tablescontent_sha256; simhash blocksExact and near-duplicate checksFast lookups

5.3 Access patterns

Access patternFrequencyKey or index that serves itPartition key rationale
Pick the next URL to fetch~772/s at peakHeap of host queues by next allowed timeHash of host: one node owns each host, so politeness needs no coordination
Check robots rules for a URLEvery fetchHost map, rules cached up to 24 hSame host partition
Check if a link is new~19 300/s averageBloom filter, then batched merge against url_fp filesLink is routed to the node that owns its host; most links are same-host
Find duplicate contentEvery 200 responsecontent_sha256, then simhash tablesGlobal, sharded by hash prefix
Find URLs due for recrawlContinuousnext_due_at per hostHost partition keeps due URLs next to their politeness state
Block a host on requestRareHost map plus control APIPush to the owning node within minutes

6. High-level design

ComponentResponsibilityScales by
URL frontierPriority front queues, per-host back queues, ready-time heapHosts per node
FetchersAsynchronous HTTP, conditional requests, timeoutsConnections per node
Robots cacheFetch, parse and cache robots.txt per host (7.2)With host partition
DNS resolverAsynchronous resolution with a local cacheResolver instances
Parser and link extractorExtract links, canonical tags, robots metaCPU cores
URL filter and normaliserNormalise, drop out-of-scope and trap-like URLsCPU cores
Host splitterRoute each URL to the node that owns its hostNodes
URL-seen checkBloom filter and batched exact setDisk per node
Content dedupExact hash, simhash near-duplicate searchMemory for tables
Recrawl schedulerCompute next due time per URL (7.5)With URL state store

7. Detailed design

The deep dives in this section, each with options, choice and reason:

Deep diveOptions consideredChoiceReasonSection
Frontier and partitioningOne global queue; partition by URL hash; partition by host hashHost hash, front and back queues per nodePoliteness state local to one node; most links are same-host7.1
PolitenessFixed delay; delay from robots extensions; adaptive delayAdaptive: max(1 s, 10 x last response time), back off on errorsFast sites crawl faster, slow sites are protected7.3
URL-seenIn-memory set; Bloom filter only; exact disk set with batchingBloom filter plus batched exact disk setNo silent loss of new URLs; bounded memory7.4
RecrawlFixed cycle; sitemap only; change-rate modelChange-rate model plus sitemap hints and conditional requestsSpend fetches where content changes7.5

7.1 Frontier

  • Front queues: one first-in first-out queue per priority level (Example: 5 levels). Priority comes from source (sitemap, seed, discovered link), estimated page importance and whether it is a recrawl.
  • Back queues: each holds URLs of exactly one host. A host-to-queue table maps hosts to queues; a heap orders queues by the time their host may next be contacted.
  • Getting a URL: a fetch slot pops the heap root (waiting if its time is in the future), takes the head URL of that queue and fetches it. When the fetch ends, the host's next allowed time is computed (7.3) and the queue goes back into the heap. When a back queue empties, it is refilled from the front queues with a bias toward high priority.
  • Partitioning: host name hash picks the crawl node. A link to another host is sent to its owner node in batches.

7.2 Robots.txt under RFC 9309

SituationBehaviour in this designRFC 9309 basis
Before the first fetch on a hostFetch /robots.txt for that scheme, host and portSection 2.3
Group selectionMatch our product token case-insensitively; fall back to the * groupSection 2.2.1
Allow and disallow conflictThe rule with the longest matching path wins; on a tie, allow winsSection 2.2.2
Special charactersSupport * (any sequence) and $ (end of path); # starts a commentSection 2.2.3
Redirects for robots.txtFollow at least 5; more than 5 means treat as unavailableSection 2.3.1.2
4xx (unavailable)Crawl allowedSection 2.3.1.3
5xx or network error (unreachable)Treat as complete disallow; keep a cached copy if one exists and retrySection 2.3.1.4
CachingReuse for at most 24 hours unless the file is unreachableSection 2.4
File sizeParse at least the first 500 KiBSection 2.5
Crawl-delay and Sitemap linesNot defined by RFC 9309; Sitemap used as a hint, Crawl-delay respected as a minimum gap by policySection 2.2.4 allows other records

RFC 9309 also notes that robots.txt is not a form of access authorisation. Respecting it is the crawler's policy and commitment, so log every decision.

7.3 Politeness and adaptive delay

RuleExample value
Connections per host1
Gap after a fetchmax(1 s, 10 x the last response time), the factor that Mercator reported using
On 429 or 503Wait for Retry-After if present, else double the gap up to 1 hour
On repeated timeoutsDouble the gap; pause the host for 1 day after 10 failures in a row
Per-IP limitHosts that share one IP address share one politeness budget
Operator overrideBlock or set a slower gap per host within 10 minutes (FR-09)

With a 0.4 s response the next allowed time is 4 s later; with a 0.1 s 304 response it is the 1 s minimum.

7.4 Deduplication

  • URL normalisation before the seen check: lowercase scheme and host, remove default ports and fragments, resolve dot segments, apply known safe rules per host (for example removing session-ID parameters that the host is known to ignore). Normalise only in ways that keep the meaning of the URL, and keep the original URL for fetching.
  • URL-seen: the Bloom filter answers "definitely new" cheaply; a "maybe seen" answer and every new URL go into a per-node batch that is sorted and merged against the exact fingerprint files every few minutes. New URLs go to the frontier; the files get the new fingerprints.
  • Exact content: SHA-256 of the normalised body; a hit links the URL to the existing content record and skips indexing.
  • Near-duplicate content: 64-bit simhash of the page text. Split the 64 bits into four 16-bit blocks; if two fingerprints differ in at most 3 bits, at least one block is identical, so four tables, each sorted by one block, find every candidate. With 10910^{9} pages each table returns about 109/216≈15 25910^{9} / 2^{16} \approx 15\,259 candidates per probe, about 61 000 for four, checked with XOR and bit counting in well under a millisecond.

7.5 Recrawl scheduling

  • Estimate a change rate per URL from past fetches (changed or not, by content hash). Set the next interval so the expected number of missed changes stays small, bounded between 1 day and 90 days.
  • Raise priority for URLs that sitemaps list with a recent lastmod; treat changefreq and priority as hints only. Sitemaps hold at most 50 000 URLs and 50 MB uncompressed per file.
  • Recrawls always send If-None-Match and If-Modified-Since when the previous response had an ETag or Last-Modified.
  • URLs that return 404 or 410 twice are removed and a crawl.removed event is emitted; a newly disallowed URL is removed at once.

7.6 Traps, spam and budgets

ProblemSignalDefence
Infinite calendars and faceted URLsMany URLs per host with the same path patternCap URLs per path pattern; cap query parameters
Session IDs in URLsSame content under many URLsLearned parameter removal per host; content hash dedup
Very long or deep URLsLength, depth from seedDrop URLs over 2 048 characters or 16 levels deep
Link farms and spam domainsMany hosts under one domain with few links from outsideBudget per registered domain in proportion to links from other domains (IRLbot's approach)
Soft 404 pages200 status with "not found" templateCompare with a probe for a random URL on the host

7.7 How real systems do it

How real systems do it (paraphrased, not copied). Heydon and Najork's Mercator papers (World Wide Web journal, 1999, and the Compaq SRC report "High-Performance Web Crawling", 2001) describe a frontier of prioritised front queues feeding back queues that each hold one host, with a heap ordered by when each host may be contacted again. The 2001 report says the team first allowed only one thread per host, still received complaints about unbroken request streams, and moved to waiting about ten times the last download time, with three times as many back queues as threads. It also reports that DNS lookups took 70% of each thread's elapsed time until a custom parallel resolver cut it to 14%, and that about 80% of links are relative, so host-based partitioning keeps most URLs on the node that found them. Lee, Leonard, Wang and Loguinov's IRLbot paper (WWW 2008, extended in ACM Transactions on the Web, 2009) reports 6.3 billion valid HTML pages in 41 days from a single server, at about 1 789 pages per second. Its DRUM structure batches URL-seen checks through disk buckets, and its STAR and BEAST methods give each domain a page budget based on links from other domains, so spam cannot snowball. Manku, Jain and Das Sarma (WWW 2007) report that 64-bit simhash fingerprints with up to 3 differing bits work for about 8 billion pages. Read the originals in 12.3; this box keeps only the general idea.

8. Scalability and performance

ConcernApproachLimit before redesign
Fetch rateAsynchronous fetchers, many hosts in flightExample: ~2 000 concurrent connections per node
Host diversityEnough ready hosts in the heapCrawls focused on few sites are politeness-bound, not hardware-bound
URL-seenBatched merges per nodeMerge time grows with the set; add nodes and re-split hosts
DNSLocal caching resolver, asynchronous lookupsUpstream resolver rate limits
StorageAppend-only WARC in object storageCost, not technology

Per-fetch time budget (target: a fetch slot is busy for about 1 s on average):

StepBudget
Heap pop and robots check (memory)0.1 ms
DNS (cached in most cases)5 ms average
TCP and TLS connection (reused when possible)150 ms
Server response and transfer800 ms
Write WARC record and hand off to parser10 ms
Headroomabout 35 ms

9. Reliability, security and operations

9.1 Failure modes

ComponentFailureDetectionBlast radiusMitigationRTO
Crawl nodeCrashHeartbeatHosts owned by that node pauseFrontier and seen files on durable disk, checkpoint every 10 min; hosts reassigned by consistent hashingExample: 10 min
DNS resolverUpstream outageResolution error rateAll new hostsServe from cache with extended TTL; pause hosts that cannot resolveExample: 30 min
Robots cacherobots.txt unreachable (5xx)Status countersOne hostFull disallow per RFC 9309; retry with backoff; use cached copy if presentHost-dependent
Object storageWrite failuresError rateFetch results not storedLocal spill buffer for 1 h; pause fetchers after thatExample: 1 h
Trap or spam domainExplosive URL growth on one domainURLs per domain per hourCrawl budget wastedDomain budget, path-pattern caps, operator blockExample: 1 h
Site owner complaintOverload or unwanted crawlComplaint channelReputation, IP blocksBlock or slow the host in 10 min; review the delay policyExample: 1 business day
[Component][Failure][Signal][Scope][Mitigation][Time]

9.2 Security, privacy and legal questions

Threat or dutyControl
Server-side request forgery through crafted links (internal IP ranges, metadata endpoints)Resolve then block private, loopback and link-local addresses; fetch from an isolated network
Malicious content (parser exploits, decompression bombs)Size limits before and after decompression, sandboxed parser, timeouts
Personal data in crawled pagesPurpose limitation, retention limits and deletion on request, reviewed with privacy counsel
Copyright and terms of serviceLegal review of the crawl purpose and reuse of stored content before launch
Impersonation of our crawler by othersPublish verification method (reverse DNS or published IP ranges) on the crawler page
[Threat][Control]

Questions to answer with legal and privacy reviewers (not legal advice): Which jurisdictions' data protection laws apply to the pages we store? Does the purpose (search, archive, AI training) require an opt-out mechanism beyond robots.txt? How long may raw copies be kept?

9.3 Observability

SignalMetric or logAlert threshold
ThroughputSuccessful fetches per hourBelow 80% of plan for 1 h
PolitenessMax concurrent connections per hostAny value above 1
Error mixShare of 4xx, 5xx, timeouts5xx share doubling vs. 7-day baseline
Duplicate wasteExact plus near-duplicate shareAbove 5%
Frontier healthReady hosts in the heapBelow 3 x fetch slots
ComplaintsTickets per weekAny unanswered after 1 business day

9.4 Cost estimate

ItemUnit costQuantityMonthly cost
Crawl nodes (fetch, frontier, seen set)[$/node-month]Example: 8[$]
Bandwidth[$/TB]Example: about 120 TB transferred per month (1 billion x 100 KB x 1.2)[$]
Object storage[$/TB-month]Example: 225 TB at steady state[$]
Key-value store for URL state[$/month][Nodes][$]
Total[$]

10. Trade-offs and alternatives

DecisionOptionsChosenWhyWhat we give up
PartitioningBy URL hash; by host hashBy host hashPoliteness without coordination; local links stay localUneven load when one host is huge
URL-seenBloom only; exact in memory; exact on disk with batchingBloom plus batched exact disk setNo silent loss, bounded memoryMinutes of delay before new URLs enter the frontier
PolitenessFixed delay; adaptiveAdaptive with backoffFair to slow servers, fast on fast onesHarder to predict per-host throughput
RenderingRender all pages; HTML onlyHTML only now, render queue later10x to 100x cheaper per pageMisses content built by JavaScript
StorageExtracted text only; raw WARCRaw WARC plus textReprocessing without refetching4x more storage than text alone
What changes at 10x / 0.1x10x (10 billion pages a month, about 3 860 pages/s average): about 7 700 hosts in flight at peak, an 800 GB exact seen set and about 2.25 PB stored for 6 months with erasure coding, so more nodes, a dedicated URL-seen service and tiered storage; politeness still caps each host. 0.1x (100 million a month, about 39 pages/s): one or two nodes with an in-memory seen set (8 GB at 1 billion URLs) are enoughReview at each doubling of the targetHost diversity and the seen set grow first[Note]
[Decision][Options][Chosen][Why][Cost]

11. Delivery plan and risks

11.1 Milestones

MilestoneScopeExit criterionTarget date
M1Single-node crawler with frontier, robots, WARC output; crawler page publishedRFC 9309 test suite passes; 1 million pages without a complaintYYYY-MM-DD
M2Host-partitioned cluster, batched seen set100 million pages in 30 days; node crash drill passesYYYY-MM-DD
M3Content dedup and recrawl schedulerDuplicate waste under 5%; freshness target met for top 10 millionYYYY-MM-DD
M4Full rate, budgets and trap defences1 billion pages in 30 daysYYYY-MM-DD

11.2 Rollout and rollback

[Example: Raise the global fetch rate in steps of 2x per week while watching complaints and error mix. Any step can be undone by lowering the global rate limit; per-host blocks apply at once.]

11.3 Risks

IDRiskLikelihoodImpactMitigationOwner
R-01Example: IP ranges blocked by large hosting providers after complaintsMediumHighConservative delays, fast response to complaints, published verification[@name]
R-02Example: Legal challenge to storing or reusing contentLowHighLegal review before M1; retention and deletion process[@name]
R-03Example: Trap consumes a large share of the crawlMediumMediumDomain budgets and caps from M2[@name]
[R-nn][Risk][L / M / H][L / M / H][Mitigation][@name]

12. Appendices

12.1 Open questions

IDQuestionOwnerDue
OQ-01Example: Do we honour AI-specific opt-out signals beyond robots.txt, and which ones?[@name]YYYY-MM-DD
OQ-02Example: Which share of pages needs JavaScript rendering to be useful?[@name]YYYY-MM-DD
[OQ-nn][Question][@name]YYYY-MM-DD

12.2 Glossary

TermMeaning
FrontierThe set of URLs waiting to be fetched, with their order
PolitenessLimits on how often and how concurrently we contact one host
Back queueA queue that holds URLs of one host only
URL-seen testCheck whether a URL has been discovered before
SimhashFingerprint where similar documents get fingerprints that differ in few bits
WARCWeb ARChive file format for raw HTTP responses (WARC 1.1, ISO 28500:2017)
Crawler trapURL space that generates unlimited distinct URLs
[Term][Meaning]

12.3 References

ReferenceUse
RFC 9309, Robots Exclusion Protocol, Koster, Illyes, Zeller and Sassman, September 2022 (Standards Track)7.2
RFC 9110 HTTP SemanticsConditional requests, Retry-After, 4.2
Sitemaps XML format, sitemaps.orgLimits and hints in 7.5
Heydon and Najork, "Mercator: A scalable, extensible Web crawler", World Wide Web 2(4):219-229, 1999, doi:10.1023/A:10192131092747.1, 7.7
Najork and Heydon, "High-Performance Web Crawling", Compaq SRC Research Report 173, 26 September 2001Frontier details, delay factor, DNS, 7.7
Lee, Leonard, Wang and Loguinov, "IRLbot: Scaling to 6 billion pages and beyond", WWW 2008, doi:10.1145/1367497.1367556; extended in ACM TWEB 3(3), 2009, doi:10.1145/1541822.1541823DRUM, budgets, 7.6, 7.7
Manku, Jain and Das Sarma, "Detecting near-duplicates for web crawling", WWW 2007, doi:10.1145/1242572.1242592Simhash parameters in 7.4
Bloom, "Space/time trade-offs in hash coding with allowable errors", CACM 13(7):422-426, 1970, doi:10.1145/362686.362692Bloom filter in 3.5
IIPC, The WARC Format 1.1; ISO 28500:2017, ISO catalogueStorage format
Full-Text Search Engine System Design (system-design/design-full-text-search)Indexer that consumes the output
Job Scheduler System Design (system-design/design-job-scheduler)Recrawl scheduling patterns
Distributed Key-Value Store System Design (system-design/design-distributed-kv-store)URL state store
Back-of-Envelope Estimation and Capacity Model (system-design/back-of-envelope-estimation)Method for section 3

Standard and licence note

Based on the Robots Exclusion Protocol (RFC 9309, September 2022), HTTP Semantics (RFC 9110), the sitemaps.org protocol and the published crawler research cited in 12.3. RFC section numbers are cited and the rules are paraphrased; no specification or paper text was copied, and all capacity numbers are illustrative examples. ISO 28500:2017 (WARC) is a paid standard and is named only; official text: ISO, purchase or licensed access at https://www.iso.org/standard/68004.html (the IIPC publishes WARC 1.1 openly). Check the current versions before relying on them. This is not legal advice; check the current official text and a qualified professional. Original text written for this collection. Template licence: MIT.

Related templates