scrapfly/skills

scrapfly-crawler

Crawl entire websites using the Scrapfly Crawler API with the Python SDK

First seen Mar 14, 2026

Installation

$ npx skills add scrapfly/skills --skill scrapfly-crawler

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from scrapfly/skills · top by installs.

npx skills add scrapfly/skills

Browse all from scrapfly/skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 3
Default branch main
Open issues 0
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 11,075 B
  • docs SUMMARY.md 96 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 87 installs

SKILL.md

Scrapfly Crawler

Use the Scrapfly Crawler API via the Python SDK to schedule and manage site-wide crawl jobs with automatic link discovery, depth control, and structured data extraction.

When to use

  • Crawling entire websites or specific sections
  • Discovering all pages/URLs on a site
  • Collecting content from multiple pages in bulk
  • Extracting structured data at scale across a site
  • Downloading site archives (WARC/HAR format)
  • Building LLM.txt files from crawled documentation

Setup

pip install scrapfly-sdk

The API key must be provided via environment variable SCRAPFLYAPIKEY or passed directly to the client.

SDK Imports

from scrapfly import ScrapflyClient, CrawlerConfig, Crawl

Additional imports for webhooks:

from scrapfly import (
    webhook_from_payload,
    CrawlStartedWebhook,
    CrawlUrlDiscoveredWebhook,
    CrawlUrlFailedWebhook,
    CrawlCompletedWebhook,
)

CrawlerConfig Parameters

Parameter Type Default Description
url str required Starting URL for the crawl
page_limit int None Maximum number of pages to crawl
max_depth int None Maximum link traversal depth from start URL
max_duration int None Maximum crawl duration in seconds
exclude_paths list[str] None URL path patterns to skip (supports *, max 100). Mutually exclusive with includeonlypaths
includeonlypaths list[str] None Only crawl URLs matching these path patterns (supports *, max 100). Mutually exclusive with exclude_paths
ignorebasepath_restriction bool False Allow crawling any path on the same domain, not just the seed URL's base path
followexternallinks bool False Follow links to external domains
allowedexternaldomains list[str] None Whitelist of external domains when followexternallinks=True (supports *, max 250)
headers dict None Custom HTTP headers as JSON object
delay int None Delay between requests in milliseconds (0-15000)
user_agent str None Custom User-Agent string (ignored when asp=True)
max_concurrency int None Maximum concurrent crawl requests
rendering_delay int None Wait time in ms after page load before extraction (0-25000). 0 disables browser rendering
use_sitemaps bool False Discover URLs from sitemap.xml when available
respectrobotstxt bool False Respect robots.txt rules and Disallow directives
ignorenofollow bool False Ignore rel="nofollow" attributes on links
cache bool False Enable cache layer for crawled pages
cache_ttl int None Cache time-to-live in seconds (0-604800)
cache_clear bool False Force refresh of cached pages
content_formats list[str] None Content formats to extract: html, clean_html, markdown, text
extraction_rules dict None Custom extraction rules for structured data
asp bool False Enable Anti Scraping Protection with browser rendering
proxy_pool str None Proxy pool to use (e.g., publicresidentialpool)
country str None Proxy country selection (ISO code)
webhook_name str None Name of webhook configured in dashboard
webhook_events list[str] None Events to subscribe to (e.g., crawlerstarted, crawlerurlvisited, crawlerfinished)
maxapicredit int None Maximum API credits to spend on this crawl

Webhook Events

  • "crawler_started" - Crawler execution began
  • "crawlerurlvisited" - A URL was successfully crawled
  • "crawlerurlskipped" - URLs were skipped
  • "crawlerurldiscovered" - New URLs were discovered
  • "crawlerurlfailed" - A URL failed to crawl
  • "crawler_stopped" - Crawler stopped due to failure or limits
  • "crawler_cancelled" - Crawl was manually cancelled
  • "crawler_finished" - Crawler completed successfully

Examples

Quick start: crawl and get results

import os
from scrapfly import ScrapflyClient, CrawlerConfig, Crawl

client = ScrapflyClient(key=os.environ["SCRAPFLY_API_KEY"])

# Create, start, and wait for crawl in one chain
# 2. Create and run crawler
crawl = Crawl(
    client,
    CrawlerConfig(url='https://web-scraping.dev/products', page_limit=5)
).crawl().wait()

# 3. Get results
pages = crawl.warc().get_pages()

# 4. Process results
print(f"Crawled {len(pages)} pages:")
for page in pages:
    print(f"  • {page['url']} ({page['status_code']})")

# 5. Access specific URLs
html = crawl.read('https://web-scraping.dev/products')
if html:
    print(f"\nMain page is {len(html):,} bytes")

Low-level workflow: start, poll, download

import os
import time
from scrapfly import ScrapflyClient, CrawlerConfig

client = ScrapflyClient(key=os.environ["SCRAPFLY_API_KEY"])

config = CrawlerConfig(
    url='https://web-scraping.dev',
    page_limit=10,
    max_depth=2,
    content_formats=['html', 'markdown']
)

# 1. Start crawler
start_response = client.start_crawl(config)
print(f"Crawler started: {start_response.uuid}")

# 2. Poll for status
while True:
    status = client.get_crawl_status(start_response.uuid)
    print(f"Status: {status.status} - {status.progress_pct:.1f}%")
    print(f"Crawled: {status.urls_crawled}/{status.urls_discovered} pages")

    if status.is_complete:
        break
    elif status.is_failed:
        print("Crawl failed!")
        break

    time.sleep(5)

