Security Notes
System Design

Design a Web Crawler

4 min read 7 sections

DifficultyHard | HelloInterview: problem breakdown


Problem Statement

Design a large-scale web crawler that systematically downloads and indexes web content. Used by search engines (Googlebot), SEO tools, archiving services (Wayback Machine), and security scanners.

๐Ÿ“–

Real-world: The original cautionary tale is the Morris Worm (1988) โ€” arguably the first internet "crawler" gone wrong: a bug in how it tracked already-visited hosts made it re-infect machines repeatedly, crippling ~10% of the internet and producing the first CFAA conviction. It's the perfect illustration of why this design's hard parts are politeness (don't hammer one domain โ€” respect robots.txt and rate-limit per host) and deduplication at scale (a Bloom filter for "have I seen this URL?", because tracking billions of URLs exactly is infeasible). Security angles worth raising: crawlers must avoid crawler traps (infinite calendars, dynamically generated link mazes), beware SSRF-style pitfalls (a malicious page linking to http://169.254.169.254/ or internal IPs โ€” your crawler shouldn't fetch cloud metadata or internal services), and handle that most of the modern web is hostile or adversarial (cloaking, spam farms). Note the same design powers security scanners โ€” a vuln scanner is a crawler with payloads.


Requirements

Functional

  • Crawl seed URLs and recursively follow links
  • Respect robots.txt (politeness)
  • Avoid re-crawling unchanged pages (freshness)
  • Store crawled content for downstream processing
  • Handle redirects, different MIME types, duplicate content

Non-Functional

  • Crawl 1B pages/month โ†’ ~400 pages/s
  • Crawl budget: don't overwhelm any single host (max 1 req/s per domain)
  • Detect and avoid infinite crawl loops
  • Scale horizontally across many crawler nodes

Core Design

URL Frontier (Priority Queue)

The URL frontier is the queue of URLs to crawl. It has two tiers:

Front queue

(priority): ordered by priority (importance of domain, freshness)

Back queue

(politeness): one queue per host, enforcing crawl delay

Scheduler logic:
  for each crawler worker:
    pick next available host queue that hasn't been polled in last N seconds
    dequeue one URL from that host's queue
    dispatch to crawler worker

This enforces one request per host per N seconds without blocking all workers.

Deduplication

Billions of URLs; many are equivalent or already crawled.

URL normalization

  • Remove default ports (http://example.com:80/ โ†’ http://example.com/)
  • Lowercase host
  • Remove #fragment (fragment is client-side only)
  • Sort query parameters consistently

Seen URL check (bloom filter):

python
bloom_filter.add(normalized_url)
if bloom_filter.contains(url): skip  # probably seen (false positives acceptable)
  • Bloom filter for 10B URLs: ~10 GB memory (acceptable)
  • False positive rate ~0.1% โ†’ occasionally re-crawl a URL (acceptable)

Content deduplication (SimHash):

  • After downloading, compute SimHash of content
  • Two pages with SimHash Hamming distance < 3 โ†’ near-duplicates (mirror content)
  • Store SimHash of each page; skip near-duplicates

robots.txt

Every crawler must respect robots.txt:

User-agent: *
Disallow: /admin/
Crawl-delay: 10

User-agent: Googlebot
Allow: /
  • Fetch and cache robots.txt per domain on first visit
  • Cache TTL: 24h (re-fetch regularly in case it changes)
  • Respect Crawl-delay directive

Architecture

Seed URLs โ†’ URL Frontier (Redis sorted set + per-domain queues)
                  โ†“
         Crawler Workers (auto-scaling)
                  โ†“
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚  DNS Resolver (cached, rate-limited)โ”‚
    โ”‚  HTTP Client (timeout, redirect cap)โ”‚
    โ”‚  robots.txt Cache                   โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ†“
         Raw Content Store (S3 / HDFS)
                  โ†“
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚  Link Extractor                โ”‚ โ†’ new URLs โ†’ URL Frontier
    โ”‚  Content Parser (HTML, PDF...) โ”‚ โ†’ Document Index (Elasticsearch)
    โ”‚  SimHash Dedup                 โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ†‘
    URL Metadata DB (Postgres):
      - last_crawled_at
      - content_hash
      - crawl_status
      - next_crawl_at

Recrawl Scheduling (Freshness)

Not all pages change at the same rate. Schedule recrawls based on change frequency:

  • News sites: every 15 minutes
  • Product pages: daily
  • Static documentation: weekly

Track last_modified header and ETag. Send If-Modified-Since / If-None-Match on recrawl โ†’ server returns 304 Not Modified if unchanged โ†’ skip processing.


Key Design Decisions

DecisionChoiceReason
URL dedupBloom filterMemory-efficient; false positive rate acceptable
Content dedupSimHashDetects near-duplicates; single-pass computation
URL prioritySorted set (Redis ZADD)O(log N) insert/extract; flexible priority
PolitenessPer-domain queue + delayAvoid overloading any single host
StorageS3 for raw HTMLCheap, durable, decoupled from processing
Crawl policyBFS with priority adjustmentsExplore breadth first; boost important domains

Security Considerations

ThreatMitigation
Crawler traps (infinite links)Max depth limit; max URLs per domain; detect URL patterns
Malicious redirects to internal IPs (SSRF)Block RFC 1918 IP ranges; validate resolved IP before connecting
Poisoned robots.txt (Disallow: /)Respect but audit; alert on suspiciously broad disallow
Zip bomb / gigantic responsesMax response size limit (e.g., 5MB); timeout on download
Malware in crawled contentDon't execute scripts; sandboxed rendering for JavaScript
Legal: crawling private contentHonor noindex meta tags; respect login-wall boundaries
Rate limiting by target sitesRespect Retry-After; respect Crawl-delay; don't try to bypass

Interview Tips

robots.txt politeness

always mention this first. Ignoring it is both technically wrong and legally problematic.

The deduplication problem has two parts

URL dedup (bloom filter) and content dedup (SimHash) โ€” distinguish them.

Crawler trap

(e.g., ?page=1&page=2&page=3...) โ€” set max URL depth and max URLs per domain.

SSRF via DNS rebinding

when a crawler resolves a hostname, an attacker's DNS can return an internal IP. Validate IP after DNS resolution, before connecting.