Prompt
How do I set up a scheduled crawl tool for tracking broken outbound links across thousands of editorial pages?
Latest observation
To set up a scheduled crawl tool for tracking broken outbound links across thousands of editorial pages, you want a pipeline that is:
- Discovering URLs to scan
- Crawling pages efficiently
- Extracting outbound links
- Checking link health
- Scheduling recurring runs
- Reporting and alerting on changes
Here’s a practical blueprint.
1) Define the scope
Decide upfront:
- Which pages to crawl
- Sitemap URLs
- CMS export
- Database of editorial pages
- Seed list + internal discovery
- Which links count as outbound
- Only external domains?
- Mailto/tel ignored?
- Social links excluded?
- What counts as broken
- HTTP 4xx/5xx
- DNS failure
- Timeout
- Soft 404s
- Redirect chains ending in error
- How often to run
- Daily, weekly, hourly, per publish event
For editorial sites, a common setup is:
- Crawl all editorial pages nightly
- Recheck only pages changed in the last 24h more frequently
- Revalidate previously broken links separately
2) Choose an architecture
A scalable pattern:
Components
- Scheduler: cron, Airflow, Celery beat, Cloud Scheduler, etc.
- Crawler workers: fetch pages and extract links
- Link checker workers: validate outbound URLs
- Storage: database for results/history
- Notification layer: email/Slack/teams
- Dashboard: view failures, trends, and ownership
Recommended data flow
- Scheduler enqueues page URLs
- Crawler fetches page HTML
- Extract outbound links from DOM
- Deduplicate links
- Send outbound URLs to checker queue
- Checker requests each target URL
- Persist status/results
- Alert if threshold exceeded or new failures appear
3) Use a queue-based design for scale
For thousands of pages, avoid a single sequential script.
Why queues help
- Parallelize across workers
- Retry failures cleanly
- Rate-limit outbound requests
- Avoid overloading target sites
- Separate page crawling from link checking
Typical queue breakdown
- Page crawl queue: editorial page URLs
- Link check queue: outbound URLs
- Dead-letter queue: items that repeatedly fail
4) Crawl pages and extract outbound links
When fetching each editorial page:
Fetch safely
- Set timeouts
- Follow redirects
- Identify yourself with a user agent
- Respect robots.txt if required by your policy
Extract links
From HTML:
<a href="">hrefin canonical/alternate tags if relevant- maybe embedded rich content if your pages generate links dynamically
Filter
Exclude:
- internal links
- anchors (
#section) mailto:tel:- javascript URLs
- tracking pixels or non-HTTP resources, unless needed
Example filter logic
Treat as outbound if:
- URL scheme is
httporhttps - Domain is not in your allowed internal domain list
5) Check outbound links efficiently
For each outbound URL:
Preferred checks
- Try
HEAD - Fall back to
GETif:- HEAD not allowed
- status is suspicious
- site blocks HEAD
Record:
- final URL after redirects
- status code
- response time
- error type
- redirect depth
- timestamp
Handle edge cases
- 403/429 may be anti-bot, not broken
- Some sites block automated requests
- Some servers return 200 for soft-404 pages
- Timeouts and DNS errors should be treated separately from HTTP errors
A good strategy is to categorize:
- Broken
- Warning
- Blocked/unknown
- Healthy
6) Store results in a database
Use a relational DB or warehouse. Suggested tables:
pages
idurllast_crawled_atcontent_hashstatus
outbound_links
idsource_page_idtarget_urlnormalized_urlfirst_seen_atlast_seen_at
link_checks
idoutbound_link_idchecked_athttp_statusfinal_urllatency_mserror_typeis_brokennotes
alerts
idtypecreated_atseveritydetails
This gives you history and trend tracking instead of just a latest snapshot.
7) Schedule runs
Pick a scheduler based on your environment:
Simple options
- cron on a server
- GitHub Actions for smaller jobs
- Cloud Scheduler + Cloud Run
- AWS EventBridge + Lambda/ECS
- Airflow if workflows are complex
Example scheduling strategy
- Nightly full crawl of all editorial pages
- Hourly crawl for newly published/updated pages
- Daily recheck of known broken outbound links
- Weekly cleanup for stale links and duplicates
8) Add normalization and deduplication
Normalize URLs before storing/checking:
- remove fragments (
#...) - standardize scheme where appropriate
- lowercase hostname
- strip tracking query params if desired
- resolve relative URLs
Deduplicate at two levels:
- Same outbound URL appearing on many pages
- Same page being crawled multiple times
This can massively reduce load.
9) Report meaningful results
Don’t just report “broken links.” Give editors useful context:
- Source page title
- Source page URL
- Broken outbound URL
- HTTP status or error
- First seen / last seen
- Number of pages affected
- Severity
- Suggested action
Useful summaries
- New broken links since last run
- Broken links by section/author/category
- Pages with the most broken outbound links
- Links broken across multiple pages
10) Alerting rules
Avoid alert spam. Trigger alerts on:
- New broken link discovered
- Broken link appearing on multiple pages
- Same link broken for N consecutive runs
- Spike in broken links after a deployment
Alert destinations:
- Slack
- MS Teams
- Jira ticket creation
11) Respect performance and politeness
Especially when checking thousands of pages/links:
- Use concurrency, but cap it
- Rate-limit requests per domain
- Cache known results
- Honor retry-after headers
- Use exponential backoff
- Consider robots.txt/policy constraints
A practical setup might be:
- 10–50 concurrent page fetches
- 20–100 concurrent link checks
- Per-domain concurrency cap of 1–3
12) Tooling options
Build your own
Good if you need custom logic and tight integration.
Common stack:
- Python
- Scrapy for crawling
- Requests/httpx for checking
- Celery/RQ for queues
- PostgreSQL for storage
- Node.js
- Playwright/Puppeteer for dynamic pages
- BullMQ for queues
- Go
- High performance for checking at scale
Use existing tools
- Screaming Frog SEO Spider with scheduled crawls
- Sitebulb
- Ahrefs/Site audits
- Custom enterprise link checkers
These are quicker to start but may be harder to customize for editorial workflows and ownership mapping.
13) Recommended implementation pattern
If you want a robust custom setup:
Stack example
- Crawler: Scrapy or Playwright
- Queue: Celery + Redis
- Storage: PostgreSQL
- Scheduler: cron or Airflow
- Alerts: Slack webhook + email
- Dashboard: Metabase / Grafana / custom admin page
Workflow
- Nightly scheduler enqueues page URLs from sitemap/CMS
- Workers crawl pages and store outbound links
- Checker workers validate unique outbound URLs
- Results stored and compared to previous run
- Alerts sent for new regressions
- Dashboard shows trends and ownership
14) Minimal pseudo-workflow
for page in editorial_pages:
html = fetch(page)
links = extract_outbound_links(html)
for link in unique(links):
status = check_url(link)
save_result(page, link, status)
if broken_links_new_or_changed:
notify_slack()
In production, each step should run asynchronously with retries and persistence.
15) If you want the fastest path
If you need something working quickly:
- Export editorial URLs from your CMS or sitemap
- Run a scheduled Python job nightly
- Parse pages with BeautifulSoup/lxml
- Check outbound URLs with
httpx - Write results to PostgreSQL or CSV
- Send a Slack summary
- Add dedupe + retries + concurrency next
If you want, I can also give you:
- a reference architecture diagram
- a Python example using Scrapy + Celery
- a Node.js/Playwright version
- or a database schema and cron setup for this exact use case.
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.