# 3. Download and process results
if status.is_complete:
    artifact = client.get_crawl_artifact(start_response.uuid)
    pages = artifact.get_pages()
    print(f"Downloaded {len(pages)} pages")

    for page in pages:
        print(f"  {page['url']}: {page['status_code']} ({len(page['content'])} bytes)")

    # Save to file
    artifact.save('crawl_results.warc.gz')

Crawl with path filtering

config = CrawlerConfig(
    url='https://web-scraping.dev/',
    page_limit=50,
    max_depth=5,
    include_only_paths=['*/product/*'],
    content_formats=['markdown', 'text'],
)
crawl = Crawl(client, config).crawl().wait()

Crawl with anti-bot bypass

config = CrawlerConfig(
    url='https://web-scraping.dev',
    page_limit=50,
    asp=True,
    content_formats=['html'],
)
crawl = Crawl(client, config).crawl().wait()

Crawl with extraction rules

config = CrawlerConfig(
    url='https://web-scraping.dev/products',
    page_limit=100,
    max_depth=3,
    include_only_paths=['/products/*'],
    extraction_rules={
        "/products/*": {
            "type": "model",
            "value": "product",
        },
    },
)
crawl = Crawl(client, config).crawl().wait()

Read content for specific URLs

# Read HTML (from WARC - fast)
content = crawl.read('https://web-scraping.dev/product/1')
if content:
    print(f"URL: {content.url}")
    print(f"Status: {content.status_code}")
    print(f"Duration: {content.duration}s")
    print(content.content)

# Read markdown (from contents API)
content = crawl.read('https://web-scraping.dev/product/1', format='markdown')
if content:
    print(content.content)

Iterate URLs matching a pattern

for content in crawl.read_iter(pattern="*/products?page=*", format="markdown"):
    print(f"{content.url}: {len(content.content)} chars")

Batch content retrieval

# Get markdown for multiple URLs in a single API call (max 100 per request)
urls = ['https://web-scraping.dev/product/1', 'https://web-scraping.dev/product/2']
contents = crawl.read_batch(urls, formats=['markdown'])

for url, formats_dict in contents.items():
    markdown = formats_dict.get('markdown', '')
    print(f"{url}: {len(markdown)} chars")

Download WARC/HAR archive

# WARC format (default)
artifact = crawl.warc()
artifact.save('crawl_results.warc.gz')

# HAR format
artifact = crawl.har()
artifact.save('crawl_results.har')

# Iterate through records
for record in artifact.iter_responses():
    print(f"{record.url}: {record.status_code}")

Build LLM.txt from crawled documentation

import os
from scrapfly import ScrapflyClient, CrawlerConfig, Crawl

client = ScrapflyClient(key=os.environ["SCRAPFLY_API_KEY"])

config = CrawlerConfig(
    url='https://web-scraping.dev/',
    include_only_paths=['/docs', '/docs/*'], # only allow doc resources
    page_limit=50,
    max_depth=5,
    follow_external_links=False,
    content_formats=['markdown'],
)

crawl = Crawl(client, config).crawl().wait(poll_interval=5, verbose=True)

# Get URLs from WARC
warc_artifact = crawl.warc()
all_urls = [
    record.url for record in warc_artifact.iter_responses()
    if record.status_code == 200
]

# Retrieve markdown content in batches
all_contents = {}
for i in range(0, len(all_urls), 100):
    batch_urls = all_urls[i:i + 100]
    batch_contents = crawl.read_batch(batch_urls, formats=['markdown'])
    all_contents.update(batch_contents)

# Build llms-full.txt
lines = ["# Documentation\n"]
for url, formats_dict in all_contents.items():
    markdown = formats_dict.get('markdown', '').strip()
    if markdown:
        lines.append(f"---\n\n### {url}\n\n{markdown}\n")

with open("llms-full.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(lines))

Crawl statistics

stats = crawl.stats()
print(f"URLs discovered: {stats['urls_discovered']}")
print(f"URLs crawled: {stats['urls_crawled']}")
print(f"Progress: {stats['progress_pct']:.1f}%")

Key SDK Classes

Class Description
ScrapflyClient Main client - handles auth and API calls
CrawlerConfig Crawl job configuration
Crawl High-level crawl lifecycle manager (start, wait, read)
CrawlerStartResponse Response from client.start_crawl()
CrawlerStatusResponse Response from client.getcrawlstatus() - has iscomplete, isfailed, progress_pct
CrawlerArtifactResponse Response from client.getcrawlartifact() - has getpages(), iterresponses(), save()
CrawlContent Content for a single URL - has url, content, status_code, duration

Important Notes

  • Use page_limit to control credit spend on large sites
  • Use includeonlypaths and exclude_paths to focus crawls on relevant sections
  • excludepaths and includeonly_paths are mutually exclusive
  • Crawl jobs are asynchronous - use Crawl.crawl().wait() for simple workflows or poll with client.getcrawlstatus() for more control
  • WARC/HAR artifacts are available for offline processing via crawl.warc() / crawl.har()
  • read_batch() supports up to 100 URLs per request for efficient bulk content retrieval
  • Webhook signatures should be verified for security in production
  • followexternallinks should be used carefully to avoid crawling the entire web