← Glossary / URL Frontier

What is URL Frontier?

URL frontier is the data structure at the heart of any crawler — the queue that holds discovered-but-not-yet-fetched URLs and determines what gets crawled next, in what order, and at what rate. A poorly designed frontier causes duplicate fetches, host hammering, priority inversion, and memory exhaustion; the frontier is where crawl efficiency is won or lost before a single request fires.

SchedulerPriority queuePolitenessDeduplicationInfrastructure
// 02 — definitions

The queue that
runs the crawl.

URL frontier design is the central engineering problem of large-scale crawling. Everything else — proxies, parsers, storage — is downstream of what the frontier decides to fetch and when.

Ask a DataFlirt engineer →

TL;DR

The URL frontier is a prioritized, deduplicated queue of URLs waiting to be fetched. It enforces per-host crawl delay, filters already-seen URLs, and balances concurrency across thousands of hosts simultaneously. At scale (100M+ URLs), naively holding the frontier in memory fails — production systems shard it to disk or distributed stores like Redis or Kafka, with a small in-memory front-buffer for the active fetch window.

01Definition & structure
A URL frontier has three layers working in tandem:
  • Prioritizer — assigns a score to each discovered URL based on importance, freshness, and depth; feeds URLs into per-host back-queues ordered by score
  • Per-host back-queues — one queue per hostname; enforces crawl delay by holding URLs until the host's slot opens
  • Front-buffer — a small in-memory pool of ready-to-fetch URLs selected from host queues whose delay has elapsed; workers pull directly from here
Deduplication sits upstream of all three: a URL that has been seen before — either already fetched or already in the frontier — never enters the back-queues. This architecture, described in the Mercator crawler paper (1999), remains the template for production systems today.
02How it works in practice
Link extraction pushes new URLs into the prioritizer. The prioritizer scores them, checks robots.txt, and routes them to the appropriate host queue. A scheduler thread continuously scans host queues, checks whether each host's crawl delay has elapsed, and — when a slot is open — moves the top-scored URL for that host into the front-buffer. Workers pull from the front-buffer and emit results back to the parser, which then generates more URLs. The loop is self-sustaining: a healthy frontier never runs dry and never builds an unmanageable backlog.
03Storage tiers at scale
A 10M-URL frontier fits in ~1.4 GB RAM — feasible. At 100M URLs it's 14 GB and competing with your fetch workers for memory. The standard pattern is three tiers:
  • In-memory front-buffer — 10K–100K URLs, direct worker access, sub-millisecond latency
  • Redis sorted sets — millions of URLs per host, fast enough for real-time scheduler access
  • Kafka / disk overflow — hundreds of millions of low-priority URLs, batch-promoted to Redis as the active frontier drains
Most teams start with pure Redis and only add Kafka when they hit its memory limits — usually around 50M unique URLs with metadata.
04How DataFlirt handles it
Our frontier is sharded by host hash across a Redis cluster, with Kafka as the overflow tier for large-scale discovery jobs. We run a canonical URL normalizer before every enqueue operation — this alone eliminates ~15–20% of duplicate entries that Bloom filtering would otherwise catch after the fact. Priority weights are pipeline-specific: price-feed pipelines weight recency at 0.7; catalog-coverage pipelines weight link-in count at 0.6. We monitor frontier depth per host in real time and alert when any single host exceeds 500K queued URLs — that pattern usually means a pagination trap or a redirect loop.
05The pagination trap
The most common frontier pathology on e-commerce targets is infinite pagination: a site generates ?page=1 through ?page=N dynamically, and N grows as the crawler scrolls. Without a URL pattern cap, the frontier will queue every pagination variant indefinitely. The fix is a combination of URL normalization (strip session tokens, collapse pagination parameters above a threshold) and a per-host depth limit on discovery. Missing this costs days of crawl time on URLs that contain no new product data.
// 03 — the math

How the frontier
prioritizes work.

Priority, politeness, and deduplication are the three competing constraints every frontier algorithm balances. These formulas are the knobs a crawler engineer actually tunes.

Priority score = P(u) = α·importance(u) + β·freshness(u)γ·depth(u)
Weights α, β, γ are tuned per pipeline. Freshness dominates for price feeds; importance for link graph crawls. Cho & Garcia-Molina, 2000
Frontier memory bound = Mfrontier = F · (avg_url_bytes + metadata_bytes)
A 10M-URL frontier with 100-byte URLs + 50-byte metadata = ~1.4 GB. 100M URLs → 14 GB: must shard to disk. Practical crawler design
Effective fetch rate = R = Nworkers · (1 / (Davg + Lavg))
D = mean crawl delay across active hosts, L = mean fetch latency. Frontier must supply URLs faster than R. Mercator design doc
// 04 — what the frontier looks like

A frontier tick,
from enqueue to dispatch.

Two operations happen every millisecond in a live frontier: URLs arrive from the parser and are classified, deduped, and scored; URLs depart to fetch workers when their host slot opens.

Redis sorted setBloom filter dedupper-host queue
edge.dataflirt.io — live
CAPTURED
// inbound — link extractor pushes discovered URL
url: "https://shop.example.com/products/88124"
bloom_check: MISS — not seen before
robots_allowed: true
priority_score: 0.74 // product page, high value
enqueued_to: "host:shop.example.com"

// outbound — scheduler pops next fetchable URL
host: "shop.example.com"
slot_open: true // last_fetch + crawl_delay elapsed
popped_url: "https://shop.example.com/products/88124"
dispatched_to: "worker_pool_14"

// post-fetch — frontier state update
bloom.add: "https://shop.example.com/products/88124"
host.next_allowed_at: now + 3.0s // slot locked
// 05 — failure modes

Where frontier design
breaks down.

Most crawler failures — missed pages, hammered hosts, ballooning memory, re-crawling the same URLs — trace back to frontier design decisions made too early and never revisited as scale grew.

TYPICAL FRONTIER SIZE  1M–500M URLs
DEDUP FALSE-POSITIVE RAT  ~0.001% (Bloom)
IN-MEMORY FRONT-BUFFER  10K–100K URLs
01

No per-host queues

host hammering · Single global queue sends burst traffic to popular hosts
02

In-memory-only frontier

memory exhaustion · Crashes at ~5M URLs on a 16 GB worker
03

No deduplication

re-fetch waste · Same URL fetched 10x from different link sources
04

FIFO without priority

priority inversion · High-value URLs buried under low-value discovery
05

No politeness floor

instant block · First-seen host hit at full concurrency immediately
// 06 — our frontier

Distributed, sharded,

with a Bloom layer in front.

Our frontier runs on a Redis cluster sharded by host hash, with a Kafka-backed overflow tier for frontiers exceeding 50M URLs. Deduplication is a two-layer Bloom filter (false-positive rate < 0.001%) with a canonical URL normalizer upstream — query param stripping, trailing-slash canonicalization, fragment removal. Priority scores are computed per-URL at enqueue time using a signal blend of page depth, link-in count, and last-modified recency.

Frontier node — live state snapshot

One shard of our frontier cluster processing a mid-size e-commerce target.

shard.host_count 4,821 active hosts
frontier.size 18.4M URLsdisk-backed
front_buffer 50K URLs · in-memory
dedup.bloom_size 512M bits0.001% FPR
dispatch_rate 2,200 URLs/son target
host_slots_locked 1,204 / 4,821awaiting delay
overflow.kafka idlehealthy

Stay ahead of the pipeline

Data engineering
intel, weekly.

Anti-bot shifts, scraping infrastructure updates, dataset delivery patterns, and business outcomes from our pipelines. Short, technical, no fluff.

// 07 — FAQ

Common
questions.

About URL frontier design, deduplication, prioritization, and how to scale a crawler without hammering targets or running out of memory.

Ask us directly →
What's the difference between a frontier and a simple URL queue? +
A queue is FIFO — first in, first out. A frontier adds priority ordering, per-host politeness enforcement, deduplication, and robots.txt filtering. A queue will hammer one host until it's exhausted; a frontier balances work across thousands of hosts simultaneously and honors crawl delay per host independently.
How does URL deduplication work at large scale? +
At 10M+ URLs, hash sets in memory become impractical. The standard solution is a Bloom filter — a probabilistic structure that answers "have I seen this URL?" with configurable false-positive rate (typically 0.001% at 512MB). False positives mean occasionally skipping a URL you haven't seen; false negatives are impossible. For critical pipelines, a secondary exact-match store (Redis SET or RocksDB) catches the rare misses.
What URL normalization should happen before enqueuing? +
At minimum: lowercase the scheme and host, strip fragment identifiers (#section), canonicalize trailing slashes, sort query parameters alphabetically, and decode percent-encoded characters that don't require encoding. Skipping these means the same product page with URLs like /p/123 and /p/123?ref=homepage both enter the frontier as distinct items.
How do you prioritize which URLs to crawl first? +
Priority signals vary by use case. For freshness-sensitive pipelines (price data), recency of last-known change dominates. For link-graph coverage, link-in count and domain authority are stronger signals. For product catalogs, page type (product detail vs. listing vs. pagination) determines priority. Most production systems blend 2–3 signals with tunable weights rather than optimizing for a single metric.
Can the URL frontier cause missed pages? +
Yes — in three ways. Bloom filter false positives skip URLs incorrectly identified as already seen. Priority starvation buries low-scored URLs that never get popped before the crawl ends. And host-queue overflow drops URLs when a single host generates more discovery than its queue capacity. All three require explicit monitoring — a crawl that "completed" may have simply exhausted its budget, not its frontier.
How do you handle a frontier that grows faster than you can fetch? +
First, accept that on large broad crawls, the frontier always grows faster than you fetch — that's normal. The response is budget management: cap the frontier size per host, drop low-priority URLs when the queue exceeds a threshold, and use a focused crawl strategy that limits discovery depth on less-relevant hosts. Uncapped frontiers will fill your disk and then your backlog will be unmanageable.
$ dataflirt scope --new-project --target=url-frontier READY

Tell us what
to extract.
We do the rest.

20-minute scoping call. Pilot dataset within the week. Production within two. Whether you need a one-off catalogue dump or a continuous feed across millions of records — we scope, build, and operate the pipeline.

hello@dataflirt.com  ·  Bengaluru  ·  IST  ·  typical reply < 4h