[
  {
    "url": "https://docs.crawl4ai.com",
    "title": "🚀🤖 Crawl4AI: Open-Source LLM-Friendly Web Crawler & Scraper",
    "type": "overview",
    "summary": "Crawl4AI is an open-source, LLM-friendly web crawler and scraper that produces clean Markdown, supports structured extraction, advanced browser control, and high-performance parallel crawling. This…",
    "sections": [
      {
        "heading": "🚀 Crawl4AI Cloud API — Closed Beta (Launching Soon)",
        "content": "Reliable, large-scale web extraction, now built to be **drastically more cost-effective** than any of the existing solutions.\n\n👉 **Apply [here](https://forms.gle/E9MyPaNXACnAMaqG7) for early…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Crawl4AI: Open-Source LLM-Friendly Web Crawler & Scraper",
        "content": "Crawl4AI is the #1 trending GitHub repository, actively maintained by a vibrant community. It delivers blazing-fast, AI-ready web crawling tailored for large language models, AI agents, and data…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🆕 AI Assistant Skill Now Available!",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🤖 Crawl4AI Skill for Claude & AI Assistants",
        "content": "Supercharge your AI coding assistant with complete Crawl4AI knowledge! Download our comprehensive skill package that includes:\n\n- 📚 Complete SDK reference (23K+ words)\n- 🚀 Ready-to-use extraction…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🎯 New: Adaptive Web Crawling",
        "content": "Crawl4AI now features intelligent adaptive crawling that knows when to stop! Using advanced information foraging algorithms, it determines when sufficient information has been gathered to answer your…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "Here's a quick example to show you how easy it is to use Crawl4AI with its asynchronous capabilities:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    # Create an instance of AsyncWebCrawler\n    async with AsyncWebCrawler() as crawler:\n        # Run the crawler on a URL…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Video Tutorial",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What Does Crawl4AI Do?",
        "content": "Crawl4AI is a feature-rich crawler and scraper that aims to:\n\n1. **Generate Clean Markdown**: Perfect for RAG pipelines or direct ingestion into LLMs.\n2. **Structured Extraction**: Parse repeated…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Documentation Structure",
        "content": "To help you get started, we’ve organized our docs into clear sections:\n\n- **Setup & Installation**: Basic instructions to install Crawl4AI via pip or Docker.\n- **Quick Start**: A hands-on…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How You Can Support",
        "content": "- **Star & Fork**: If you find Crawl4AI helpful, star the repo on GitHub or fork it to add your own features.\n- **File Issues**: Encounter a bug or missing feature? Let us know by filing an issue, so…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Links",
        "content": "- **[GitHub Repo](https://github.com/unclecode/crawl4ai)**\n- **[Installation Guide](core/installation/)**\n- **[Quick Start](core/quickstart/)**\n- **[API Reference](api/async-webcrawler/)**\n-…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawler",
      "scraper",
      "LLM",
      "web crawling",
      "open-source",
      "Python",
      "AsyncWebCrawler",
      "Markdown",
      "extraction",
      "AI",
      "RAG",
      "adaptive crawling",
      "documentation"
    ],
    "prerequisites": [],
    "_content_hash": "5ab29c50b5f0b2b408fc95ef0b33dc777bcc6789aa2ccb9b7f220ac50a6cda56",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/",
    "title": "Home - Crawl4AI Documentation (v0.9.x)",
    "type": "overview",
    "summary": "Landing page and overview for Crawl4AI, an open-source, LLM-friendly web crawler and scraper. It introduces the project's mission, key capabilities, quick-start example, documentation structure, and…",
    "sections": [
      {
        "heading": "🚀🤖 Crawl4AI: Open-Source LLM-Friendly Web Crawler & Scraper",
        "content": "🚀 Crawl4AI Cloud API — Closed Beta (Launching Soon)\n\nReliable, large-scale web extraction, now built to be drastically more cost-effective than any of the existing solutions.\n\n👉 Apply here for early…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🆕 AI Assistant Skill Now Available!",
        "content": "🤖 Crawl4AI Skill for Claude & AI Assistants\n\nSupercharge your AI coding assistant with complete Crawl4AI knowledge! Download our comprehensive skill package that includes:\n\n- 📚 Complete SDK reference…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🎯 New: Adaptive Web Crawling",
        "content": "Crawl4AI now features intelligent adaptive crawling that knows when to stop! Using advanced information foraging algorithms, it determines when sufficient information has been gathered to answer your…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "Here's a quick example to show you how easy it is to use Crawl4AI with its asynchronous capabilities:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    # Create an instance of AsyncWebCrawler\n    async with AsyncWebCrawler() as crawler:\n        # Run the crawler on a URL…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Video Tutorial",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What Does Crawl4AI Do?",
        "content": "Crawl4AI is a feature-rich crawler and scraper that aims to:\n\n1. Generate Clean Markdown: Perfect for RAG pipelines or direct ingestion into LLMs.\n2. Structured Extraction: Parse repeated patterns…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Documentation Structure",
        "content": "To help you get started, we’ve organized our docs into clear sections:\n\n- Setup & Installation — Basic instructions to install Crawl4AI via pip or Docker.\n- Quick Start — A hands-on introduction…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How You Can Support",
        "content": "- Star & Fork: If you find Crawl4AI helpful, star the repo on GitHub or fork it to add your own features.\n- File Issues: Encounter a bug or missing feature? Let us know by filing an issue, so we can…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Links",
        "content": "- GitHub Repo\n- Installation Guide\n- Quick Start\n- API Reference\n- Changelog\n\nThank you for joining me on this journey. Let’s keep building an open, democratic approach to data extraction and AI…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "web crawler",
      "scraper",
      "LLM",
      "open source",
      "Python",
      "async",
      "AI agents",
      "RAG",
      "documentation"
    ],
    "prerequisites": [],
    "_content_hash": "5ab29c50b5f0b2b408fc95ef0b33dc777bcc6789aa2ccb9b7f220ac50a6cda56",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/CONTRIBUTING/",
    "title": "Contributing Guide - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "Contribution guide for Crawl4AI explaining the branching strategy, contributor workflow, release process, and best practices for submitting pull requests.",
    "sections": [
      {
        "heading": "Introduction",
        "content": "Welcome to the Crawl4AI project! As an open-source library for web crawling and AI integration, we value contributions from the community. This guide explains our branching strategy, how to…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Core Branches",
        "content": "- **main** : The stable branch containing production-ready code. It's always identical to the latest released version and is tagged for releases. Do not submit PRs directly here.\n\n- **develop** : The…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Contributor Workflow",
        "content": "We encourage contributions of all kinds: bug fixes, new features, documentation improvements, tests, or even Docker enhancements. Follow these steps to contribute:\n\n- **Fork the Repository** : Create…",
        "code_blocks": [
          {
            "language": "shell",
            "code": "git checkout develop\ngit checkout -b feature/your-feature-name  # Or bugfix/your-bugfix-name",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Lead Maintainer's Workflow (For Reference)",
        "content": "- The lead maintainer (Unclecode) uses the `next` branch for isolated experimental work.\n\n- Features from `next` are periodically merged into `develop` (via rebase and merge) to keep everything in…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Release Process (High-Level Overview)",
        "content": "Releases happen bi-weekly to ship improvements regularly. As a contributor, your merged changes in `develop` will be included in the next release unless specified otherwise. Here's a summary of what…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Benefits of This Approach",
        "content": "- **Stability** : `main` is always reliable for users.\n\n- **Collaboration** : Fixed PR target (`develop`) makes contributing straightforward.\n\n- **Isolation** : Experimental work in `next` doesn't…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Checklist for Contributors",
        "content": "Before submitting a PR:\n\n- [ ]  Based on and targeting `develop`.\n\n- [ ]  Tests pass (`pytest`).\n\n- [ ]  Docs updated if needed (e.g., version refs in mkdocs.yml, Docker files).\n\n- [ ]  No breaking…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Common Issues",
        "content": "- **Merge Conflicts** : Rebase your branch on latest `develop` before PR.\n\n- **Docker Builds** : Test multi-arch (amd64/arm64) locally if changing Dockerfile.\n\n- **Version Consistency** : Ensure any…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Communication",
        "content": "- Open issues for discussions or bugs.\n\n- Join our Discord (link in README) for real-time help.\n\n- After releases, announcements go to GitHub, Discord, and social media.\n\nThanks for contributing to…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "open-source",
      "contributing",
      "GitFlow",
      "GitHub",
      "Docker",
      "semantic versioning",
      "documentation"
    ],
    "prerequisites": [],
    "_content_hash": "8f0f3ec4efafcab7f0c51ce4407652c13de60ea90e78e00b7abc167c28ff9b47",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/adaptive-strategies/",
    "title": "Adaptive Strategies - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This guide covers advanced adaptive strategies in Crawl4AI, including the three-layer scoring system, link ranking algorithm, domain-specific configurations, performance optimization, debugging,…",
    "sections": [
      {
        "heading": "Overview",
        "content": "While the default adaptive crawling configuration works well for most use cases, understanding the underlying strategies and scoring mechanisms allows you to fine-tune the crawler for specific…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "The Three-Layer Scoring System",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Coverage Score",
        "content": "Coverage measures how comprehensively your knowledge base covers the query terms and related concepts.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Mathematical Foundation",
        "content": "",
        "code_blocks": [
          {
            "language": "text",
            "code": "Coverage(K, Q) = Σ(t ∈ Q) score(t, K) / |Q|\n\nwhere score(t, K) = doc_coverage(t) × (1 + freq_boost(t))",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Components",
        "content": "- **Document Coverage**: Percentage of documents containing the term\n- **Frequency Boost**: Logarithmic bonus for term frequency\n- **Query Decomposition**: Handles multi-word queries intelligently",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Tuning Coverage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# For technical documentation with specific terminology\nconfig = AdaptiveConfig(\n    confidence_threshold=0.85,  # Require high coverage\n    top_k_links=5              # Cast wider net\n)\n\n# For…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Consistency Score",
        "content": "Consistency evaluates whether the information across pages is coherent and non-contradictory.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How It Works",
        "content": "- Extracts key statements from each document\n- Compares statements across documents\n- Measures agreement vs. contradiction\n- Returns normalized score (0-1)",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Practical Impact",
        "content": "- **High consistency (>0.8)**: Information is reliable and coherent\n- **Medium consistency (0.5-0.8)**: Some variation, but generally aligned\n- **Low consistency (<0.5)**: Conflicting information,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3. Saturation Score",
        "content": "Saturation detects when new pages stop providing novel information.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Detection Algorithm",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Tracks new unique terms per page\nnew_terms_page_1 = 50\nnew_terms_page_2 = 30  # 60% of first\nnew_terms_page_3 = 15  # 50% of second\nnew_terms_page_4 = 5   # 33% of third\n# Saturation detected:…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = AdaptiveConfig(\n    min_gain_threshold=0.1  # Stop if <10% new information\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Link Ranking Algorithm",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Expected Information Gain",
        "content": "Each uncrawled link is scored based on:",
        "code_blocks": [
          {
            "language": "text",
            "code": "ExpectedGain(link) = Relevance × Novelty × Authority",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1. Relevance Scoring",
        "content": "Uses BM25 algorithm on link preview text:\n\nFactors:\n- Term frequency in preview\n- Inverse document frequency\n- Preview length normalization",
        "code_blocks": [
          {
            "language": "text",
            "code": "relevance = BM25(link.preview_text, query)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Novelty Estimation",
        "content": "Measures how different the link appears from already-crawled content:\n\nPrevents crawling duplicate or highly similar pages.",
        "code_blocks": [
          {
            "language": "text",
            "code": "novelty = 1 - max_similarity(preview, knowledge_base)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Authority Calculation",
        "content": "URL structure and domain analysis:\n\nFactors:\n- Domain reputation\n- URL depth (fewer slashes = higher authority)\n- Clean URL structure",
        "code_blocks": [
          {
            "language": "text",
            "code": "authority = f(domain_rank, url_depth, url_structure)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Domain-Specific Configurations",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Technical Documentation",
        "content": "Rationale:\n- High threshold ensures comprehensive coverage\n- Lower gain threshold captures edge cases\n- Moderate link following for depth",
        "code_blocks": [
          {
            "language": "python",
            "code": "tech_doc_config = AdaptiveConfig(\n    confidence_threshold=0.85,\n    max_pages=30,\n    top_k_links=3,\n    min_gain_threshold=0.05  # Keep crawling for small gains\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "News & Articles",
        "content": "Rationale:\n- Lower threshold (articles often repeat information)\n- Higher gain threshold (avoid duplicate stories)\n- More links per page (explore different perspectives)",
        "code_blocks": [
          {
            "language": "python",
            "code": "news_config = AdaptiveConfig(\n    confidence_threshold=0.6,\n    max_pages=10,\n    top_k_links=5,\n    min_gain_threshold=0.15  # Stop quickly on repetition\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "E-commerce",
        "content": "Rationale:\n- Balanced threshold for product variations\n- Focused link following (avoid infinite products)\n- Standard gain threshold",
        "code_blocks": [
          {
            "language": "python",
            "code": "ecommerce_config = AdaptiveConfig(\n    confidence_threshold=0.7,\n    max_pages=20,\n    top_k_links=2,\n    min_gain_threshold=0.1\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Research & Academic",
        "content": "Rationale:\n- Very high threshold for completeness\n- Many pages allowed for thorough research\n- Very low gain threshold to capture references",
        "code_blocks": [
          {
            "language": "python",
            "code": "research_config = AdaptiveConfig(\n    confidence_threshold=0.9,\n    max_pages=50,\n    top_k_links=4,\n    min_gain_threshold=0.02  # Very low - capture citations\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Optimization",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Memory Management",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# For large crawls, use streaming\nconfig = AdaptiveConfig(\n    max_pages=100,\n    save_state=True,\n    state_path=\"large_crawl.json\"\n)\n\n# Periodically clean state\nif len(state.knowledge_base) >…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Parallel Processing",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Use multiple start points\nstart_urls = [\n    \"https://docs.example.com/intro\",\n    \"https://docs.example.com/api\",\n    \"https://docs.example.com/guides\"\n]\n\n# Crawl in parallel\ntasks = […",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Debugging & Analysis",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Enable Debugging",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import logging\n\nlogging.basicConfig(level=logging.DEBUG)\nadaptive = AdaptiveCrawler(crawler, config, verbose=True)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Analyze Crawl Patterns",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# After crawling\nstate = await adaptive.digest(start_url, query)\n\n# Analyze link selection\nprint(\"Link selection order:\")\nfor i, url in enumerate(state.crawl_order):\n    print(f\"{i+1}. {url}\")\n\n#…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Export for Analysis",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Export detailed metrics\nimport json\n\nmetrics = {\n    \"query\": query,\n    \"total_pages\": len(state.crawled_urls),\n    \"confidence\": adaptive.confidence,\n    \"coverage_stats\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Custom Strategies",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Implementing a Custom Strategy",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.adaptive_crawler import CrawlStrategy\n\nclass DomainSpecificStrategy(CrawlStrategy):\n    def calculate_coverage(self, state: CrawlState) -> float:\n        # Custom coverage calculation…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining Strategies",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "class HybridStrategy(CrawlStrategy):\n    def __init__(self):\n        self.strategies = [\n            TechnicalDocStrategy(),\n            SemanticSimilarityStrategy(),…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Start Conservative",
        "content": "Begin with default settings and adjust based on results:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Start with defaults\nresult = await adaptive.digest(url, query)\n\n# Analyze and adjust\nif adaptive.confidence < 0.7:\n    config.max_pages += 10\n    config.confidence_threshold -= 0.1",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Monitor Resource Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import psutil\n\n# Check memory before large crawls\nmemory_percent = psutil.virtual_memory().percent\nif memory_percent > 80:\n    config.max_pages = min(config.max_pages, 20)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Use Domain Knowledge",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# For API documentation\nif \"api\" in start_url:\n    config.top_k_links = 2  # APIs have clear structure\n\n# For blogs\nif \"blog\" in start_url:\n    config.min_gain_threshold = 0.2  # Avoid similar posts",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Validate Results",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Always validate the knowledge base\nrelevant_content = adaptive.get_relevant_content(top_k=10)\n\n# Check coverage\nquery_terms = set(query.lower().split())\ncovered_terms = set()\n\nfor doc in…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Next Steps",
        "content": "Explore [Custom Strategy Implementation](../tutorials/custom-adaptive-strategies.md)\nLearn about [Knowledge Base Management](../tutorials/knowledge-base-management.md)\nSee [Performance…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "adaptive",
      "scoring",
      "coverage",
      "consistency",
      "saturation",
      "link ranking",
      "BM25",
      "domain-specific",
      "performance",
      "debugging",
      "custom strategies",
      "best practices",
      "Crawl4AI"
    ],
    "prerequisites": [],
    "_content_hash": "a6319cb032b0b93217b594fd31bca2e6fb95064ac47b5ef17ef6e6e3408e8e10",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/advanced-features/",
    "title": "Overview of Some Important Advanced Features",
    "type": "guide",
    "summary": "A guide to advanced Crawl4AI features including proxy usage, PDF/screenshot capture, SSL certificates, custom headers, session persistence, robots.txt compliance, and anti-bot techniques.",
    "sections": [
      {
        "heading": "Overview of Some Important Advanced Features",
        "content": "Crawl4AI offers multiple power-user features that go beyond simple crawling. This tutorial covers:\n\n1. **Proxy Usage**\n\n2. **Capturing PDFs & Screenshots**\n\n3. **Handling SSL Certificates**\n\n4.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Proxy Usage",
        "content": "If you need to route your crawl traffic through a proxy—whether for IP rotation, geo-testing, or privacy—Crawl4AI supports it via `BrowserConfig.proxy_config`.\n\n**Key Points**\n\n- **`proxy_config`**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    browser_cfg = BrowserConfig(\n        proxy_config={\n            \"server\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Capturing PDFs & Screenshots",
        "content": "Sometimes you need a visual record of a page or a PDF “printout.” Crawl4AI can do both in one pass:\n\n**Why PDF + Screenshot?**\n\n- Large or complex pages can be slow or error-prone with “traditional”…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import os, asyncio\nfrom base64 import b64decode\nfrom crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig\n\nasync def main():\n    run_config = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Handling SSL Certificates",
        "content": "If you need to verify or export a site’s SSL certificate—for compliance, debugging, or data analysis—Crawl4AI can fetch it during the crawl:\n\n**Key Points**\n\n- **`fetch_ssl_certificate=True`**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio, os\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    tmp_dir = os.path.join(os.getcwd(), \"tmp\")\n    os.makedirs(tmp_dir, exist_ok=True)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Custom Headers",
        "content": "Sometimes you need to set custom headers (e.g., language preferences, authentication tokens, or specialized user-agent strings). You can do this in multiple ways:\n\n**Notes**\n\n- Some sites may react…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    # Option 1: Set headers at the crawler strategy level\n    crawler1 = AsyncWebCrawler(\n        # The underlying strategy can…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Session Persistence & Local Storage",
        "content": "Crawl4AI can preserve cookies and localStorage so you can continue where you left off—ideal for logging into sites or skipping repeated auth flows.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "5.1 `storage_state`",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    storage_dict = {\n        \"cookies\": [\n            {\n                \"name\": \"session\",\n                \"value\": \"abcd1234\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5.2 Exporting & Reusing State",
        "content": "You can sign in once, export the browser context, and reuse it later—without re-entering credentials.\n\n- **`await context.storage_state(path=\"my_storage.json\")`**: Exports cookies, localStorage, etc.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6. Robots.txt Compliance",
        "content": "Crawl4AI supports respecting robots.txt rules with efficient caching:\n\n**Key Points**\n\n- Robots.txt files are cached locally for efficiency\n\n- Cache is stored in…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Enable robots.txt checking in config\n    config = CrawlerRunConfig(\n        check_robots_txt=True  #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Putting It All Together",
        "content": "Here’s a snippet that combines multiple “advanced” features (proxy, PDF, screenshot, SSL, custom headers, and session reuse) into one run. Normally, you’d tailor each setting to your project’s needs.",
        "code_blocks": [
          {
            "language": "python",
            "code": "import os, asyncio\nfrom base64 import b64decode\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def main():\n    # 1. Browser config with proxy + headless…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Anti-Bot Features (Stealth Mode & Undetected Browser)",
        "content": "Crawl4AI provides two powerful features to bypass bot detection:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "7.1 Stealth Mode",
        "content": "Stealth mode uses playwright-stealth to modify browser fingerprints and behaviors. Enable it with a simple flag:\n\n**When to use**: Sites with basic bot detection (checking navigator.webdriver,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(\n    enable_stealth=True,  # Activates stealth mode\n    headless=False\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7.2 Undetected Browser",
        "content": "For advanced bot detection, use the undetected browser adapter:\n\n**When to use**: Sites with sophisticated bot detection (Cloudflare, DataDome, etc.)",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import UndetectedAdapter\nfrom crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy\n\n# Create undetected adapter\nadapter = UndetectedAdapter()\nstrategy =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7.3 Combining Both",
        "content": "For maximum evasion, combine stealth mode with undetected browser:",
        "code_blocks": [
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(\n    enable_stealth=True,  # Enable stealth\n    headless=False\n)\n\nadapter = UndetectedAdapter()  # Use undetected browser",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Choosing the Right Approach",
        "content": "| Detection Level | Recommended Approach |\n| --- | --- |\n| No protection | Regular browser |\n| Basic checks | Regular + Stealth mode |\n| Advanced protection | Undetected browser |\n| Maximum evasion |…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Conclusion & Next Steps",
        "content": "You've now explored several **advanced** features:\n\n- **Proxy Usage**\n\n- **PDF & Screenshot** capturing for large or critical pages\n\n- **SSL Certificate** retrieval & exporting\n\n- **Custom Headers**…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "proxy",
      "PDF",
      "screenshot",
      "SSL",
      "custom headers",
      "session persistence",
      "storage state",
      "robots.txt",
      "anti-bot",
      "stealth mode",
      "undetected browser"
    ],
    "prerequisites": [],
    "_content_hash": "301d3656906ec78dff2743e6608dace0a6bf490db4cdea00846115e9ddc46291",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/anti-bot-and-fallback/",
    "title": "Anti-Bot Detection & Fallback",
    "type": "guide",
    "summary": "Explains how Crawl4AI detects anti-bot blocks and describes the layered retry/fallback system using proxies, retries, and custom fetch functions to retrieve content from protected sites.",
    "sections": [
      {
        "heading": "How Detection Works",
        "content": "After each crawl attempt, Crawl4AI inspects the HTTP status code and HTML content for known anti-bot signals:\n\n- **HTTP 403/429** with short or empty response bodies\n- **Challenge pages** —…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Configuration Options",
        "content": "All anti-bot retry options live on `CrawlerRunConfig`:\n\n| Parameter | Type | Default | Description |\n| --- | --- | --- | --- |\n| `proxy_config` | `ProxyConfig`, `list[ProxyConfig]`, or `None` |…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Escalation Chain",
        "content": "Each retry round tries every proxy in `proxy_config` in order. If all rounds are exhausted and the page is still blocked, the fallback fetch function is called as a last resort.\n\nWorst-case attempts…",
        "code_blocks": [
          {
            "language": "text",
            "code": "For each round (1 + max_retries rounds):\n    1. Try proxy_config[0] (or direct if proxy_config is None)\n    2. If blocked → try proxy_config[1]\n    3. If blocked → try proxy_config[2]\n    4. ...…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Crawl Stats",
        "content": "Every crawl result includes a `crawl_stats` dict with detailed attempt tracking:",
        "code_blocks": [
          {
            "language": "python",
            "code": "result.crawl_stats = {\n    \"attempts\": 3,                    # total browser attempts made\n    \"retries\": 1,                     # retry rounds used (0 = succeeded first round)\n    \"proxies_used\": […",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Usage Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Simple Retry (No Proxy)",
        "content": "Retry the crawl up to 3 times when blocking is detected. Useful when blocks are intermittent or IP-based.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler\nfrom crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig\n\nasync with AsyncWebCrawler(config=BrowserConfig(headless=True)) as crawler:\n    result = await…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Single Proxy",
        "content": "Pass a single `ProxyConfig` — it's used on every attempt. Same behavior as always.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.async_configs import ProxyConfig\n\nconfig = CrawlerRunConfig(\n    max_retries=2,\n    proxy_config=ProxyConfig(\n        server=\"http://proxy.example.com:8080\",\n        username=\"user\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Direct-First, Then Proxies",
        "content": "Try without a proxy first, then escalate to proxies if blocked. Use `ProxyConfig.DIRECT` (or the string `\"direct\"`) in the list to represent a no-proxy attempt.\n\nWith this setup, each round tries…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    max_retries=1,\n    proxy_config=[\n        ProxyConfig.DIRECT,  # Try without proxy first\n        ProxyConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Proxy List (Escalation)",
        "content": "Pass a list of proxies. They're tried in order — first one that works wins. Within each retry round, the entire list is tried again.\n\nWith this setup, each round tries the datacenter proxy first,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    max_retries=1,\n    proxy_config=[\n        ProxyConfig(\n            server=\"http://datacenter-proxy.example.com:8080\",\n            username=\"user\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Fallback Fetch Function",
        "content": "When all browser-based attempts fail, call a custom async function as a last resort. This function receives the URL and must return raw HTML as a string. The returned HTML is processed through the…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import aiohttp\n\nasync def my_scraping_api(url: str) -> str:\n    \"\"\"Fetch HTML via an external scraping API.\"\"\"\n    async with aiohttp.ClientSession() as session:\n        async with session.get(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Full Escalation (All Features Combined)",
        "content": "This example combines every layer: stealth mode, a list of proxies tried in order, retries, and a final fetch function.\n\n**What happens step by step:**\n\n| Round | Attempt | What runs |\n| --- | --- |…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import aiohttp\nfrom crawl4ai import AsyncWebCrawler\nfrom crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig, ProxyConfig\n\n# Last-resort: fetch HTML via an external service\nasync def…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Tips",
        "content": "- Start with `max_retries=0` and a `fallback_fetch_function` if you just want a safety net without burning time on retries.\n- Order proxies cheapest-first — datacenter proxies before residential,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [Proxy & Security](../proxy-security/) — Proxy setup, authentication, and rotation\n- [Undetected Browser](../undetected-browser/) — Stealth mode and browser fingerprint evasion\n- [Session…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "anti-bot",
      "proxy",
      "retry",
      "fallback",
      "Cloudflare",
      "Akamai",
      "stealth",
      "web scraping",
      "Python"
    ],
    "prerequisites": [],
    "_content_hash": "761a25a8bfc2d3124f85bd552c4c77c1fdab50abd49e44df6d51772cf1c949c9",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/crawl-dispatcher/",
    "title": "Crawl Dispatcher",
    "type": "overview",
    "summary": "This page announces the upcoming Crawl Dispatcher module in Crawl4AI, a feature for handling thousands of crawling tasks simultaneously with efficient resource management and real-time monitoring.",
    "sections": [
      {
        "heading": "Crawl Dispatcher",
        "content": "We’re excited to announce a  **Crawl Dispatcher**  module that can handle  **thousands**  of crawling tasks simultaneously. By efficiently managing system resources (memory, CPU, network), this…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Crawl Dispatcher",
      "multi-URL crawling",
      "performance monitoring",
      "scalable"
    ],
    "prerequisites": [],
    "_content_hash": "2bdcb7f67c8ae58365e1b233a4aeb5ce7420f330f604caae09af161537bbb725",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/file-downloading/",
    "title": "Download Handling in Crawl4AI",
    "type": "guide",
    "summary": "This guide explains how to use Crawl4AI to handle file downloads during crawling, including enabling downloads, specifying download locations, triggering downloads, and accessing downloaded files.",
    "sections": [
      {
        "heading": "Overview",
        "content": "This guide explains how to use Crawl4AI to handle file downloads during crawling. You'll learn how to trigger downloads, specify download locations, and access downloaded files.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Enabling Downloads",
        "content": "To enable downloads, set the `accept_downloads` parameter in the `BrowserConfig` object and pass it to the crawler.",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai.async_configs import BrowserConfig, AsyncWebCrawler\n\nasync def main():\n    config = BrowserConfig(accept_downloads=True)  # Enable downloads globally\n    async with…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Specifying Download Location",
        "content": "Specify the download directory using the `downloads_path` attribute in the `BrowserConfig` object. If not provided, Crawl4AI defaults to creating a \"downloads\" directory inside the `.crawl4ai` folder…",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai.async_configs import BrowserConfig\nimport os\n\ndownloads_path = os.path.join(os.getcwd(), \"my_downloads\")  # Custom download path\nos.makedirs(downloads_path, exist_ok=True)\n\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Triggering Downloads",
        "content": "Downloads are typically triggered by user interactions on a web page, such as clicking a download button. Use `js_code` in `CrawlerRunConfig` to simulate these actions and `wait_for` to allow…",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai.async_configs import CrawlerRunConfig\n\nconfig = CrawlerRunConfig(\n    js_code=\"\"\"\n        const downloadLink = document.querySelector('a[href$=\".exe\"]');\n        if (downloadLink) {…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Accessing Downloaded Files",
        "content": "The `downloaded_files` attribute of the `CrawlResult` object contains paths to downloaded files.",
        "code_blocks": [
          {
            "language": "",
            "code": "if result.downloaded_files:\n    print(\"Downloaded files:\")\n    for file_path in result.downloaded_files:\n        print(f\"- {file_path}\")\n        file_size = os.path.getsize(file_path)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Example: Downloading Multiple Files",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig\nimport os\nfrom pathlib import Path\n\nasync def download_multiple_files(url: str, download_path: str):\n    config =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Important Considerations",
        "content": "- **Browser Context:**  Downloads are managed within the browser context. Ensure `js_code` correctly targets the download triggers on the webpage.\n\n- **Timing:**  Use `wait_for` in `CrawlerRunConfig`…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "file downloads",
      "BrowserConfig",
      "CrawlerRunConfig",
      "AsyncWebCrawler",
      "downloaded_files",
      "js_code",
      "wait_for"
    ],
    "prerequisites": [],
    "_content_hash": "8569f41f8478282952c6e7984fae4060471fe4cebb838f0370bb71cea534f368",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/hooks-auth/",
    "title": "Hooks & Auth in AsyncWebCrawler",
    "type": "guide",
    "summary": "This guide explains how to use hooks in AsyncWebCrawler to customize the crawling pipeline at specific stages, including authentication, route blocking, and pre/post-processing, with a detailed…",
    "sections": [
      {
        "heading": "Introduction",
        "content": "##### Hooks & Auth in AsyncWebCrawler\n\n\n\nCrawl4AI’s  **hooks**  let you customize the crawler at specific points in the pipeline:\n\n\n\n\n1.  **`on_browser_created`**  – After browser creation.\n\n2.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Example: Using Hooks in AsyncWebCrawler",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\nfrom playwright.async_api import Page, BrowserContext\n\nasync def main():\n    print(\"🔗 Hooks…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Hook Lifecycle Summary",
        "content": "1.  **`on_browser_created`** :\n\n   - Browser is up, but  **no**  pages or contexts yet.\n\n   - Light setup only—don’t try to open or close pages here (that belongs in…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "When to Handle Authentication",
        "content": "**Recommended** : Use  **`on_page_context_created`**  if you need to:\n\n\n\n\n- Navigate to a login page or fill forms\n\n- Set cookies or localStorage tokens\n\n- Block resource routes to avoid ads\n\n\n\n\nThis…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Additional Considerations",
        "content": "- **Session Management** : If you want multiple `arun()` calls to reuse a single session, pass `session_id=` in your `CrawlerRunConfig`. Hooks remain the same.\n\n- **Performance** : Hooks can slow…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "Hooks provide  **fine-grained**  control over:\n\n\n\n\n- **Browser**  creation (light tasks only)\n\n- **Page**  and  **context**  creation (auth, route blocking)\n\n- **Navigation**  phases\n\n- **Final…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "hooks",
      "authentication",
      "AsyncWebCrawler",
      "Playwright",
      "Python",
      "web crawling"
    ],
    "prerequisites": [],
    "_content_hash": "fda9aa77b90df500c4c0773fe126774b815d9350f3f646f41e4ea30aa7631fda",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/identity-based-crawling/",
    "title": "Identity Based Crawling - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This guide explains how to use Crawl4AI's Managed Browsers and BrowserProfiler to preserve a user's authentic digital identity while crawling, including persistent profiles, Magic Mode fallback, and…",
    "sections": [
      {
        "heading": "Preserve Your Identity with Crawl4AI",
        "content": "Crawl4AI empowers you to navigate and interact with the web using your **authentic digital identity**, ensuring you’re recognized as a human and not mistaken for a bot. This tutorial covers:\n\n1.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Managed Browsers: Your Digital Identity Solution",
        "content": "**Managed Browsers** let developers create and use **persistent browser profiles**. These profiles store local storage, cookies, and other session data, letting you browse as your **real self**…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Benefits",
        "content": "- **Authentic Browsing Experience**: Retain session data and browser fingerprints as though you’re a normal user.\n- **Effortless Configuration**: Once you log in or solve CAPTCHAs in your chosen data…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Creating a User Data Directory (Command-Line Approach via Playwright)",
        "content": "If you installed Crawl4AI (which installs Playwright under the hood), you already have a Playwright-managed Chromium on your system. Follow these steps to launch that **Chromium** from your command…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "python -m playwright install --dry-run",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "playwright install --dry-run",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "~/.cache/ms-playwright/chromium-1234/chrome-linux/chrome",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "# Linux example\n~/.cache/ms-playwright/chromium-1234/chrome-linux/chrome \\\n    --user-data-dir=/home/<you>/my_chrome_profile",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "# macOS example (Playwright’s internal binary)\n~/Library/Caches/ms-playwright/chromium-1234/chrome-mac/Chromium.app/Contents/MacOS/Chromium \\\n    --user-data-dir=/Users/<you>/my_chrome_profile",
            "filename": ""
          },
          {
            "language": "powershell",
            "code": "# Windows example (PowerShell/cmd)\n\"C:\\Users\\<you>\\AppData\\Local\\ms-playwright\\chromium-1234\\chrome-win\\chrome.exe\" ^\n    --user-data-dir=\"C:\\Users\\<you>\\my_chrome_profile\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nbrowser_config = BrowserConfig(\n    headless=True,\n    use_managed_browser=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Creating a Profile Using the Crawl4AI CLI (Easiest)",
        "content": "If you prefer a guided, interactive setup, use the built-in CLI to create and manage persistent browser profiles.\n\n1. Launch the profile manager (`crwl profiles`).\n\n2. Choose \"Create new profile\" and…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crwl profiles",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig\n\nprofile_path = \"/home/<you>/.crawl4ai/profiles/test_profile_1\"\n\nbrowser_config = BrowserConfig(\n    headless=True,\n    use_managed_browser=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Using Managed Browsers in Crawl4AI",
        "content": "Once you have a data directory with your session data, pass it to **`BrowserConfig`**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    # 1) Reference your persistent data directory\n    browser_config = BrowserConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Workflow",
        "content": "1. **Login** externally (via CLI or your normal Chrome with `--user-data-dir=...`).\n2. **Close** that browser.\n3. **Use** the same folder in `user_data_dir=` in Crawl4AI.\n4. **Crawl** – The site sees…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4. Magic Mode: Simplified Automation",
        "content": "If you **don’t** need a persistent profile or identity-based approach, **Magic Mode** offers a quick way to simulate human-like browsing without storing long-term data.\n\n**Magic Mode**:\n\n- Simulates…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\n        url=\"https://example.com\",\n        config=CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Comparing Managed Browsers vs. Magic Mode",
        "content": "| Feature | **Managed Browsers** | **Magic Mode** |\n| --- | --- | --- |\n| **Session Persistence** | Full localStorage/cookies retained in user_data_dir | No persistent data (fresh each run) |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6. Using the BrowserProfiler Class",
        "content": "Crawl4AI provides a dedicated `BrowserProfiler` class for managing browser profiles, making it easy to create, list, and delete profiles for identity-based browsing.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Creating and Managing Profiles with BrowserProfiler",
        "content": "The `BrowserProfiler` class offers a comprehensive API for browser profile management:\n\n**How profile creation works:**\n1. A browser window opens for you to interact with\n2. You log in to websites,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import BrowserProfiler\n\nasync def manage_profiles():\n    # Create a profiler instance\n    profiler = BrowserProfiler()\n\n    # Create a profile interactively - opens a…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Interactive Profile Management",
        "content": "The `BrowserProfiler` also offers an interactive management console that guides you through profile creation, listing, and deletion:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import BrowserProfiler, AsyncWebCrawler, BrowserConfig\n\n# Define a function to use a profile for crawling\nasync def crawl_with_profile(profile_path, url):…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Legacy Methods",
        "content": "For backward compatibility, the previous methods on `ManagedBrowser` are still available, but they delegate to the new `BrowserProfiler` class:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.browser_manager import ManagedBrowser\n\n# These methods still work but use BrowserProfiler internally\nprofiles = ManagedBrowser.list_profiles()",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complete Example",
        "content": "See the full example in `docs/examples/identity_based_browsing.py` for a complete demonstration of creating and using profiles for authenticated browsing using the new `BrowserProfiler` class.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "7. Locale, Timezone, and Geolocation Control",
        "content": "In addition to using persistent profiles, Crawl4AI supports customizing your browser's locale, timezone, and geolocation settings. These features enhance your identity-based browsing experience by…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Setting Locale and Timezone",
        "content": "You can set the browser's locale and timezone through `CrawlerRunConfig`:\n\n**How it works:**\n- `locale` affects language preferences, date formats, number formats, etc.\n- `timezone_id` affects…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\n        url=\"https://example.com\",\n        config=CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuring Geolocation",
        "content": "Control the GPS coordinates reported by the browser's geolocation API:\n\n**Important notes:**\n- When `geolocation` is specified, the browser is automatically granted permission to access location\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, GeolocationConfig\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\n        url=\"https://maps.google.com\",  # Or any…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining with Managed Browsers",
        "content": "These settings work perfectly with managed browsers for a complete identity solution:\n\nCombining persistent profiles with precise geolocation and region settings gives you complete control over your…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import (\n    AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, \n    GeolocationConfig\n)\n\nbrowser_config = BrowserConfig(\n    use_managed_browser=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Summary",
        "content": "- **Create** your user-data directory either:\n  - By launching Chrome/Chromium externally with `--user-data-dir=/some/path`\n  - Or by using the built-in `BrowserProfiler.create_profile()` method\n  -…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Managed Browsers",
      "BrowserProfiler",
      "Playwright",
      "Magic Mode",
      "identity-based crawling",
      "persistent profiles",
      "geolocation",
      "locale",
      "timezone"
    ],
    "prerequisites": [],
    "_content_hash": "69b98b5f69113d5987f4e9ffda67084fa7178c8bd95b34f76a729127485ff1fe",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/lazy-loading/",
    "title": "Lazy Loading - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This guide explains how to handle lazy-loaded images in Crawl4AI by using wait_for_images, scan_full_page, and scroll_delay settings, and how to combine these with media filters and domain exclusions.",
    "sections": [
      {
        "heading": "Handling Lazy-Loaded Images",
        "content": "Many websites now load images **lazily** as you scroll. If you need to ensure they appear in your final crawl (and in `result.media`), consider:\n\n1. **`wait_for_images=True`** – Wait for images to…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Example: Ensuring Lazy Images Appear",
        "content": "**Explanation**:\n\n- **`wait_for_images=True`**\n\n  The crawler tries to ensure images have finished loading before finalizing the HTML.\n\n- **`scan_full_page=True`**\n\n  Tells the crawler to attempt…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, BrowserConfig\nfrom crawl4ai.async_configs import CacheMode\n\nasync def main():\n    config = CrawlerRunConfig(\n        # Force the…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining with Other Link & Media Filters",
        "content": "You can still combine **lazy-load** logic with the usual **exclude_external_images**, **exclude_domains**, or link filtration:\n\nThis approach ensures you see **all** images from the main domain while…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    wait_for_images=True,\n    scan_full_page=True,\n    scroll_delay=0.5,\n\n    # Filter out external images if you only want local ones\n    exclude_external_images=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Tips & Troubleshooting",
        "content": "1. **Long Pages**\n\n   - Setting `scan_full_page=True` on extremely long or infinite-scroll pages can be resource-intensive.\n\n   - Consider using [hooks](../../core/page-interaction/) or specialized…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "lazy-loading",
      "images",
      "Crawl4AI",
      "web crawling",
      "scroll",
      "wait_for_images",
      "scan_full_page",
      "scroll_delay",
      "media filters"
    ],
    "prerequisites": [],
    "_content_hash": "cc9921dc0dbcb0f3f555e9c7b2e21d23b3f4231ae4ac5cbfa4ee379197cfb710",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/multi-url-crawling/",
    "title": "Advanced Multi-URL Crawling with Dispatchers",
    "type": "api",
    "summary": "This page covers advanced multi-URL crawling using dispatchers in Crawl4AI, including RateLimiter, CrawlerMonitor, MemoryAdaptiveDispatcher, and SemaphoreDispatcher, with usage examples and…",
    "sections": [
      {
        "heading": "1. Introduction",
        "content": "> **Heads Up** : Crawl4AI supports advanced dispatchers for **parallel** or **throttled** crawling, providing dynamic rate limiting and memory usage checks. The built-in `arun_many()` function uses…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. Core Components",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 Rate Limiter",
        "content": "Here’s the revised and simplified explanation of the **RateLimiter** , focusing on constructor parameters and adhering to your markdown style and mkDocs guidelines.",
        "code_blocks": [
          {
            "language": "python",
            "code": "class RateLimiter:\n    def __init__(\n        # Random delay range between requests\n        base_delay: Tuple[float, float] = (1.0, 3.0),  \n\n        # Maximum backoff delay\n        max_delay: float =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "RateLimiter Constructor Parameters",
        "content": "The **RateLimiter** is a utility that helps manage the pace of requests to avoid overloading servers or getting blocked due to rate limits. It operates internally to delay requests and handle retries…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import RateLimiter\n\n# Create a RateLimiter with custom settings\nrate_limiter = RateLimiter(\n    base_delay=(2.0, 4.0),  # Random delay between 2-4 seconds\n    max_delay=30.0,         #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.2 Crawler Monitor",
        "content": "The CrawlerMonitor provides real-time visibility into crawling operations:\n\n **Display Modes** :\n\n- **DETAILED** : Shows individual task status, memory usage, and timing\n- **AGGREGATED** : Displays…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerMonitor, DisplayMode\nmonitor = CrawlerMonitor(\n    # Maximum rows in live display\n    max_visible_rows=15,          \n\n    # DETAILED or AGGREGATED view…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Available Dispatchers",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.1 MemoryAdaptiveDispatcher (Default)",
        "content": "Automatically manages concurrency based on system memory usage:\n\n **Constructor Parameters:** \n\n1. **`memory_threshold_percent`** (`float`, default: `90.0`)\n\n   Specifies the memory usage threshold…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.async_dispatcher import MemoryAdaptiveDispatcher\n\ndispatcher = MemoryAdaptiveDispatcher(\n    memory_threshold_percent=90.0,  # Pause if memory exceeds this\n    check_interval=1.0,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.2 SemaphoreDispatcher",
        "content": "Provides simple concurrency control with a fixed limit:\n\n **Constructor Parameters:** \n\n1. **`max_session_permit`** (`int`, default: `20`)\n\n   The maximum number of concurrent crawling tasks allowed,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.async_dispatcher import SemaphoreDispatcher\n\ndispatcher = SemaphoreDispatcher(\n    max_session_permit=20,         # Maximum concurrent tasks\n    rate_limiter=RateLimiter(      #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Usage Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4.1 Batch Processing (Default)",
        "content": "**Review:** \n\n- **Purpose:** Executes a batch crawl with all URLs processed together after crawling is complete.\n- **Dispatcher:** Uses `MemoryAdaptiveDispatcher` to manage concurrency and system…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def crawl_batch():\n    browser_config = BrowserConfig(headless=True, verbose=False)\n    run_config = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        stream=False  # Default: get…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.2 Streaming Mode",
        "content": "**Review:** \n\n- **Purpose:** Enables streaming to process results as soon as they’re available.\n- **Dispatcher:** Uses `MemoryAdaptiveDispatcher` for concurrency and memory management.\n- **Stream:**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def crawl_streaming():\n    browser_config = BrowserConfig(headless=True, verbose=False)\n    run_config = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        stream=True  # Enable…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.3 Semaphore-based Crawling",
        "content": "**Review:** \n\n- **Purpose:** Uses `SemaphoreDispatcher` to limit concurrency with a fixed number of slots.\n- **Dispatcher:** Configured with a semaphore to control parallel crawling tasks.\n- **Rate…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def crawl_with_semaphore(urls):\n    browser_config = BrowserConfig(headless=True, verbose=False)\n    run_config = CrawlerRunConfig(cache_mode=CacheMode.BYPASS)\n\n    dispatcher =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.4 Robots.txt Consideration",
        "content": "**Review:** \n\n- **Purpose:** Ensures compliance with `robots.txt` rules for ethical and legal web crawling.\n- **Configuration:** Set `check_robots_txt=True` to validate each URL against `robots.txt`…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    urls = [\n        \"https://example1.com\",\n        \"https://example2.com\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Dispatch Results",
        "content": "Each crawl result includes dispatch information:\n\nAccess via `result.dispatch_result`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "@dataclass\nclass DispatchResult:\n    task_id: str\n    memory_usage: float\n    peak_memory: float\n    start_time: datetime\n    end_time: datetime\n    error_message: str = \"\"\nCopy",
            "filename": ""
          },
          {
            "language": "python",
            "code": "for result in results:\n    if result.success:\n        dr = result.dispatch_result\n        print(f\"URL: {result.url}\")\n        print(f\"Memory: {dr.memory_usage:.1f}MB\")\n        print(f\"Duration:…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. URL-Specific Configurations",
        "content": "When crawling diverse content types, you often need different configurations for different URLs. For example:\n- PDFs need specialized extraction\n- Blog pages benefit from content filtering\n- Dynamic…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6.1 Basic URL Pattern Matching",
        "content": "**Important** : A `CrawlerRunConfig` without `url_matcher` (or with `url_matcher=None`) matches ALL URLs. This makes it perfect as a default/fallback configuration.\n\nThe `url_matcher` parameter…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, MatchMode\nfrom crawl4ai.processors.pdf import PDFContentScrapingStrategy\nfrom crawl4ai.extraction_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6.2 Advanced Pattern Matching",
        "content": "**Important** : A `CrawlerRunConfig` without `url_matcher` (or with `url_matcher=None`) matches ALL URLs. This makes it perfect as a default/fallback configuration.\n\nThe `url_matcher` parameter…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Glob Patterns (Strings)",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Simple patterns\n\"*.pdf\"                    # Any PDF file\n\"*/api/*\"                  # Any URL with /api/ in path\n\"https://*.example.com/*\"  # Subdomain matching\n\"*://example.com/blog/*\"   # Any…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Custom Functions",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Complex logic with lambdas\nlambda url: url.startswith('https://') and 'secure' in url\nlambda url: len(url) > 50 and url.count('/') > 5\nlambda url: any(domain in url for domain in ['api.', 'data.',…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Mixed Lists with AND/OR Logic",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Combine multiple conditions\nCrawlerRunConfig(\n    url_matcher=[\n        \"https://*\",                        # Must be HTTPS\n        lambda url: 'internal' in url,      # Must contain 'internal'…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6.3 Practical Example: News Site Crawler",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def crawl_news_site():\n    dispatcher = MemoryAdaptiveDispatcher(\n        memory_threshold_percent=70.0,\n        rate_limiter=RateLimiter(base_delay=(1.0, 2.0))\n    )\n\n    configs = [\n        #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6.4 Best Practices",
        "content": "- **Order Matters** : Configs are evaluated in order - put specific patterns before general ones\n- **Default Config Behavior** :\n  - A config without `url_matcher` matches ALL URLs\n  - Always include…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(url_matcher=\"*.pdf\")\nprint(config.is_match(\"https://example.com/doc.pdf\"))  # True\n\ndefault_config = CrawlerRunConfig()  # No…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Summary",
        "content": "1. **Two Dispatcher Types** :\n\n   - MemoryAdaptiveDispatcher (default): Dynamic concurrency based on memory\n   - SemaphoreDispatcher: Fixed concurrency limit\n\n2. **Optional Components** :\n\n   -…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "base_delay",
        "type": "Tuple[float, float]",
        "description": "The range for a random delay (in seconds) between consecutive requests to the same domain. A random delay is chosen between base_delay[0] and base_delay[1] for each request.",
        "default": "(1.0, 3.0)",
        "required": false
      },
      {
        "name": "max_delay",
        "type": "float",
        "description": "The maximum allowable delay when rate-limiting errors occur. When servers return rate-limit responses (e.g., 429 or 503), the delay increases exponentially with jitter, capped at this value.",
        "default": "60.0",
        "required": false
      },
      {
        "name": "max_retries",
        "type": "int",
        "description": "The maximum number of retries for a request if rate-limiting errors occur. After encountering a rate-limit response, the RateLimiter retries the request up to this number of times.",
        "default": "3",
        "required": false
      },
      {
        "name": "rate_limit_codes",
        "type": "List[int]",
        "description": "A list of HTTP status codes that trigger the rate-limiting logic. These status codes indicate the server is overwhelmed or actively limiting requests.",
        "default": "[429, 503]",
        "required": false
      },
      {
        "name": "memory_threshold_percent",
        "type": "float",
        "description": "Specifies the memory usage threshold (as a percentage). If system memory usage exceeds this value, the dispatcher pauses crawling to prevent system overload.",
        "default": "90.0",
        "required": false
      },
      {
        "name": "check_interval",
        "type": "float",
        "description": "The interval (in seconds) at which the dispatcher checks system memory usage.",
        "default": "1.0",
        "required": false
      },
      {
        "name": "max_session_permit",
        "type": "int",
        "description": "The maximum number of concurrent crawling tasks allowed. This ensures resource limits are respected while maintaining concurrency.",
        "default": "10",
        "required": false
      },
      {
        "name": "memory_wait_timeout",
        "type": "float",
        "description": "Optional timeout (in seconds). If memory usage exceeds memory_threshold_percent for longer than this duration, a MemoryError is raised.",
        "default": "600.0",
        "required": false
      },
      {
        "name": "rate_limiter",
        "type": "RateLimiter",
        "description": "Optional rate-limiting logic to avoid server-side blocking (e.g., for handling 429 or 503 errors).",
        "default": "None",
        "required": false
      },
      {
        "name": "monitor",
        "type": "CrawlerMonitor",
        "description": "Optional monitoring for real-time task tracking and performance insights.",
        "default": "None",
        "required": false
      },
      {
        "name": "max_session_permit",
        "type": "int",
        "description": "The maximum number of concurrent crawling tasks allowed, irrespective of semaphore slots.",
        "default": "20",
        "required": false
      },
      {
        "name": "rate_limiter",
        "type": "RateLimiter",
        "description": "Optional rate-limiting logic to avoid overwhelming servers.",
        "default": "None",
        "required": false
      },
      {
        "name": "monitor",
        "type": "CrawlerMonitor",
        "description": "Optional monitoring for tracking task progress and resource usage.",
        "default": "None",
        "required": false
      },
      {
        "name": "max_visible_rows",
        "type": "int",
        "description": "Maximum rows in live display.",
        "default": "15",
        "required": false
      },
      {
        "name": "display_mode",
        "type": "DisplayMode",
        "description": "DETAILED or AGGREGATED view.",
        "default": "DisplayMode.DETAILED",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "dispatcher",
      "RateLimiter",
      "MemoryAdaptiveDispatcher",
      "SemaphoreDispatcher",
      "CrawlerMonitor",
      "concurrency",
      "rate limiting",
      "web crawling",
      "async",
      "Python"
    ],
    "prerequisites": [],
    "_content_hash": "77b33cadfdf25a242e60dbf57a6d410c35c585bfda48406e0eb4c7f441c1725f",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/network-console-capture/",
    "title": "Network Requests & Console Message Capturing",
    "type": "guide",
    "summary": "This page explains how to capture network requests and browser console messages during a crawl using Crawl4AI, including configuration, example usage, data structures, benefits, and use cases.",
    "sections": [
      {
        "heading": "Configuration",
        "content": "To enable network and console capturing, use these configuration options:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\n# Enable both network request capture and console message capture\nconfig = CrawlerRunConfig(\n    capture_network_requests=True,  # Capture all…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Example Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Enable both network request capture and console message capture\n    config =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Captured Data Structure",
        "content": "The `result.network_requests` contains a list of dictionaries, each representing a network event with these common fields:\n\n| Field | Description |\n| --- | --- |\n| `event_type` | Type of event:…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Network Requests",
        "content": "The `result.network_requests` contains a list of dictionaries, each representing a network event with these common fields:\n\n| Field | Description |\n| --- | --- |\n| `event_type` | Type of event:…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Request Event Fields",
        "content": "",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n  \"event_type\": \"request\",\n  \"url\": \"https://example.com/api/data.json\",\n  \"method\": \"GET\",\n  \"headers\": {\"User-Agent\": \"...\", \"Accept\": \"...\"},\n  \"post_data\": \"key=value&otherkey=value\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Response Event Fields",
        "content": "",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n  \"event_type\": \"response\",\n  \"url\": \"https://example.com/api/data.json\",\n  \"status\": 200,\n  \"status_text\": \"OK\",\n  \"headers\": {\"Content-Type\": \"application/json\", \"Cache-Control\": \"...\"},…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Failed Request Event Fields",
        "content": "",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n  \"event_type\": \"request_failed\",\n  \"url\": \"https://example.com/missing.png\",\n  \"method\": \"GET\",\n  \"resource_type\": \"image\",\n  \"failure_text\": \"net::ERR_ABORTED 404\",\n  \"timestamp\": 1633456789.789\n}",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Console Messages",
        "content": "The `result.console_messages` contains a list of dictionaries, each representing a console message with these common fields:\n\n| Field | Description |\n| --- | --- |\n| `type` | Message type: `\"log\"`,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Console Message Example",
        "content": "",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n  \"type\": \"error\",\n  \"text\": \"Uncaught TypeError: Cannot read property 'length' of undefined\",\n  \"location\": \"https://example.com/script.js:123:45\",\n  \"timestamp\": 1633456790.123\n}",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Key Benefits",
        "content": "**Full Request Visibility** : Capture all network activity including:\n- Requests (URLs, methods, headers, post data)\n- Responses (status codes, headers, timing)\n- Failed requests (with error…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Use Cases",
        "content": "**API Discovery** : Identify hidden endpoints and data flows in single-page applications\n\n**Debugging** : Track down JavaScript errors affecting page functionality\n\n**Security Auditing** : Detect…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "network capture",
      "console capture",
      "debugging",
      "security",
      "performance",
      "API discovery"
    ],
    "prerequisites": [],
    "_content_hash": "d9aa7df721a13da71678ee324a44f49924597d1069e446e041912448c9dc5874",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/pdf-parsing/",
    "title": "PDF Processing Strategies",
    "type": "api",
    "summary": "This page describes the PDF processing strategies in Crawl4AI, including PDFCrawlerStrategy and PDFContentScrapingStrategy, which enable crawling and extracting content from PDF files.",
    "sections": [
      {
        "heading": "Overview",
        "content": "`PDFCrawlerStrategy` is an implementation of `AsyncCrawlerStrategy` designed specifically for PDF documents. Instead of interpreting the input URL as an HTML webpage, this strategy treats it as a…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "When to Use",
        "content": "Use `PDFCrawlerStrategy` when you need to:\n- Process PDF files using the `AsyncWebCrawler`.\n- Handle PDFs from both web URLs (e.g., `https://example.com/document.pdf`) and local file paths (e.g.,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Methods and Their Behavior",
        "content": "- **`__init__(self, logger: AsyncLogger = None)`** :\n\n- Initializes the strategy.\n- `logger`: An optional `AsyncLogger` instance (from `crawl4ai.async_logger`) for logging purposes.\n\n- **`async…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Example Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.processors.pdf import PDFCrawlerStrategy, PDFContentScrapingStrategy\n\nasync def main():\n    # Initialize the PDF…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Pros and Cons",
        "content": "**Pros:** \n-   Enables `AsyncWebCrawler` to handle PDF sources directly using familiar `arun` calls.\n-   Provides a consistent interface for specifying PDF sources (URLs or local paths).\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Configuration Attributes",
        "content": "When initializing `PDFContentScrapingStrategy`, you can configure its behavior using the following attributes:\n-    **`extract_images: bool = False`** : If `True`, the strategy will attempt to…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "logger",
        "type": "AsyncLogger",
        "description": "An optional AsyncLogger instance for logging purposes.",
        "default": "None",
        "required": false
      },
      {
        "name": "url",
        "type": "str",
        "description": "The URL pointing to a PDF file.",
        "default": "",
        "required": true
      },
      {
        "name": "save_images_locally",
        "type": "bool",
        "description": "If True (and extract_images is also True), extracted images will be saved to disk in the image_save_dir.",
        "default": "False",
        "required": false
      },
      {
        "name": "extract_images",
        "type": "bool",
        "description": "If True, the strategy will attempt to extract images from the PDF.",
        "default": "False",
        "required": false
      },
      {
        "name": "image_save_dir",
        "type": "str",
        "description": "Specifies the directory where extracted images should be saved if save_images_locally is True.",
        "default": "None",
        "required": false
      },
      {
        "name": "batch_size",
        "type": "int",
        "description": "Defines how many PDF pages are processed in a single batch.",
        "default": "4",
        "required": false
      },
      {
        "name": "logger",
        "type": "AsyncLogger",
        "description": "An optional AsyncLogger instance for logging.",
        "default": "None",
        "required": false
      },
      {
        "name": "url",
        "type": "str",
        "description": "The path or URL to the PDF file.",
        "default": "",
        "required": true
      },
      {
        "name": "html",
        "type": "str",
        "description": "Typically an empty string when used with PDFCrawlerStrategy, as the content is a PDF, not HTML.",
        "default": "",
        "required": true
      },
      {
        "name": "url",
        "type": "str",
        "description": "The path or URL to the PDF file.",
        "default": "",
        "required": true
      },
      {
        "name": "html",
        "type": "str",
        "description": "Typically an empty string when used with PDFCrawlerStrategy, as the content is a PDF, not HTML.",
        "default": "",
        "required": true
      },
      {
        "name": "url",
        "type": "str",
        "description": "The URL or path to the PDF file.",
        "default": "",
        "required": true
      }
    ],
    "see_also": [],
    "tags": [
      "PDF",
      "Crawl4AI",
      "AsyncWebCrawler",
      "PDFCrawlerStrategy",
      "PDFContentScrapingStrategy",
      "scraping",
      "parsing",
      "document processing",
      "image extraction",
      "metadata extraction"
    ],
    "prerequisites": [],
    "_content_hash": "a9f3d19898fc0ba1d5161b18ee8440150e804d2a1d000f41be537a2779b19624",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/proxy-security/",
    "title": "Proxy & Security",
    "type": "guide",
    "summary": "This guide covers proxy configuration and security features in Crawl4AI, including SSL certificate analysis and proxy rotation strategies.",
    "sections": [
      {
        "heading": "Understanding Proxy Configuration",
        "content": "Crawl4AI recommends configuring proxies per request through `CrawlerRunConfig.proxy_config`. This gives you precise control, enables rotation strategies, and keeps examples simple enough to copy,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Proxy Setup",
        "content": "Configure proxies that apply to each crawl operation:\n\nWhy request-level?\n\n`CrawlerRunConfig.proxy_config` keeps each request self-contained, so swapping proxies or rotation strategies is just a…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, ProxyConfig\n\nrun_config = CrawlerRunConfig(proxy_config=ProxyConfig(server=\"http://proxy.example.com:8080\"))\n#…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Supported Proxy Formats",
        "content": "The `ProxyConfig.from_string()` method supports multiple formats:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import ProxyConfig\n\n# HTTP proxy with authentication\nproxy1 = ProxyConfig.from_string(\"http://user:pass@192.168.1.1:8080\")\n\n# HTTPS proxy\nproxy2 =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Authenticated Proxies",
        "content": "For proxies requiring authentication:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler,BrowserConfig, CrawlerRunConfig, ProxyConfig\n\nrun_config = CrawlerRunConfig(\n    proxy_config=ProxyConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Environment Variable Configuration",
        "content": "Load proxies from environment variables for easy configuration:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import os\nfrom crawl4ai import ProxyConfig, CrawlerRunConfig\n\n# Set environment variable\nos.environ[\"PROXIES\"] = \"ip1:port1:user1:pass1,ip2:port2:user2:pass2,ip3:port3\"\n\n# Load all proxies\nproxies =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Rotating Proxies",
        "content": "Crawl4AI supports automatic proxy rotation to distribute requests across multiple proxy servers. Rotation is applied per request using a rotation strategy on `CrawlerRunConfig`.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Proxy Rotation (recommended)",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport re\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode, ProxyConfig\nfrom crawl4ai.proxy_strategy import RoundRobinProxyStrategy\n\nasync def main():…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "SSL Certificate Analysis",
        "content": "Combine proxy usage with SSL certificate inspection for enhanced security analysis. SSL certificate fetching is configured per request via `CrawlerRunConfig`.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Per-Request SSL Certificate Analysis",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nrun_config = CrawlerRunConfig(\n    proxy_config={\n        \"server\": \"http://proxy.example.com:8080\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Security Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Proxy Rotation for Anonymity",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig, ProxyConfig\nfrom crawl4ai.proxy_strategy import RoundRobinProxyStrategy\n\n# Use multiple proxies to avoid IP blocking\nproxies =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. SSL Certificate Verification",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig\n\n# Always verify SSL certificates when possible\n# Per-request (affects specific requests)\nrun_config = CrawlerRunConfig(fetch_ssl_certificate=True)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Environment Variable Security",
        "content": "",
        "code_blocks": [
          {
            "language": "bash",
            "code": "# Use environment variables for sensitive proxy credentials\n# Avoid hardcoding usernames/passwords in code\nexport PROXIES=\"ip1:port1:user1:pass1,ip2:port2:user2:pass2\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. SOCKS5 for Enhanced Security",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig\n\n# Prefer SOCKS5 proxies for better protocol support\nrun_config = CrawlerRunConfig(proxy_config=\"socks5://proxy.example.com:1080\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Migration from Deprecated `proxy` Parameter",
        "content": "The legacy `proxy` argument on `BrowserConfig` is deprecated. Configure proxies through `CrawlerRunConfig.proxy_config` so each request fully describes its network settings.",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Old (deprecated) approach\n# from crawl4ai import BrowserConfig\n# browser_config = BrowserConfig(proxy_config=\"http://proxy.example.com:8080\")\n\n# New (preferred) approach\nfrom crawl4ai import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Safe Logging of Proxies",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import ProxyConfig\n\ndef safe_proxy_repr(proxy: ProxyConfig):\n    if getattr(proxy, \"username\", None):\n        return f\"{proxy.server} (auth: ****)\"\n    return proxy.server",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Troubleshooting",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Common Issues",
        "content": "Proxy connection failed\n\n- Verify the proxy server is reachable from your network.\n- Double-check authentication credentials.\n- Ensure the protocol matches (`http`, `https`, or `socks5`).\n\nSSL…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "[Anti-Bot Detection & Fallback](../anti-bot-and-fallback/) — Automatic retry with proxy escalation and fallback functions when anti-bot blocking is detected",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "proxy",
      "security",
      "ssl",
      "certificate",
      "rotation",
      "crawl4ai",
      "authentication",
      "socks5"
    ],
    "prerequisites": [],
    "_content_hash": "d5518b24e6f706e1dfa5093f264fef073d2fa813a83fe817826a9769bbec22a6",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/session-management/",
    "title": "Session Management - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page explains how to use session management in Crawl4AI to maintain state across multiple requests, enabling sequential crawling, dynamic content handling, and advanced techniques like custom…",
    "sections": [
      {
        "heading": "Overview",
        "content": "Session management in Crawl4AI is a powerful feature that allows you to maintain state across multiple requests, making it particularly suitable for handling complex multi-step crawling tasks. It…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Session Usage",
        "content": "Use `BrowserConfig` and `CrawlerRunConfig` to maintain state with a `session_id`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig\n\nasync with AsyncWebCrawler() as crawler:\n    session_id = \"my_session\"\n\n    # Define configurations\n    config1 =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Dynamic Content with Sessions",
        "content": "Here's an example of crawling GitHub commits across multiple pages while preserving session state:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.async_configs import CrawlerRunConfig\nfrom crawl4ai import JsonCssExtractionStrategy\nfrom crawl4ai.cache_context import CacheMode\n\nasync def crawl_dynamic_content():\n    url =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Example 1: Basic Session-Based Crawling",
        "content": "A simple example using session-based crawling:\n\nThis example shows:\n1. Reusing the same `session_id` across multiple requests.\n2. Executing JavaScript to load more content dynamically.\n3. Properly…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig\nfrom crawl4ai.cache_context import CacheMode\n\nasync def basic_session_crawl():\n    async with AsyncWebCrawler() as…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Technique 1: Custom Execution Hooks",
        "content": "> Warning: You might feel confused by the end of the next few examples 😅, so make sure you are comfortable with the order of the parts before you start this.\n\nUse custom hooks to handle complex…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def advanced_session_crawl_with_hooks():\n    first_commit = \"\"\n\n    async def on_execution_started(page):\n        nonlocal first_commit\n        try:\n            while True:…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Technique 2: Integrated JavaScript Execution and Waiting",
        "content": "Combine JavaScript execution and waiting logic for concise handling of dynamic content:",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def integrated_js_and_wait_crawl():\n    async with AsyncWebCrawler() as crawler:\n        session_id = \"integrated_session\"\n        url = \"https://github.com/example/repo/commits/main\"…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Common Use Cases for Sessions",
        "content": "1. **Authentication Flows**: Login and interact with secured pages.\n\n2. **Pagination Handling**: Navigate through multiple pages.\n\n3. **Form Submissions**: Fill forms, submit, and process…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "session management",
      "crawling",
      "browser automation",
      "async",
      "python",
      "crawl4ai"
    ],
    "prerequisites": [],
    "_content_hash": "fa62a727c57a013bd7f85806480ad509c46a4fd743a6a187c01ceeef8d9e90fa",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/ssl-certificate/",
    "title": "SSLCertificate Reference",
    "type": "api",
    "summary": "Reference for the SSLCertificate class in Crawl4AI, covering how to load, inspect, and export SSL/TLS certificate data, and how to use it with fetch_ssl_certificate=True in CrawlerRunConfig.",
    "sections": [
      {
        "heading": "1. Overview",
        "content": "The **`SSLCertificate`** class encapsulates an SSL certificate’s data and allows exporting it in various formats (PEM, DER, JSON, or text). It’s used within **Crawl4AI** whenever you set…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class SSLCertificate:\n    \"\"\"\n    Represents an SSL certificate with methods to export in various formats.\n\n    Main Methods:\n    - from_url(url, timeout=10)\n    - from_file(file_path)\n    -…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Typical Use Case",
        "content": "- You **enable** certificate fetching in your crawl by:\n- After `arun()`, if `result.ssl_certificate` is present, it’s an instance of **`SSLCertificate`**.\n- You can **read** basic properties…",
        "code_blocks": [
          {
            "language": "python",
            "code": "CrawlerRunConfig(fetch_ssl_certificate=True, ...)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Construction & Fetching",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 from_url(url, timeout=10)",
        "content": "Manually load an SSL certificate from a given URL (port 443). Typically used internally, but you can call it directly if you want:",
        "code_blocks": [
          {
            "language": "python",
            "code": "cert = SSLCertificate.from_url(\"https://example.com\")\nif cert:\n    print(\"Fingerprint:\", cert.fingerprint)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.2 from_file(file_path)",
        "content": "Load from a file containing certificate data in ASN.1 or DER. Rarely needed unless you have local cert files:",
        "code_blocks": [
          {
            "language": "python",
            "code": "cert = SSLCertificate.from_file(\"/path/to/cert.der\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.3 from_binary(binary_data)",
        "content": "Initialize from raw binary. E.g., if you captured it from a socket or another source:",
        "code_blocks": [
          {
            "language": "python",
            "code": "cert = SSLCertificate.from_binary(raw_bytes)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Common Properties",
        "content": "After obtaining a **`SSLCertificate`** instance (e.g. `result.ssl_certificate` from a crawl), you can read:\n\n1. **`issuer`** *(dict)*\n   - E.g. `{\"CN\": \"My Root CA\", \"O\": \"...\"}`\n2. **`subject`**…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4. Export Methods",
        "content": "Once you have a **`SSLCertificate`** object, you can **export** or **inspect** it:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4.1 to_json(filepath=None) → Optional[str]",
        "content": "- Returns a JSON string containing the parsed certificate fields.\n- If `filepath` is provided, saves it to disk instead, returning `None`.\n\n**Usage**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "json_data = cert.to_json()  # returns JSON string\ncert.to_json(\"certificate.json\")  # writes file, returns None",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.2 to_pem(filepath=None) → Optional[str]",
        "content": "- Returns a PEM-encoded string (common for web servers).\n- If `filepath` is provided, saves it to disk instead.",
        "code_blocks": [
          {
            "language": "python",
            "code": "pem_str = cert.to_pem()              # in-memory PEM string\ncert.to_pem(\"/path/to/cert.pem\")     # saved to file",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.3 to_der(filepath=None) → Optional[bytes]",
        "content": "- Returns the original DER (binary ASN.1) bytes.\n- If `filepath` is specified, writes the bytes there instead.",
        "code_blocks": [
          {
            "language": "python",
            "code": "der_bytes = cert.to_der()\ncert.to_der(\"certificate.der\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.4 (Optional) export_as_text()",
        "content": "- If you see a method like `export_as_text()`, it typically returns an OpenSSL-style textual representation.\n- Not always needed, but can help for debugging or manual inspection.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "5. Example Usage in Crawl4AI",
        "content": "Below is a minimal sample showing how the crawler obtains an SSL cert from a site, then reads or exports it. The code snippet:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport os\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    tmp_dir = \"tmp\"\n    os.makedirs(tmp_dir, exist_ok=True)\n\n    config =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Notes & Best Practices",
        "content": "1. **Timeout**: `SSLCertificate.from_url` internally uses a default **10s** socket connect and wraps SSL.\n2. **Binary Form**: The certificate is loaded in ASN.1 (DER) form, then re-parsed by…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Summary",
        "content": "- **`SSLCertificate`** is a convenience class for capturing and exporting the **TLS certificate** from your crawled site(s).\n- Common usage is in the **`CrawlResult.ssl_certificate`** field,…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "from_url.url",
        "type": "str",
        "description": "The URL to load the SSL certificate from (port 443).",
        "default": "",
        "required": true
      },
      {
        "name": "from_url.timeout",
        "type": "int",
        "description": "Socket connect timeout in seconds.",
        "default": "10",
        "required": false
      },
      {
        "name": "from_file.file_path",
        "type": "str",
        "description": "Path to a file containing certificate data in ASN.1 or DER.",
        "default": "",
        "required": true
      },
      {
        "name": "from_binary.binary_data",
        "type": "bytes",
        "description": "Raw binary certificate data.",
        "default": "",
        "required": true
      },
      {
        "name": "to_json.filepath",
        "type": "Optional[str]",
        "description": "If provided, saves the JSON output to disk instead of returning a string.",
        "default": "None",
        "required": false
      },
      {
        "name": "to_pem.filepath",
        "type": "Optional[str]",
        "description": "If provided, saves the PEM output to disk instead of returning a string.",
        "default": "None",
        "required": false
      },
      {
        "name": "to_der.filepath",
        "type": "Optional[str]",
        "description": "If provided, writes the DER bytes to disk instead of returning bytes.",
        "default": "None",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "SSLCertificate",
      "SSL",
      "TLS",
      "certificate",
      "Crawl4AI",
      "CrawlerRunConfig",
      "PEM",
      "DER",
      "JSON",
      "OpenSSL",
      "AsyncWebCrawler"
    ],
    "prerequisites": [],
    "_content_hash": "678bee01067ce4b13bbc2594cd9976d10d5c334cb2f9968896cc89cc433e5f4c",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/undetected-browser/",
    "title": "Undetected Browser Mode",
    "type": "guide",
    "summary": "This guide covers Crawl4AI's anti-bot features: Stealth Mode and Undetected Browser Mode, including how to use them, when to use each, and best practices for evading bot detection.",
    "sections": [
      {
        "heading": "Overview",
        "content": "Crawl4AI offers two powerful anti-bot features to help you access websites with bot detection:\n\n- **Stealth Mode** - Uses playwright-stealth to modify browser fingerprints and behaviors\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Anti-Bot Features Comparison",
        "content": "| Feature | Regular Browser | Stealth Mode | Undetected Browser |\n| --- | --- | --- | --- |\n| WebDriver Detection | ❌ | ✅ | ✅ |\n| Navigator Properties | ❌ | ✅ | ✅ |\n| Plugin Emulation | ❌ | ✅ | ✅ |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "When to Use Each Approach",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Use Regular Browser + Stealth Mode When:",
        "content": "- Sites have basic bot detection (checking navigator.webdriver, plugins, etc.)\n- You need good performance with basic protection\n- Sites check for common automation indicators",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Use Undetected Browser When:",
        "content": "- Sites employ sophisticated bot detection services (Cloudflare, DataDome, etc.)\n- Stealth mode alone isn't sufficient\n- You're willing to trade some performance for better evasion",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Best Practice: Progressive Enhancement",
        "content": "- **Start with**: Regular browser + Stealth mode\n- **If blocked**: Switch to Undetected browser\n- **If still blocked**: Combine Undetected browser + Stealth mode",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Stealth Mode",
        "content": "Stealth mode is the simpler anti-bot solution that works with both regular and undetected browsers:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig\n\n# Enable stealth mode with regular browser\nbrowser_config = BrowserConfig(\n    enable_stealth=True,  # Simple flag to enable\n    headless=False…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "What Stealth Mode Does:",
        "content": "- Removes `navigator.webdriver` flag\n- Modifies browser fingerprints\n- Emulates realistic plugin behavior\n- Adjusts navigator properties\n- Fixes common automation leaks",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Undetected Browser Mode",
        "content": "For sites with sophisticated bot detection that stealth mode can't bypass, use the undetected browser adapter:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Features",
        "content": "- **Drop-in Replacement**: Uses the same API as regular browser mode\n- **Enhanced Stealth**: Built-in patches to evade common detection methods\n- **Browser Adapter Pattern**: Seamlessly switch…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import (\n    AsyncWebCrawler, \n    BrowserConfig, \n    CrawlerRunConfig,\n    UndetectedAdapter\n)\nfrom crawl4ai.async_crawler_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining Both Features",
        "content": "For maximum evasion, combine stealth mode with undetected browser:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig, UndetectedAdapter\nfrom crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy\n\n# Create browser config with stealth…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Example 1: Basic Stealth Mode",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def test_stealth_mode():\n    # Simple stealth mode configuration\n    browser_config = BrowserConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Example 2: Undetected Browser Mode",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import (\n    AsyncWebCrawler,\n    BrowserConfig,\n    CrawlerRunConfig,\n    UndetectedAdapter\n)\nfrom crawl4ai.async_crawler_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Browser Adapter Pattern",
        "content": "The undetected browser support is implemented using an adapter pattern, allowing seamless switching between different browser implementations:\n\nThe adapter handles:\n- JavaScript execution\n- Console…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Regular browser adapter (default)\nfrom crawl4ai import PlaywrightAdapter\nregular_adapter = PlaywrightAdapter()\n\n# Undetected browser adapter\nfrom crawl4ai import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "- **Avoid Headless Mode**: Detection is easier in headless mode\n- **Use Reasonable Delays**: Don't rush through pages\n- **Rotate User Agents**: You can customize user agents\n- **Handle Failures…",
        "code_blocks": [
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(headless=False)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "crawler_config = CrawlerRunConfig(\n    wait_time=3.0,  # Wait 3 seconds after page load\n    delay_before_return_html=2.0  # Additional delay\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(\n    headers={\"User-Agent\": \"your-user-agent\"}\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if not result.success:\n    print(f\"Crawl failed: {result.error_message}\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Usage Tips",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Progressive Detection Handling",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def crawl_with_progressive_evasion(url):\n    # Step 1: Try regular browser with stealth\n    browser_config = BrowserConfig(\n        enable_stealth=True,\n        headless=False\n    )\n\n    async…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Installation",
        "content": "The undetected browser dependencies are automatically installed when you run:\n\nThis command installs all necessary browser dependencies for both regular and undetected modes.",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crawl4ai-setup",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Limitations",
        "content": "- **Performance**: Slightly slower than regular mode due to additional patches\n- **Headless Detection**: Some sites can still detect headless mode\n- **Resource Usage**: May use more resources than…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Troubleshooting",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Browser Not Found",
        "content": "Run the setup command:",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crawl4ai-setup",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Detection Still Occurring",
        "content": "Try combining with other features:",
        "code_blocks": [
          {
            "language": "python",
            "code": "crawler_config = CrawlerRunConfig(\n    simulate_user=True,  # Add user simulation\n    magic=True,  # Enable magic mode\n    wait_time=5.0,  # Longer waits\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Issues",
        "content": "If experiencing slow performance:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Use selective undetected mode only for protected sites\nif is_protected_site(url):\n    adapter = UndetectedAdapter()\nelse:\n    adapter = PlaywrightAdapter()  # Default adapter",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Future Plans",
        "content": "**Note**: In future versions of Crawl4AI, we may enable stealth mode and undetected browser by default to provide better out-of-the-box success rates. For now, users should explicitly enable these…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "Crawl4AI provides flexible anti-bot solutions:\n\n- **Start Simple**: Use regular browser + stealth mode for most sites\n- **Escalate if Needed**: Switch to undetected browser for sophisticated…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [Advanced Features](../advanced-features/) - Overview of all advanced features\n- [Proxy & Security](../proxy-security/) - Using proxies with anti-bot features\n- [Session…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Stealth Mode",
      "Undetected Browser",
      "Anti-bot",
      "Playwright",
      "Browser Automation",
      "Web Scraping"
    ],
    "prerequisites": [],
    "_content_hash": "33163d8cc0605541ef6bd082f38540286b73414c1c0fff6c32d39bc5baca4fef",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/advanced/virtual-scroll/",
    "title": "Virtual Scroll - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page explains Crawl4AI's Virtual Scroll feature for handling virtual scrolling websites, covering configuration, usage examples, comparison with scan_full_page, and performance tips.",
    "sections": [
      {
        "heading": "Understanding Virtual Scroll",
        "content": "Modern websites increasingly use virtual scrolling (also called windowed rendering or viewport rendering) to handle large datasets efficiently. This technique only renders visible items in the DOM,…",
        "code_blocks": [
          {
            "language": "text",
            "code": "Traditional Scroll:          Virtual Scroll:\n┌─────────────┐             ┌─────────────┐\n│ Item 1      │             │ Item 11     │  <- Items 1-10 removed\n│ Item 2      │             │ Item 12     │…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, VirtualScrollConfig\n\n# Configure virtual scroll\nvirtual_config = VirtualScrollConfig(\n    container_selector=\"#feed\",      # CSS selector for…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Parameters",
        "content": "###### VirtualScrollConfig\n\n| Parameter | Type | Default | Description |\n| --- | --- | --- | --- |\n| `container_selector` | `str` | Required | CSS selector for the scrollable container |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Real-World Examples",
        "content": "###### Twitter-like Timeline\n\nTwitter replaces tweets as you scroll.\n\n###### Instagram Grid\n\nInstagram uses virtualized grid for performance.\n\n###### Mixed Content (News Feed)\n\nSome sites mix static and…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, VirtualScrollConfig, BrowserConfig\n\nasync def crawl_twitter_timeline():\n    # Twitter replaces tweets as you scroll\n    virtual_config =…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def crawl_instagram_grid():\n    # Instagram uses virtualized grid for performance\n    virtual_config = VirtualScrollConfig(\n        container_selector=\"article\",  # Main feed container…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def crawl_mixed_feed():\n    # Featured articles stay, regular articles virtualize\n    virtual_config = VirtualScrollConfig(\n        container_selector=\".main-feed\",\n        scroll_count=25,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Virtual Scroll vs scan_full_page",
        "content": "Both features handle dynamic content, but serve different purposes:\n\n| Feature | Virtual Scroll | scan_full_page |\n| --- | --- | --- |\n| **Purpose** | Capture content that's replaced during scroll |…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Combining with Extraction",
        "content": "Virtual Scroll works seamlessly with extraction strategies.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import LLMExtractionStrategy, LLMConfig\n\n# Define extraction schema\nschema = {\n    \"type\": \"array\",\n    \"items\": {\n        \"type\": \"object\", \n        \"properties\": {…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Tips",
        "content": "- **Container Selection**: Be specific with selectors. Using the correct container improves performance.\n- **Scroll Count**: Start conservative and increase as needed.\n- **Wait Times**: Adjust based…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Start with fewer scrolls\nvirtual_config = VirtualScrollConfig(\n    container_selector=\"#feed\",\n    scroll_count=10  # Test with 10, increase if needed\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Fast sites\nwait_after_scroll=0.2\n\n# Slower sites or heavy content\nwait_after_scroll=1.5",
            "filename": ""
          },
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(headless=False)\nasync with AsyncWebCrawler(config=browser_config) as crawler:\n    # Watch the scrolling happen",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "How It Works Internally",
        "content": "- **Detection Phase**: Scrolls and compares HTML to detect behavior\n- **Capture Phase**: For replaced content, stores HTML chunks at each position\n- **Merge Phase**: Combines all chunks, removing…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Error Handling",
        "content": "Virtual Scroll handles errors gracefully. If the container isn't found, crawling continues normally without virtual scroll.",
        "code_blocks": [
          {
            "language": "python",
            "code": "# If container not found or scrolling fails\nresult = await crawler.arun(url=\"...\", config=config)\n\nif result.success:\n    # Virtual scroll worked or wasn't needed\n    print(f\"Captured…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complete Example",
        "content": "See our comprehensive example that demonstrates:\n- Twitter-like feeds\n- Instagram grids\n- Traditional infinite scroll\n- Mixed content scenarios\n- Performance comparisons\n\nThe example includes a local…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "# Run the examples\ncd docs/examples\npython virtual_scroll_example.py",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "virtual scroll",
      "windowed rendering",
      "viewport rendering",
      "infinite scroll",
      "Crawl4AI",
      "web crawling",
      "dynamic content",
      "scraping"
    ],
    "prerequisites": [],
    "_content_hash": "a132c3fd838fb9c4e775f090484a5c22217412f2e188f800efcce0d5b4c05225",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/adaptive-crawler/",
    "title": "AdaptiveCrawler",
    "type": "api",
    "summary": "The AdaptiveCrawler class implements intelligent web crawling that automatically determines when sufficient information has been gathered to answer a query. It uses a three-layer scoring system to…",
    "sections": [
      {
        "heading": "Constructor",
        "content": "###### Parameters\n\n- **crawler**  (`AsyncWebCrawler`): The underlying web crawler instance to use for fetching pages\n- **config**  (`Optional[AdaptiveConfig]`): Configuration settings for adaptive…",
        "code_blocks": [
          {
            "language": "python",
            "code": "AdaptiveCrawler(\n    crawler: AsyncWebCrawler,\n    config: Optional[AdaptiveConfig] = None\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Primary Method",
        "content": "###### digest()\n\nThe main method that performs adaptive crawling starting from a URL with a specific query.\n\n###### Parameters\n\n- **start_url**  (`str`): The starting URL for crawling\n- **query**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def digest(\n    start_url: str,\n    query: str,\n    resume_from: Optional[Union[str, Path]] = None\n) -> CrawlState",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async with AsyncWebCrawler() as crawler:\n    adaptive = AdaptiveCrawler(crawler)\n    state = await adaptive.digest(\n        start_url=\"https://docs.python.org\",\n        query=\"async context…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Properties",
        "content": "###### confidence\n\nCurrent confidence score (0-1) indicating information sufficiency.\n\n###### coverage_stats\n\nDictionary containing detailed coverage statistics.\n\nReturns:\n-  **coverage** : Query term…",
        "code_blocks": [
          {
            "language": "python",
            "code": "@property\ndef confidence(self) -> float",
            "filename": ""
          },
          {
            "language": "python",
            "code": "@property  \ndef coverage_stats(self) -> Dict[str, float]",
            "filename": ""
          },
          {
            "language": "python",
            "code": "@property\ndef is_sufficient(self) -> bool",
            "filename": ""
          },
          {
            "language": "python",
            "code": "@property\ndef state(self) -> CrawlState",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Methods",
        "content": "###### get_relevant_content()\n\nRetrieve the most relevant content from the knowledge base.\n\n###### Parameters\n\n- **top_k**  (`int`): Number of top relevant documents to return (default: 5)\n\n####…",
        "code_blocks": [
          {
            "language": "python",
            "code": "def get_relevant_content(\n    self,\n    top_k: int = 5\n) -> List[Dict[str, Any]]",
            "filename": ""
          },
          {
            "language": "python",
            "code": "def print_stats(\n    self,\n    detailed: bool = False\n) -> None",
            "filename": ""
          },
          {
            "language": "python",
            "code": "def export_knowledge_base(\n    self,\n    path: Union[str, Path]\n) -> None",
            "filename": ""
          },
          {
            "language": "python",
            "code": "adaptive.export_knowledge_base(\"my_knowledge.jsonl\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def import_knowledge_base(\n    self,\n    path: Union[str, Path]\n) -> None",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration",
        "content": "The `AdaptiveConfig` class controls the behavior of adaptive crawling:\n\n###### Example with Custom Config",
        "code_blocks": [
          {
            "language": "python",
            "code": "@dataclass\nclass AdaptiveConfig:\n    confidence_threshold: float = 0.8      # Stop when confidence reaches this\n    max_pages: int = 50                    # Maximum pages to crawl\n    top_k_links:…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = AdaptiveConfig(\n    confidence_threshold=0.7,\n    max_pages=20,\n    top_k_links=3\n)\n\nadaptive = AdaptiveCrawler(crawler, config=config)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complete Example",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, AdaptiveCrawler, AdaptiveConfig\n\nasync def main():\n    # Configure adaptive crawling\n    config = AdaptiveConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [digest() Method Reference](../digest/)\n- [Adaptive Crawling Guide](../../core/adaptive-crawling/)\n- [Advanced Adaptive Strategies](../../advanced/adaptive-strategies/)",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "crawler",
        "type": "AsyncWebCrawler",
        "description": "The underlying web crawler instance to use for fetching pages",
        "default": "",
        "required": true
      },
      {
        "name": "config",
        "type": "Optional[AdaptiveConfig]",
        "description": "Configuration settings for adaptive crawling behavior. If not provided, uses default settings.",
        "default": "None",
        "required": false
      },
      {
        "name": "start_url",
        "type": "str",
        "description": "The starting URL for crawling",
        "default": "",
        "required": true
      },
      {
        "name": "query",
        "type": "str",
        "description": "The search query that guides the crawling process",
        "default": "",
        "required": true
      },
      {
        "name": "resume_from",
        "type": "Optional[Union[str, Path]]",
        "description": "Path to a saved state file to resume from",
        "default": "None",
        "required": false
      },
      {
        "name": "top_k",
        "type": "int",
        "description": "Number of top relevant documents to return",
        "default": "5",
        "required": false
      },
      {
        "name": "detailed",
        "type": "bool",
        "description": "If True, shows detailed metrics with colors. If False, shows summary table.",
        "default": "False",
        "required": false
      },
      {
        "name": "path",
        "type": "Union[str, Path]",
        "description": "Output file path for JSONL export",
        "default": "",
        "required": true
      },
      {
        "name": "path",
        "type": "Union[str, Path]",
        "description": "Path to JSONL file to import",
        "default": "",
        "required": true
      }
    ],
    "see_also": [],
    "tags": [
      "crawling",
      "adaptive",
      "web scraping",
      "AsyncWebCrawler",
      "Crawl4AI",
      "coverage",
      "consistency",
      "saturation"
    ],
    "prerequisites": [],
    "_content_hash": "3f98737cd61f2a399695aae3ef579feced480b34c6e0f3a6df1e4a14d25df467",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/arun/",
    "title": "`arun()` Parameter Guide (New Approach)",
    "type": "guide",
    "summary": "A guide to the parameters of the `arun()` method in Crawl4AI, now organized under `CrawlerRunConfig`, covering caching, content processing, navigation, session management, media options, extraction,…",
    "sections": [
      {
        "heading": "Introduction",
        "content": "In Crawl4AI's **latest** configuration model, nearly all parameters that once went directly to `arun()` are now part of **`CrawlerRunConfig`** . When calling `arun()`, you provide:\n\nBelow is an…",
        "code_blocks": [
          {
            "language": "python",
            "code": "await crawler.arun(\n    url=\"https://example.com\",  \n    config=my_run_config\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1. Core Usage",
        "content": "**Key Fields**:\n- `verbose=True` logs each crawl step. \n- `cache_mode` decides how to read/write the local crawl cache.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    run_config = CrawlerRunConfig(\n        verbose=True,            # Detailed logging…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Cache Control",
        "content": "**`cache_mode`** (default: `CacheMode.ENABLED`)\n\nUse a built-in enum from `CacheMode`:\n\n- `ENABLED`: Normal caching—reads if available, writes if missing.\n- `DISABLED`: No caching—always refetch…",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    cache_mode=CacheMode.BYPASS\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.1 Text Processing",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    word_count_threshold=10,   # Ignore text blocks <10 words\n    only_text=False,           # If True, tries to remove non-text elements\n    keep_data_attributes=False…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.2 Content Selection",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    css_selector=\".main-content\",  # Focus on .main-content region only\n    excluded_tags=[\"form\", \"nav\"], # Remove entire tag blocks\n    remove_forms=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.3 Link Handling",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    exclude_external_links=True,         # Remove external links from final content\n    exclude_social_media_links=True,     # Remove links to known social sites…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.4 Media Filtering",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    exclude_external_images=True  # Strip images from other domains\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.1 Basic Browser Flow",
        "content": "**Key Fields**:\n- `wait_for`:\n  - `\"css:selector\"` or\n  - `\"js:() => boolean\"`\n  e.g. `js:() => document.querySelectorAll('.item').length > 10`.\n- `mean_delay` & `max_range`: define random delays for…",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    wait_for=\"css:.dynamic-content\", # Wait for .dynamic-content\n    delay_before_return_html=2.0,    # Wait 2s before capturing final HTML\n    page_timeout=60000,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.2 JavaScript Execution",
        "content": "- `js_code` can be a single string or a list of strings.\n- `js_only=True` means “I’m continuing in the same session with new JS steps, no new full navigation.”",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    js_code=[\n        \"window.scrollTo(0, document.body.scrollHeight);\",\n        \"document.querySelector('.load-more')?.click();\"\n    ],\n    js_only=False\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.3 Anti-Bot",
        "content": "- `magic=True` tries multiple stealth features. \n- `simulate_user=True` mimics mouse movements or random delays. \n- `override_navigator=True` fakes some navigator properties (like user agent checks).",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    magic=True,\n    simulate_user=True,\n    override_navigator=True\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Session Management",
        "content": "If re-used in subsequent `arun()` calls, the same tab/page context is continued (helpful for multi-step tasks or stateful browsing).",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    session_id=\"my_session123\"\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Screenshot, PDF & Media Options",
        "content": "**Where they appear**:\n- `result.screenshot` → Base64 screenshot string.\n- `result.pdf` → Byte array with PDF data.",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    screenshot=True,             # Grab a screenshot as base64\n    screenshot_wait_for=1.0,     # Wait 1s before capturing\n    pdf=True,                    # Also…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Extraction Strategy",
        "content": "The extracted data will appear in `result.extracted_content`.",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    extraction_strategy=my_css_or_llm_strategy\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Comprehensive Example",
        "content": "Below is a snippet combining many parameters:\n\n**What we covered**:\n1. **Crawling** the main content region, ignoring external links. \n2. Running **JavaScript** to click “.show-more”. \n3. **Waiting**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    # Example schema\n    schema = {\n        \"name\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "9. Best Practices",
        "content": "1. **Use `BrowserConfig` for global browser** settings (headless, user agent). \n2. **Use `CrawlerRunConfig`** to handle the **specific** crawl needs: content filtering, caching, JS, screenshot,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "10. Conclusion",
        "content": "All parameters that used to be direct arguments to `arun()` now belong in **`CrawlerRunConfig`** . This approach:\n\n- Makes code **clearer** and **more maintainable**.\n- Minimizes confusion about…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "arun",
      "CrawlerRunConfig",
      "caching",
      "content processing",
      "JavaScript",
      "screenshot",
      "PDF",
      "extraction",
      "session management",
      "anti-bot",
      "best practices"
    ],
    "prerequisites": [],
    "_content_hash": "b87bf8b18e7571949d4a839f34c565f4d7e1bf5d3fe619ca5ad0f3a7cd9f1f50",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/arun_many/",
    "title": "arun_many()",
    "type": "api",
    "summary": "Reference for the arun_many() function in Crawl4AI, which crawls multiple URLs concurrently or in batches, with support for dispatchers, streaming, and per-URL configurations.",
    "sections": [
      {
        "heading": "Function Signature",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def arun_many(\n    urls: Union[List[str], List[Any]],\n    config: Optional[Union[CrawlerRunConfig, List[CrawlerRunConfig]]] = None,\n    dispatcher: Optional[BaseDispatcher] = None,\n    ...\n) ->…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Differences from arun()",
        "content": "1. **Multiple URLs**:\n- Instead of crawling a single URL, you pass a list of them (strings or tasks).\n- The function returns `RunManyReturn` which contains either a **list** of `CrawlResult` or an…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Example (Batch Mode)",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Minimal usage: The default dispatcher will be used\nresults = await crawler.arun_many(\n    urls=[\"https://site1.com\", \"https://site2.com\"],\n    config=CrawlerRunConfig(stream=False)  # Default…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Streaming Example",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    stream=True,  # Enable streaming mode\n    cache_mode=CacheMode.BYPASS\n)\n\n# Process results as they complete\nasync for result in await crawler.arun_many(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "With a Custom Dispatcher",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "dispatcher = MemoryAdaptiveDispatcher(\n    memory_threshold_percent=70.0,\n    max_session_permit=10\n)\nresults = await crawler.arun_many(\n    urls=[\"https://site1.com\", \"https://site2.com\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "URL-Specific Configurations",
        "content": "Instead of using one config for all URLs, provide a list of configs with `url_matcher` patterns:\n\n**URL Matching Features**:\n- **String patterns**: `\"*.pdf\"`, `\"*/blog/*\"`, `\"*python.org*\"`\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig, MatchMode\nfrom crawl4ai.processors.pdf import PDFContentScrapingStrategy\nfrom crawl4ai.extraction_strategy import JsonCssExtractionStrategy\nfrom…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Return Value",
        "content": "Returns a **`RunManyReturn`** object which contains either a **list** of [`CrawlResult`](../crawl-result/) objects, or an **async generator** if streaming is enabled. You can iterate to check…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Dispatcher Reference",
        "content": "- **`MemoryAdaptiveDispatcher`** : Dynamically manages concurrency based on system memory usage.\n- **`SemaphoreDispatcher`** : Fixed concurrency limit, simpler but less adaptive.\n\nFor advanced usage…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Common Pitfalls",
        "content": "1. **Large Lists** : If you pass thousands of URLs, be mindful of memory or rate-limits. A dispatcher can help.\n2. **Session Reuse** : If you need specialized logins or persistent contexts, ensure…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "Use `arun_many()` when you want to **crawl multiple URLs** simultaneously or in controlled parallel tasks. If you need advanced concurrency features (like memory-based adaptive throttling or complex…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "urls",
        "type": "Union[List[str], List[Any]]",
        "description": "A list of URLs (or tasks) to crawl.",
        "default": "",
        "required": true
      },
      {
        "name": "config",
        "type": "Optional[Union[CrawlerRunConfig, List[CrawlerRunConfig]]]",
        "description": "Either a single CrawlerRunConfig applying to all URLs, or a list of CrawlerRunConfig objects with url_matcher patterns.",
        "default": "None",
        "required": false
      },
      {
        "name": "dispatcher",
        "type": "Optional[BaseDispatcher]",
        "description": "A concurrency controller (e.g. MemoryAdaptiveDispatcher).",
        "default": "None",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "arun_many",
      "crawling",
      "concurrency",
      "dispatcher",
      "streaming",
      "batch"
    ],
    "prerequisites": [],
    "_content_hash": "c137298e045ce75a16e03f85ab44dd5d058c49a604f776a35fac7467de005044",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/async-webcrawler/",
    "title": "AsyncWebCrawler - Crawl4AI Documentation (v0.9.x)",
    "type": "reference",
    "summary": "Extraction fallback content.",
    "sections": [
      {
        "heading": "AsyncWebCrawler - Crawl4AI Documentation (v0.9.x)",
        "content": "\n\n\n##### AsyncWebCrawler\n\n\n\n\nThe  **`AsyncWebCrawler`**  is the core class for asynchronous web crawling in Crawl4AI. You typically create it  **once** , optionally customize it with a  **`BrowserConfig`**  (e.g., headless, user agent), then  **run**  multiple  **`arun()`**  calls with different  **`CrawlerRunConfig`**  objects.\n\n\n\n\n **Recommended usage** :\n\n\n\n\n1.  **Create**  a `BrowserConfig` for global browser settings.  \n\n\n\n\n2.  **Instantiate**  `AsyncWebCrawler(config=browser_config)`.  \n\n\n\n\n3.  **Use**  the crawler in an async context manager (`async with`) or manage start/close manually.  \n\n\n\n\n4.  **Call**  `arun(url, config=crawler_run_config)` for each page you want.\n\n\n\n\n\n##### 1. Constructor Overview\n\n\n\n\n\n **Notes** :\n\n\n\n\n\n\n- **Legacy**  parameters like `always_bypass_cache` remain for backward compatibility, but prefer to set  **caching**  in `CrawlerRunConfig`.\n\n\n\n\n\n\n##### 2. Lifecycle: Start/Close or Context Manager\n\n\n\n\n###### 2.1 Context Manager (Recommended)\n\n\n\n\n\nWhen the `async with` block ends, the crawler cleans up (closes the browser, etc.).\n\n\n\n\n###### 2.2 Manual Start & Close\n\n\n\n\n\nUse this style if you have a  **long-running**  application or need full control of the crawler’s lifecycle.\n\n\n\n\n\n##### 3. Primary Method: `arun()`\n\n\n\n\n\n###### 3.1 New Approach\n\n\n\n\nYou pass a `CrawlerRunConfig` object that sets up everything about a crawl—content filtering, caching, session reuse, JS code, screenshots, etc.\n\n\n\n\n\n###### 3.2 Legacy Parameters Still Accepted\n\n\n\n\nFor  **backward**  compatibility, `arun()` can still accept direct arguments like `css_selector=...`, `word_count_threshold=...`, etc., but we strongly advise migrating them into a  **`CrawlerRunConfig`** .\n\n\n\n\n\n##### 4. Batch Processing: `arun_many()`\n\n\n\n\n\n###### 4.1 Resource-Aware Crawling\n\n\n\n\nThe `arun_many()` method now uses an intelligent dispatcher that:\n\n\n\n\n\n\n- Monitors system memory usage\n\n- Implements adaptive rate limiting\n\n- Provides detailed progress monitoring\n\n- Manages concurrent crawls efficiently\n\n\n\n\n\n###### 4.2 Example Usage\n\n\n\n\nCheck page [Multi-url Crawling](../../advanced/multi-url-crawling/) for a detailed example of how to use `arun_many()`.\n\n\n\n\n\n **Explanation** :\n\n\n\n\n\n\n- We define a  **`BrowserConfig`**  with Firefox, no headless, and `verbose=True`.\n\n- We define a  **`CrawlerRunConfig`**  that  **bypasses cache** , uses a  **CSS**  extraction schema, has a `word_count_threshold=15`, etc.\n\n- We pass them to `AsyncWebCrawler(config=...)` and `arun(url=..., config=...)`.\n\n\n\n\n\n\n##### 7. Best Practices & Migration Notes\n\n\n\n\n1.  **Use**  `BrowserConfig` for  **global**  settings about the browser’s environment.  \n2.  **Use**  `CrawlerRunConfig` for  **per-crawl**  logic (caching, content filtering, extraction strategies, wait conditions).  \n3.  **Avoid**  legacy parameters like `css_selector` or `word_count_threshold` directly in `arun()`. Instead:\n\n\n\n\n\n4.  **Context Manager**  usage is simplest unless you want a persistent crawler across many calls.\n\n\n\n\n\n##### 8. Summary\n\n\n\n\n **AsyncWebCrawler**  is your entry point to asynchronous crawling:\n\n\n\n\n\n\n- **Constructor**  accepts  **`BrowserConfig`**  (or defaults).\n\n- **`arun(url, config=CrawlerRunConfig)`**  is the main method for single-page crawls.\n\n- **`arun_many(urls, config=CrawlerRunConfig)`**  handles concurrency across multiple URLs.\n\n- For advanced lifecycle control, use `start()` and `close()` explicitly.\n\n\n\n\n\n **Migration** :  \n\n\n\n\n\n\n- If you used `AsyncWebCrawler(browser_type=\"chromium\", css_selector=\"...\")`, move browser settings to `BrowserConfig(...)` and content/crawl logic to `CrawlerRunConfig(...)`.\n\n\n\n\n\nThis modular approach ensures your code is  **clean** ,  **scalable** , and  **easy to maintain** . For any advanced or rarely used parameters, see the [BrowserConfig docs](../parameters/).\n\n\n",
        "code_blocks": [
          {
            "language": "python",
            "code": "class AsyncWebCrawler:\n    def __init__(\n        self,\n        crawler_strategy: Optional[AsyncCrawlerStrategy] = None,\n        config: Optional[BrowserConfig] = None,\n        always_bypass_cache: bool = False,           # deprecated\n        always_by_pass_cache: Optional[bool] = None, # also deprecated\n        base_directory: str = ...,\n        thread_safe: bool = False,\n        **kwargs,\n    ):\n        \"\"\"\n        Create an AsyncWebCrawler instance.\n\n        Args:\n            crawler_strategy: \n                (Advanced) Provide a custom crawler strategy if needed.\n            config: \n                A BrowserConfig object specifying how the browser is set up.\n            always_bypass_cache: \n                (Deprecated) Use CrawlerRunConfig.cache_mode instead.\n            base_directory:     \n                Folder for storing caches/logs (if relevant).\n            thread_safe: \n                If True, attempts some concurrency safeguards. Usually False.\n            **kwargs: \n                Additional legacy or debugging parameters.\n        \"\"\"\n    )\n\n### Typical Initialization\n\n```python\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig\n\nbrowser_cfg = BrowserConfig(\n    browser_type=\"chromium\",\n    headless=True,\n    verbose=True\n)\n\ncrawler = AsyncWebCrawler(config=browser_cfg)",
            "filename": ""
          },
          {
            "language": "csharp",
            "code": "async with AsyncWebCrawler(config=browser_cfg) as crawler:\n    result = await crawler.arun(\"https://example.com\")\n    # The crawler automatically starts/closes resources",
            "filename": ""
          },
          {
            "language": "csharp",
            "code": "crawler = AsyncWebCrawler(config=browser_cfg)\nawait crawler.start()\n\nresult1 = await crawler.arun(\"https://example.com\")\nresult2 = await crawler.arun(\"https://another.com\")\n\nawait crawler.close()",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def arun(\n    self,\n    url: str,\n    config: Optional[CrawlerRunConfig] = None,\n    # Legacy parameters for backward compatibility...\n) -> RunManyReturn:\n    ...",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import CrawlerRunConfig, CacheMode\n\nrun_cfg = CrawlerRunConfig(\n    cache_mode=CacheMode.BYPASS,\n    css_selector=\"main.article\",\n    word_count_threshold=10,\n    screenshot=True\n)\n\nasync with AsyncWebCrawler(config=browser_cfg) as crawler:\n    result = await crawler.arun(\"https://example.com/news\", config=run_cfg)\n    print(\"Crawled HTML length:\", len(result.cleaned_html))\n    if result.screenshot:\n        print(\"Screenshot base64 length:\", len(result.screenshot))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def arun_many(\n    self,\n    urls: List[str],\n    config: Optional[CrawlerRunConfig] = None,\n    # Legacy parameters maintained for backwards compatibility...\n) -> RunManyReturn:\n    \"\"\"\n    Process multiple URLs with intelligent rate limiting and resource monitoring.\n    \"\"\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "### 4.3 Key Features\n\n1. **Rate Limiting**\n\n   - Automatic delay between requests\n   - Exponential backoff on rate limit detection\n   - Domain-specific rate limiting\n   - Configurable retry strategy\n\n2. **Resource Monitoring**\n\n   - Memory usage tracking\n   - Adaptive concurrency based on system load\n   - Automatic pausing when resources are constrained\n\n3. **Progress Monitoring**\n\n   - Detailed or aggregated progress display\n   - Real-time status updates\n   - Memory usage statistics\n\n4. **Error Handling**\n\n   - Graceful handling of rate limits\n   - Automatic retries with backoff\n   - Detailed error reporting\n\n---\n\n## 5. `CrawlResult` Output\n\nEach `arun()` returns a **`CrawlResult`** containing:\n\n- `url`: Final URL (if redirected).\n- `html`: Original HTML.\n- `cleaned_html`: Sanitized HTML.\n- `markdown_v2`: Removed in v0.5. Accessing it raises `AttributeError`; use `markdown`.\n- `extracted_content`: If an extraction strategy was used (JSON for CSS/LLM strategies).\n- `screenshot`, `pdf`: If screenshots/PDF requested.\n- `media`, `links`: Information about discovered images/links.\n- `success`, `error_message`: Status info.\n\nFor details, see [CrawlResult doc](./crawl-result.md).\n\n---\n\n## 6. Quick Example\n\nBelow is an example hooking it all together:\n\n```python\nimport asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\nimport json\n\nasync def main():\n    # 1. Browser config\n    browser_cfg = BrowserConfig(\n        browser_type=\"firefox\",\n        headless=False,\n        verbose=True\n    )\n\n    # 2. Run config\n    schema = {\n        \"name\": \"Articles\",\n        \"baseSelector\": \"article.post\",\n        \"fields\": [\n            {\n                \"name\": \"title\", \n                \"selector\": \"h2\", \n                \"type\": \"text\"\n            },\n            {\n                \"name\": \"url\", \n                \"selector\": \"a\", \n                \"type\": \"attribute\", \n                \"attribute\": \"href\"\n            }\n        ]\n    }\n\n    run_cfg = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        extraction_strategy=JsonCssExtractionStrategy(schema),\n        word_count_threshold=15,\n        remove_overlay_elements=True,\n        wait_for=\"css:.post\"  # Wait for posts to appear\n    )\n\n    async with AsyncWebCrawler(config=browser_cfg) as crawler:\n        result = await crawler.arun(\n            url=\"https://example.com/blog\",\n            config=run_cfg\n        )\n\n        if result.success:\n            print(\"Cleaned HTML length:\", len(result.cleaned_html))\n            if result.extracted_content:\n                articles = json.loads(result.extracted_content)\n                print(\"Extracted articles:\", articles[:2])\n        else:\n            print(\"Error:\", result.error_message)\n\nasyncio.run(main())",
            "filename": ""
          },
          {
            "language": "ini",
            "code": "run_cfg = CrawlerRunConfig(css_selector=\".main-content\", word_count_threshold=20)\nresult = await crawler.arun(url=\"...\", config=run_cfg)",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [],
    "prerequisites": [],
    "_content_hash": "8a6384fe9b45b4de2464b9233f32722d567cbe227ca8851933ca86afc69a2d6e",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/c4a-script-reference/",
    "title": "C4A-Script API Reference",
    "type": "reference",
    "summary": "Complete reference for all C4A-Script commands, syntax, and advanced features, including navigation, waiting, mouse, keyboard, control flow, variables, procedures, and integration with Crawl4AI.",
    "sections": [
      {
        "heading": "Command Categories",
        "content": "Complete reference for all C4A-Script commands, syntax, and advanced features.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🧭 Navigation Commands",
        "content": "Navigate between pages and manage browser history.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`GO <url>`",
        "content": "Navigate to a specific URL.\n\n**Syntax:**\n\n```\nGO <url>\n```\n\n**Parameters:**\n- `url` - Target URL (string)\n\n**Examples:**\n\n```\nGO https://example.com\nGO https://api.example.com/login\nGO…",
        "code_blocks": [
          {
            "language": "",
            "code": "GO <url>",
            "filename": ""
          },
          {
            "language": "",
            "code": "GO https://example.com\nGO https://api.example.com/login\nGO /relative/path",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`RELOAD`",
        "content": "Refresh the current page.\n\n**Syntax:**\n\n```\nRELOAD\n```\n\n**Examples:**\n\n```\nRELOAD\n```\n\n**Notes:**\n- Equivalent to pressing F5 or clicking browser refresh\n- Waits for page reload to complete\n-…",
        "code_blocks": [
          {
            "language": "",
            "code": "RELOAD",
            "filename": ""
          },
          {
            "language": "",
            "code": "RELOAD",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`BACK`",
        "content": "Navigate back in browser history.\n\n**Syntax:**\n\n```\nBACK\n```\n\n**Examples:**\n\n```\nBACK\n```\n\n**Notes:**\n- Equivalent to clicking browser back button\n- Does nothing if no previous page exists\n- Waits…",
        "code_blocks": [
          {
            "language": "",
            "code": "BACK",
            "filename": ""
          },
          {
            "language": "",
            "code": "BACK",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`FORWARD`",
        "content": "Navigate forward in browser history.\n\n**Syntax:**\n\n```\nFORWARD\n```\n\n**Examples:**\n\n```\nFORWARD\n```\n\n**Notes:**\n- Equivalent to clicking browser forward button\n- Does nothing if no next page exists\n-…",
        "code_blocks": [
          {
            "language": "",
            "code": "FORWARD",
            "filename": ""
          },
          {
            "language": "",
            "code": "FORWARD",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "⏱️ Wait Commands",
        "content": "Control timing and synchronization with page elements.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`WAIT <time>`",
        "content": "Wait for a specified number of seconds.\n\n**Syntax:**\n\n```\nWAIT <seconds>\n```\n\n**Parameters:**\n- `seconds` - Number of seconds to wait (number)\n\n**Examples:**\n\n```\nWAIT 3\nWAIT 1.5\nWAIT…",
        "code_blocks": [
          {
            "language": "",
            "code": "WAIT <seconds>",
            "filename": ""
          },
          {
            "language": "",
            "code": "WAIT 3\nWAIT 1.5\nWAIT 10",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`WAIT <selector> <timeout>`",
        "content": "Wait for an element to appear on the page.\n\n**Syntax:**\n\n```\nWAIT `<selector>` <timeout>\n```\n\n**Parameters:**\n- `selector` - CSS selector for the element (string in backticks)\n- `timeout` - Maximum…",
        "code_blocks": [
          {
            "language": "",
            "code": "WAIT `<selector>` <timeout>",
            "filename": ""
          },
          {
            "language": "",
            "code": "WAIT `#content` 10\nWAIT `.loading-spinner` 5\nWAIT `button[type=\"submit\"]` 15\nWAIT `.results .item:first-child` 8",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`WAIT \"<text>\" <timeout>`",
        "content": "Wait for specific text to appear anywhere on the page.\n\n**Syntax:**\n\n```\nWAIT \"<text>\" <timeout>\n```\n\n**Parameters:**\n- `text` - Text content to wait for (string in quotes)\n- `timeout` - Maximum…",
        "code_blocks": [
          {
            "language": "",
            "code": "WAIT \"<text>\" <timeout>",
            "filename": ""
          },
          {
            "language": "",
            "code": "WAIT \"Loading complete\" 10\nWAIT \"Welcome back\" 5\nWAIT \"Search results\" 15",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "🖱️ Mouse Commands",
        "content": "Simulate mouse interactions and movements.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`CLICK <selector>`",
        "content": "Click on an element specified by CSS selector.\n\n**Syntax:**\n\n```\nCLICK `<selector>`\n```\n\n**Parameters:**\n- `selector` - CSS selector for the element (string in backticks)\n\n**Examples:**\n\n```\nCLICK…",
        "code_blocks": [
          {
            "language": "",
            "code": "CLICK `<selector>`",
            "filename": ""
          },
          {
            "language": "",
            "code": "CLICK `#submit-button`\nCLICK `.menu-item:first-child`\nCLICK `button[data-action=\"save\"]`\nCLICK `a[href=\"/dashboard\"]`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`CLICK <x> <y>`",
        "content": "Click at specific coordinates on the page.\n\n**Syntax:**\n\n```\nCLICK <x> <y>\n```\n\n**Parameters:**\n- `x` - X coordinate in pixels (number)\n- `y` - Y coordinate in pixels…",
        "code_blocks": [
          {
            "language": "",
            "code": "CLICK <x> <y>",
            "filename": ""
          },
          {
            "language": "",
            "code": "CLICK 100 200\nCLICK 500 300\nCLICK 0 0",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`DOUBLE_CLICK <selector>`",
        "content": "Double-click on an element.\n\n**Syntax:**\n\n```\nDOUBLE_CLICK `<selector>`\n```\n\n**Parameters:**\n- `selector` - CSS selector for the element (string in backticks)\n\n**Examples:**\n\n```\nDOUBLE_CLICK…",
        "code_blocks": [
          {
            "language": "",
            "code": "DOUBLE_CLICK `<selector>`",
            "filename": ""
          },
          {
            "language": "",
            "code": "DOUBLE_CLICK `.file-icon`\nDOUBLE_CLICK `#editable-cell`\nDOUBLE_CLICK `.expandable-item`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`RIGHT_CLICK <selector>`",
        "content": "Right-click on an element to open context menu.\n\n**Syntax:**\n\n```\nRIGHT_CLICK `<selector>`\n```\n\n**Parameters:**\n- `selector` - CSS selector for the element (string in…",
        "code_blocks": [
          {
            "language": "",
            "code": "RIGHT_CLICK `<selector>`",
            "filename": ""
          },
          {
            "language": "",
            "code": "RIGHT_CLICK `#context-target`\nRIGHT_CLICK `.menu-trigger`\nRIGHT_CLICK `img.thumbnail`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`SCROLL <direction> <amount>`",
        "content": "Scroll the page in a specified direction.\n\n**Syntax:**\n\n```\nSCROLL <direction> <amount>\n```\n\n**Parameters:**\n- `direction` - Direction to scroll: `UP`, `DOWN`, `LEFT`, `RIGHT`\n- `amount` - Number of…",
        "code_blocks": [
          {
            "language": "",
            "code": "SCROLL <direction> <amount>",
            "filename": ""
          },
          {
            "language": "",
            "code": "SCROLL DOWN 500\nSCROLL UP 200\nSCROLL LEFT 100\nSCROLL RIGHT 300",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`MOVE <x> <y>`",
        "content": "Move mouse cursor to specific coordinates.\n\n**Syntax:**\n\n```\nMOVE <x> <y>\n```\n\n**Parameters:**\n- `x` - X coordinate in pixels (number)\n- `y` - Y coordinate in pixels (number)\n\n**Examples:**\n\n```\nMOVE…",
        "code_blocks": [
          {
            "language": "",
            "code": "MOVE <x> <y>",
            "filename": ""
          },
          {
            "language": "",
            "code": "MOVE 200 100\nMOVE 500 400",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`DRAG <x1> <y1> <x2> <y2>`",
        "content": "Drag from one point to another.\n\n**Syntax:**\n\n```\nDRAG <x1> <y1> <x2> <y2>\n```\n\n**Parameters:**\n- `x1`, `y1` - Starting coordinates (numbers)\n- `x2`, `y2` - Ending coordinates…",
        "code_blocks": [
          {
            "language": "",
            "code": "DRAG <x1> <y1> <x2> <y2>",
            "filename": ""
          },
          {
            "language": "",
            "code": "DRAG 100 100 500 300\nDRAG 0 200 400 200",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "⌨️ Keyboard Commands",
        "content": "Simulate keyboard input and key presses.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`TYPE \"<text>\"`",
        "content": "Type text into the currently focused element.\n\n**Syntax:**\n\n```\nTYPE \"<text>\"\n```\n\n**Parameters:**\n- `text` - Text to type (string in quotes)\n\n**Examples:**\n\n```\nTYPE \"Hello, World!\"\nTYPE…",
        "code_blocks": [
          {
            "language": "",
            "code": "TYPE \"<text>\"",
            "filename": ""
          },
          {
            "language": "",
            "code": "TYPE \"Hello, World!\"\nTYPE \"user@example.com\"\nTYPE \"Password123!\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`TYPE $<variable>`",
        "content": "Type the value of a variable.\n\n**Syntax:**\n\n```\nTYPE $<variable>\n```\n\n**Parameters:**\n- `variable` - Variable name (without quotes)\n\n**Examples:**\n\n```\nSETVAR email = \"user@example.com\"\nTYPE…",
        "code_blocks": [
          {
            "language": "",
            "code": "TYPE $<variable>",
            "filename": ""
          },
          {
            "language": "",
            "code": "SETVAR email = \"user@example.com\"\nTYPE $email",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`PRESS <key>`",
        "content": "Press and release a special key.\n\n**Syntax:**\n\n```\nPRESS <key>\n```\n\n**Parameters:**\n- `key` - Key name (see supported keys below)\n\n**Supported Keys:**\n- `Tab`, `Enter`, `Escape`, `Space`\n- `ArrowUp`,…",
        "code_blocks": [
          {
            "language": "",
            "code": "PRESS <key>",
            "filename": ""
          },
          {
            "language": "",
            "code": "PRESS Tab\nPRESS Enter\nPRESS Escape\nPRESS ArrowDown",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`KEY_DOWN <key>`",
        "content": "Hold down a modifier key.\n\n**Syntax:**\n\n```\nKEY_DOWN <key>\n```\n\n**Parameters:**\n- `key` - Modifier key: `Shift`, `Control`, `Alt`, `Meta`\n\n**Examples:**\n\n```\nKEY_DOWN Shift\nKEY_DOWN…",
        "code_blocks": [
          {
            "language": "",
            "code": "KEY_DOWN <key>",
            "filename": ""
          },
          {
            "language": "",
            "code": "KEY_DOWN Shift\nKEY_DOWN Control",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`KEY_UP <key>`",
        "content": "Release a modifier key.\n\n**Syntax:**\n\n```\nKEY_UP <key>\n```\n\n**Parameters:**\n- `key` - Modifier key: `Shift`, `Control`, `Alt`, `Meta`\n\n**Examples:**\n\n```\nKEY_UP Shift\nKEY_UP Control\n```\n\n**Notes:**\n-…",
        "code_blocks": [
          {
            "language": "",
            "code": "KEY_UP <key>",
            "filename": ""
          },
          {
            "language": "",
            "code": "KEY_UP Shift\nKEY_UP Control",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`CLEAR <selector>`",
        "content": "Clear the content of an input field.\n\n**Syntax:**\n\n```\nCLEAR `<selector>`\n```\n\n**Parameters:**\n- `selector` - CSS selector for input element (string in backticks)\n\n**Examples:**\n\n```\nCLEAR…",
        "code_blocks": [
          {
            "language": "",
            "code": "CLEAR `<selector>`",
            "filename": ""
          },
          {
            "language": "",
            "code": "CLEAR `#search-box`\nCLEAR `input[name=\"email\"]`\nCLEAR `.form-input:first-child`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`SET <selector> \"<value>\"`",
        "content": "Set the value of an input field directly.\n\n**Syntax:**\n\n```\nSET `<selector>` \"<value>\"\n```\n\n**Parameters:**\n- `selector` - CSS selector for input element (string in backticks)\n- `value` - Value to…",
        "code_blocks": [
          {
            "language": "",
            "code": "SET `<selector>` \"<value>\"",
            "filename": ""
          },
          {
            "language": "",
            "code": "SET `#email` \"user@example.com\"\nSET `#age` \"25\"\nSET `textarea#message` \"Hello, this is a test message.\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "🔀 Control Flow Commands",
        "content": "Add conditional logic and loops to your scripts.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`IF (EXISTS <selector>) THEN <command>`",
        "content": "Execute command if element exists.\n\n**Syntax:**\n\n```\nIF (EXISTS `<selector>`) THEN <command>\n```\n\n**Parameters:**\n- `selector` - CSS selector to check (string in backticks)\n- `command` - Command to…",
        "code_blocks": [
          {
            "language": "",
            "code": "IF (EXISTS `<selector>`) THEN <command>",
            "filename": ""
          },
          {
            "language": "",
            "code": "IF (EXISTS `.cookie-banner`) THEN CLICK `.accept-cookies`\nIF (EXISTS `#popup-modal`) THEN CLICK `.close-button`\nIF (EXISTS `.error-message`) THEN RELOAD",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`IF (EXISTS <selector>) THEN <command> ELSE <command>`",
        "content": "Execute command based on element existence.\n\n**Syntax:**\n\n```\nIF (EXISTS `<selector>`) THEN <command> ELSE <command>\n```\n\n**Parameters:**\n- `selector` - CSS selector to check (string in backticks)\n-…",
        "code_blocks": [
          {
            "language": "",
            "code": "IF (EXISTS `<selector>`) THEN <command> ELSE <command>",
            "filename": ""
          },
          {
            "language": "",
            "code": "IF (EXISTS `.user-menu`) THEN CLICK `.logout` ELSE CLICK `.login`\nIF (EXISTS `.loading`) THEN WAIT 5 ELSE CLICK `#continue`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`IF (NOT EXISTS <selector>) THEN <command>`",
        "content": "Execute command if element does not exist.\n\n**Syntax:**\n\n```\nIF (NOT EXISTS `<selector>`) THEN <command>\n```\n\n**Parameters:**\n- `selector` - CSS selector to check (string in backticks)\n- `command` -…",
        "code_blocks": [
          {
            "language": "",
            "code": "IF (NOT EXISTS `<selector>`) THEN <command>",
            "filename": ""
          },
          {
            "language": "",
            "code": "IF (NOT EXISTS `.logged-in`) THEN GO /login\nIF (NOT EXISTS `.results`) THEN CLICK `#search-button`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`IF (<javascript>) THEN <command>`",
        "content": "Execute command based on JavaScript condition.\n\n**Syntax:**\n\n```\nIF (`<javascript>`) THEN <command>\n```\n\n**Parameters:**\n- `javascript` - JavaScript expression that returns boolean (string in…",
        "code_blocks": [
          {
            "language": "",
            "code": "IF (`<javascript>`) THEN <command>",
            "filename": ""
          },
          {
            "language": "",
            "code": "IF (`window.innerWidth < 768`) THEN CLICK `.mobile-menu`\nIF (`document.readyState === \"complete\"`) THEN CLICK `#start`\nIF (`localStorage.getItem(\"user\")`) THEN GO /dashboard",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`REPEAT (<command>, <count>)`",
        "content": "Repeat a command a specific number of times.\n\n**Syntax:**\n\n```\nREPEAT (<command>, <count>)\n```\n\n**Parameters:**\n- `command` - Command to repeat\n- `count` - Number of times to repeat…",
        "code_blocks": [
          {
            "language": "",
            "code": "REPEAT (<command>, <count>)",
            "filename": ""
          },
          {
            "language": "",
            "code": "REPEAT (SCROLL DOWN 300, 5)\nREPEAT (PRESS Tab, 3)\nREPEAT (CLICK `.load-more`, 10)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`REPEAT (<command>, <condition>)`",
        "content": "Repeat a command while condition is true.\n\n**Syntax:**\n\n```\nREPEAT (<command>, `<condition>`)\n```\n\n**Parameters:**\n- `command` - Command to repeat\n- `condition` - JavaScript condition to check…",
        "code_blocks": [
          {
            "language": "",
            "code": "REPEAT (<command>, `<condition>`)",
            "filename": ""
          },
          {
            "language": "",
            "code": "REPEAT (SCROLL DOWN 500, `document.querySelector(\".load-more\")`)\nREPEAT (PRESS ArrowDown, `window.scrollY < document.body.scrollHeight`)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "💾 Variables and Data",
        "content": "Store and manipulate data within scripts.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`SETVAR <name> = \"<value>\"`",
        "content": "Create or update a variable.\n\n**Syntax:**\n\n```\nSETVAR <name> = \"<value>\"\n```\n\n**Parameters:**\n- `name` - Variable name (alphanumeric, underscore)\n- `value` - Variable value (string in…",
        "code_blocks": [
          {
            "language": "",
            "code": "SETVAR <name> = \"<value>\"",
            "filename": ""
          },
          {
            "language": "",
            "code": "SETVAR username = \"john@example.com\"\nSETVAR password = \"secret123\"\nSETVAR base_url = \"https://api.example.com\"\nSETVAR counter = \"0\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`EVAL <javascript>`",
        "content": "Execute arbitrary JavaScript code.\n\n**Syntax:**\n\n```\nEVAL `<javascript>`\n```\n\n**Parameters:**\n- `javascript` - JavaScript code to execute (string in backticks)\n\n**Examples:**\n\n```\nEVAL…",
        "code_blocks": [
          {
            "language": "",
            "code": "EVAL `<javascript>`",
            "filename": ""
          },
          {
            "language": "",
            "code": "EVAL `console.log(\"Script started\")`\nEVAL `window.scrollTo(0, 0)`\nEVAL `localStorage.setItem(\"test\", \"value\")`\nEVAL `document.title = \"Automated Test\"`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "📝 Comments and Documentation",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`# <comment>`",
        "content": "Add comments to scripts for documentation.\n\n**Syntax:**\n\n```\n# <comment text>\n```\n\n**Examples:**\n\n```\n# This script logs into the application\n# Step 1: Navigate to login page\nGO /login\n\n# Step 2:…",
        "code_blocks": [
          {
            "language": "",
            "code": "# <comment text>",
            "filename": ""
          },
          {
            "language": "",
            "code": "# This script logs into the application\n# Step 1: Navigate to login page\nGO /login\n\n# Step 2: Fill credentials\nTYPE \"user@example.com\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "🔧 Procedures (Advanced)",
        "content": "Define reusable command sequences.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "`PROC <name> ... ENDPROC`",
        "content": "Define a reusable procedure.\n\n**Syntax:**\n\n```\nPROC <name>\n  <commands>\nENDPROC\n```\n\n**Parameters:**\n- `name` - Procedure name (alphanumeric, underscore)\n- `commands` - Commands to include in…",
        "code_blocks": [
          {
            "language": "",
            "code": "PROC <name>\n  <commands>\nENDPROC",
            "filename": ""
          },
          {
            "language": "",
            "code": "PROC login\n  CLICK `#email`\n  TYPE $email\n  CLICK `#password`\n  TYPE $password\n  CLICK `#submit`\nENDPROC\n\nPROC handle_popups\n  IF (EXISTS `.cookie-banner`) THEN CLICK `.accept`\n  IF (EXISTS…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`<procedure_name>`",
        "content": "Call a defined procedure.\n\n**Syntax:**\n\n```\n<procedure_name>\n```\n\n**Examples:**\n\n```\n# Define procedure first\nPROC setup\n  GO /login\n  WAIT `#form` 5\nENDPROC\n\n# Call…",
        "code_blocks": [
          {
            "language": "",
            "code": "<procedure_name>",
            "filename": ""
          },
          {
            "language": "",
            "code": "# Define procedure first\nPROC setup\n  GO /login\n  WAIT `#form` 5\nENDPROC\n\n# Call procedure\nsetup\nlogin",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Error Handling Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Always Use Waits",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Bad - element might not be ready\nCLICK `#button`\n\n# Good - wait for element first\nWAIT `#button` 5\nCLICK `#button`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Handle Optional Elements",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Check before interacting\nIF (EXISTS `.popup`) THEN CLICK `.close`\nIF (EXISTS `.cookie-banner`) THEN CLICK `.accept`\n\n# Then proceed with main flow\nCLICK `#main-action`",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Use Descriptive Variables",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Set up reusable data\nSETVAR admin_email = \"admin@company.com\"\nSETVAR test_password = \"TestPass123!\"\nSETVAR staging_url = \"https://staging.example.com\"\n\n# Use throughout script\nGO $staging_url\nTYPE…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Add Debugging Information",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Log progress\nEVAL `console.log(\"Starting login process\")`\nGO /login\n\n# Verify page state\nIF (`document.title.includes(\"Login\")`) THEN EVAL `console.log(\"On login page\")`\n\n# Continue with login\nTYPE…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Common Patterns",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Login Flow",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Complete login automation\nSETVAR email = \"user@example.com\"\nSETVAR password = \"mypassword\"\n\nGO /login\nWAIT `#login-form` 5\n\n# Handle optional cookie banner\nIF (EXISTS `.cookie-banner`) THEN CLICK…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Infinite Scroll",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Load all content with infinite scroll\nGO /products\n\n# Scroll and load more content\nREPEAT (SCROLL DOWN 500, `document.querySelector(\".load-more\")`)\n\n# Alternative: Fixed number of scrolls\nREPEAT…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Form Validation",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Handle form with validation\nSET `#email` \"invalid-email\"\nCLICK `#submit`\n\n# Check for validation error\nIF (EXISTS `.error-email`) THEN SET `#email` \"valid@example.com\"\n\n# Retry submission\nCLICK…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Multi-step Process",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Complex multi-step workflow\nPROC navigate_to_step\n  CLICK `.next-button`\n  WAIT `.step-content` 5\nENDPROC\n\n# Step 1\nWAIT `.step-1` 5\nSET `#name` \"John Doe\"\nnavigate_to_step\n\n# Step 2\nSET `#email`…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Integration with Crawl4AI",
        "content": "Use C4A-Script with Crawl4AI for dynamic content interaction:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\n# Define interaction script\nscript = \"\"\"\n# Handle dynamic content loading\nWAIT `.content` 5\nIF (EXISTS `.load-more-button`) THEN CLICK…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "This reference covers all available C4A-Script commands and patterns. For interactive learning, try the [tutorial](../examples/c4a_script/tutorial/) or [live…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "C4A-Script",
      "Crawl4AI",
      "automation",
      "browser",
      "scripting",
      "commands"
    ],
    "prerequisites": [],
    "_content_hash": "3d0f7677153465b1c10d6e2887c073fe7143d281cd58726c050c7ac7da676e6c",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/crawl-result/",
    "title": "CrawlResult Reference",
    "type": "api",
    "summary": "Reference for the CrawlResult class in Crawl4AI, detailing all fields returned after a crawl operation, including content, metadata, links, media, and optional captures.",
    "sections": [
      {
        "heading": "Overview",
        "content": "The `CrawlResult` class encapsulates everything returned after a single crawl operation. It provides the raw or processed content, details on links and media, plus optional metadata (like…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class CrawlResult(BaseModel):\n    url: str\n    html: str\n    success: bool\n    cleaned_html: Optional[str] = None\n    fit_html: Optional[str] = None  # Preprocessed HTML optimized for extraction…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1. Basic Crawl Info",
        "content": "###### 1.1 `url` (str)\n\n**What**: The final crawled URL (after any redirects).\n\n###### 1.2 `success` (bool)\n\n**What**: `True` if the crawl pipeline ended without major errors; `False` otherwise.\n\n###### 1.3…",
        "code_blocks": [
          {
            "language": "python",
            "code": "print(result.url)  # e.g., \"https://example.com/\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if not result.success:\n    print(f\"Crawl failed: {result.error_message}\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.status_code == 404:\n    print(\"Page not found!\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.status_code in (301, 302) and result.redirected_status_code == 200:\n    print(f\"Redirected to {result.redirected_url} (OK)\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if not result.success:\n    print(\"Error:\", result.error_message)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# If you used session_id=\"login_session\" in CrawlerRunConfig, see it here:\nprint(\"Session:\", result.session_id)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.response_headers:\n    print(\"Server:\", result.response_headers.get(\"Server\", \"Unknown\"))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.ssl_certificate:\n    print(\"Issuer:\", result.ssl_certificate.issuer)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Raw / Cleaned Content",
        "content": "###### 2.1 `html` (str)\n\n**What**: The **original** unmodified HTML from the final page load.\n\n###### 2.2 `cleaned_html` (Optional[str])\n\n**What**: A sanitized HTML version—scripts, styles, or excluded…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Possibly large\nprint(len(result.html))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "print(result.cleaned_html[:500])  # Show a snippet",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Markdown Fields",
        "content": "###### 3.1 The Markdown Generation Approach\n\nCrawl4AI can convert HTML→Markdown, optionally including:\n\n- **Raw** markdown\n- **Links as citations** (with a references section)\n- **Fit** markdown if a…",
        "code_blocks": [
          {
            "language": "python",
            "code": "if result.markdown:\n    md_res = result.markdown\n    print(\"Raw MD:\", md_res.raw_markdown[:300])\n    print(\"Citations MD:\", md_res.markdown_with_citations[:300])\n    print(\"References:\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "print(result.markdown.raw_markdown[:200])\nprint(result.markdown.fit_markdown)\nprint(result.markdown.fit_html)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Media & Links",
        "content": "###### 4.1 `media` (Dict[str, List[Dict]])\n\n**What**: Contains info about discovered images, videos, or audio. Typically keys: `\"images\"`, `\"videos\"`, `\"audios\"`.\n\n**Common Fields** in each item:\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "images = result.media.get(\"images\", [])\nfor img in images:\n    if img.get(\"score\", 0) > 5:\n        print(\"High-value image:\", img[\"src\"])",
            "filename": ""
          },
          {
            "language": "python",
            "code": "for link in result.links[\"internal\"]:\n    print(f\"Internal link to {link['href']} with text {link['text']}\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Additional Fields",
        "content": "###### 5.1 `extracted_content` (Optional[str])\n\n**What**: If you used `extraction_strategy` (CSS, LLM, etc.), the structured output (JSON).\n\n###### 5.2 `downloaded_files` (Optional[List[str]])\n\n**What**:…",
        "code_blocks": [
          {
            "language": "python",
            "code": "if result.extracted_content:\n    data = json.loads(result.extracted_content)\n    print(data)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.downloaded_files:\n    for file_path in result.downloaded_files:\n        print(\"Downloaded:\", file_path)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import base64\nif result.screenshot:\n    with open(\"page.png\", \"wb\") as f:\n        f.write(base64.b64decode(result.screenshot))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.pdf:\n    with open(\"page.pdf\", \"wb\") as f:\n        f.write(result.pdf)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.mhtml:\n    with open(\"page.mhtml\", \"w\", encoding=\"utf-8\") as f:\n        f.write(result.mhtml)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.metadata:\n    print(\"Title:\", result.metadata.get(\"title\"))\n    print(\"Author:\", result.metadata.get(\"author\"))",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. `dispatch_result` (optional)",
        "content": "A `DispatchResult` object providing additional concurrency and resource usage information when crawling URLs in parallel (e.g., via `arun_many()` with custom dispatchers). It contains:\n\n- `task_id`:…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Example usage:\nfor result in results:\n    if result.success and result.dispatch_result:\n        dr = result.dispatch_result\n        print(f\"URL: {result.url}, Task ID: {dr.task_id}\")…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Network Requests & Console Messages",
        "content": "When you enable network and console message capturing in `CrawlerRunConfig` using `capture_network_requests=True` and `capture_console_messages=True`, the `CrawlResult` will include these…",
        "code_blocks": [
          {
            "language": "python",
            "code": "if result.network_requests:\n    # Count different types of events\n    requests = [r for r in result.network_requests if r.get(\"event_type\") == \"request\"]\n    responses = [r for r in…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.console_messages:\n    # Count messages by type\n    message_types = {}\n    for msg in result.console_messages:\n        msg_type = msg.get(\"type\", \"unknown\")\n        message_types[msg_type] =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Example: Accessing Everything",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def handle_result(result: CrawlResult):\n    if not result.success:\n        print(\"Crawl error:\", result.error_message)\n        return\n\n    # Basic info\n    print(\"Crawled URL:\", result.url)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "9. Key Points & Future",
        "content": "1. **Deprecated legacy properties of CrawlResult**\n   - `markdown_v2` - Removed in v0.5 and now raises `AttributeError`. Use `result.markdown` instead.\n   - `fit_markdown` and `fit_html` - No longer…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "url",
        "type": "str",
        "description": "The final crawled URL (after any redirects).",
        "default": "",
        "required": true
      },
      {
        "name": "html",
        "type": "str",
        "description": "The original unmodified HTML from the final page load.",
        "default": "",
        "required": true
      },
      {
        "name": "success",
        "type": "bool",
        "description": "True if the crawl pipeline ended without major errors; False otherwise.",
        "default": "",
        "required": true
      },
      {
        "name": "cleaned_html",
        "type": "Optional[str]",
        "description": "A sanitized HTML version—scripts, styles, or excluded tags are removed based on your CrawlerRunConfig.",
        "default": "None",
        "required": false
      },
      {
        "name": "fit_html",
        "type": "Optional[str]",
        "description": "Preprocessed HTML optimized for extraction",
        "default": "None",
        "required": false
      },
      {
        "name": "media",
        "type": "Dict[str, List[Dict]]",
        "description": "Contains info about discovered images, videos, or audio. Typically keys: 'images', 'videos', 'audios'.",
        "default": "{}",
        "required": false
      },
      {
        "name": "links",
        "type": "Dict[str, List[Dict]]",
        "description": "Holds internal and external link data. Usually two keys: 'internal' and 'external'.",
        "default": "{}",
        "required": false
      },
      {
        "name": "downloaded_files",
        "type": "Optional[List[str]]",
        "description": "If accept_downloads=True in your BrowserConfig + downloads_path, lists local file paths for downloaded items.",
        "default": "None",
        "required": false
      },
      {
        "name": "screenshot",
        "type": "Optional[str]",
        "description": "Base64-encoded screenshot if screenshot=True in CrawlerRunConfig.",
        "default": "None",
        "required": false
      },
      {
        "name": "pdf",
        "type": "Optional[bytes]",
        "description": "Raw PDF bytes if pdf=True in CrawlerRunConfig.",
        "default": "None",
        "required": false
      },
      {
        "name": "mhtml",
        "type": "Optional[str]",
        "description": "MHTML snapshot of the page if capture_mhtml=True in CrawlerRunConfig.",
        "default": "None",
        "required": false
      },
      {
        "name": "markdown",
        "type": "Optional[Union[str, MarkdownGenerationResult]]",
        "description": "Holds the MarkdownGenerationResult.",
        "default": "None",
        "required": false
      },
      {
        "name": "extracted_content",
        "type": "Optional[str]",
        "description": "If you used extraction_strategy (CSS, LLM, etc.), the structured output (JSON).",
        "default": "None",
        "required": false
      },
      {
        "name": "metadata",
        "type": "Optional[dict]",
        "description": "Page-level metadata if discovered (title, description, OG data, etc.).",
        "default": "None",
        "required": false
      },
      {
        "name": "error_message",
        "type": "Optional[str]",
        "description": "If success=False, a textual description of the failure.",
        "default": "None",
        "required": false
      },
      {
        "name": "session_id",
        "type": "Optional[str]",
        "description": "The ID used for reusing a browser context across multiple calls.",
        "default": "None",
        "required": false
      },
      {
        "name": "response_headers",
        "type": "Optional[dict]",
        "description": "Final HTTP response headers.",
        "default": "None",
        "required": false
      },
      {
        "name": "status_code",
        "type": "Optional[int]",
        "description": "The page's HTTP status code (e.g., 200, 404). When the page was reached via redirect, this is the status code of the first response in the redirect chain.",
        "default": "None",
        "required": false
      },
      {
        "name": "redirected_status_code",
        "type": "Optional[int]",
        "description": "The HTTP status code of the final redirect destination.",
        "default": "None",
        "required": false
      },
      {
        "name": "ssl_certificate",
        "type": "Optional[SSLCertificate]",
        "description": "If fetch_ssl_certificate=True in your CrawlerRunConfig, contains a SSLCertificate object.",
        "default": "None",
        "required": false
      },
      {
        "name": "dispatch_result",
        "type": "Optional[DispatchResult]",
        "description": "A DispatchResult object providing additional concurrency and resource usage information when crawling URLs in parallel.",
        "default": "None",
        "required": false
      },
      {
        "name": "network_requests",
        "type": "Optional[List[Dict[str, Any]]]",
        "description": "A list of dictionaries containing information about all network requests, responses, and failures captured during the crawl.",
        "default": "None",
        "required": false
      },
      {
        "name": "console_messages",
        "type": "Optional[List[Dict[str, Any]]]",
        "description": "A list of dictionaries containing all browser console messages captured during the crawl.",
        "default": "None",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Web Crawling",
      "Python",
      "Pydantic",
      "API Reference",
      "CrawlResult"
    ],
    "prerequisites": [],
    "_content_hash": "2e1491438dee4599d0ac1cc4cdbccae890a45ced6d95f10e8137f30838c12cbe",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/digest/",
    "title": "digest()",
    "type": "api",
    "summary": "The digest() method is the primary interface for adaptive web crawling. It intelligently crawls websites starting from a given URL, guided by a query, and automatically determines when sufficient…",
    "sections": [
      {
        "heading": "Method Signature",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def digest(\n    start_url: str,\n    query: str,\n    resume_from: Optional[Union[str, Path]] = None\n) -> CrawlState",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Parameters",
        "content": "###### start_url\n\n- **Type** : `str`\n- **Required** : Yes\n- **Description** : The starting URL for the crawl. This should be a valid HTTP/HTTPS URL that serves as the entry point for information…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Return Value",
        "content": "Returns a `CrawlState` object containing:\n\n- **crawled_urls** (`Set[str]`): All URLs that have been crawled\n- **knowledge_base** (`List[CrawlResult]`): Collection of crawled pages with content\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How It Works",
        "content": "The `digest()` method implements an intelligent crawling algorithm:\n\n- **Initial Crawl** : Starts from the provided URL\n- **Link Analysis** : Evaluates all discovered links for relevance\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Examples",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async with AsyncWebCrawler() as crawler:\n    adaptive = AdaptiveCrawler(crawler)\n\n    state = await adaptive.digest(\n        start_url=\"https://docs.python.org/3/\",\n        query=\"async await context…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = AdaptiveConfig(\n    confidence_threshold=0.9,  # Require high confidence\n    max_pages=30,             # Allow more pages\n    top_k_links=3             # Follow top 3 links per…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# First crawl - may be interrupted\nstate1 = await adaptive.digest(\n    start_url=\"https://example.com\",\n    query=\"machine learning algorithms\"\n)\n\n# Save state (if not…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "state = await adaptive.digest(\n    start_url=\"https://docs.example.com\",\n    query=\"api reference\"\n)\n\n# Monitor progress\nprint(f\"Pages crawled: {len(state.crawled_urls)}\")\nprint(f\"New terms…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Query Best Practices",
        "content": "- **Be Specific** : Use descriptive terms that appear in target content\n- **Include Key Terms** : Add technical terms you expect to find\n- **Multiple Concepts** : Combine related concepts for…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Good\nquery = \"python async context managers implementation\"\n\n# Too broad\nquery = \"python programming\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "query = \"oauth2 jwt refresh tokens authorization\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "query = \"rest api pagination sorting filtering\"",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Considerations",
        "content": "- **Initial URL** : Choose a page with good navigation (e.g., documentation index)\n- **Query Length** : 3-8 terms typically work best\n- **Link Density** : Sites with clear navigation crawl more…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Error Handling",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "try:\n    state = await adaptive.digest(\n        start_url=\"https://example.com\",\n        query=\"search terms\"\n    )\nexcept Exception as e:\n    print(f\"Crawl failed: {e}\")\n    # State is auto-saved if…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Stopping Conditions",
        "content": "The crawl stops when any of these conditions are met:\n\n- **Confidence Threshold** : Reached the configured confidence level\n- **Page Limit** : Crawled the maximum number of pages\n- **Diminishing…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [AdaptiveCrawler Class](../adaptive-crawler/)\n- [Adaptive Crawling Guide](../../core/adaptive-crawling/)\n- [Configuration Options](../../core/adaptive-crawling/#configuration-options)",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "start_url",
        "type": "str",
        "description": "The starting URL for the crawl. This should be a valid HTTP/HTTPS URL that serves as the entry point for information gathering.",
        "default": "",
        "required": true
      },
      {
        "name": "query",
        "type": "str",
        "description": "The search query that guides the crawling process. This should contain key terms related to the information you're seeking. The crawler uses this to evaluate relevance and determine which links to…",
        "default": "",
        "required": true
      },
      {
        "name": "resume_from",
        "type": "Optional[Union[str, Path]]",
        "description": "Path to a previously saved crawl state file. When provided, the crawler resumes from the saved state instead of starting fresh.",
        "default": "None",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "adaptive crawling",
      "digest",
      "web crawling",
      "Python",
      "async"
    ],
    "prerequisites": [],
    "_content_hash": "43017001b472953d6e4f466707ac7694f1edaeb476d8161f8e4e6c909ff8a636",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/parameters/",
    "title": "Browser, Crawler & LLM Config - Crawl4AI Documentation (v0.9.x)",
    "type": "api",
    "summary": "This page documents the configuration classes for Crawl4AI: BrowserConfig, CrawlerRunConfig, and LLMConfig, detailing their parameters, usage, and helper methods.",
    "sections": [
      {
        "heading": "1. BrowserConfig – Controlling the Browser",
        "content": "`BrowserConfig` focuses on  **how**  the browser is launched and behaves. This includes headless mode, proxies, user agents, and other environment tweaks.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig\n\nbrowser_cfg = BrowserConfig(\n    browser_type=\"chromium\",\n    headless=True,\n    viewport_width=1280,\n    viewport_height=720,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1.1 Parameter Highlights",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`browser_type`** | `\"chromium\"`, `\"firefox\"`, `\"webkit\"`  *(default: `\"chromium\"`)* | Which browser engine to use.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. CrawlerRunConfig – Controlling Each Crawl",
        "content": "While `BrowserConfig` sets up the  **environment** , `CrawlerRunConfig` details  **how**  each  **crawl operation**  should behave: caching, content filtering, link or domain blocking, timeouts,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nrun_cfg = CrawlerRunConfig(\n    wait_for=\"css:.main-content\",\n    word_count_threshold=15,\n    excluded_tags=[\"nav\", \"footer\"],…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.1 Parameter Highlights",
        "content": "We group them by category.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "A) Content Processing",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`word_count_threshold`** | `int` (default: ~200) | Skips text blocks below X words. Helps ignore trivial sections.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "B) Browser Location and Identity",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`locale`** | `str or None` (None) | Browser's locale (e.g., \"en-US\", \"fr-FR\") for language preferences. |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "C) Caching & Session",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`cache_mode`** | `CacheMode or None` | Controls how caching is handled (`ENABLED`, `BYPASS`, `DISABLED`, etc.). If…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "D) Page Navigation & Timing",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`wait_until`** | `str` (domcontentloaded) | Condition for navigation to \"complete\". Often `\"networkidle\"` or…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "E) Page Interaction",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`js_code`** | `str or list[str]` (None) | JavaScript to run  **after**  `wait_for` and `delay_before_return_html`, on…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "F) Media Handling",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`screenshot`** | `bool` (False) | Capture a screenshot (base64) in `result.screenshot`. |\n| **`screenshot_wait_for`**…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "G) Link/Domain Handling",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`exclude_social_media_domains`** | `list` (e.g. Facebook/Twitter) | A default list can be extended. Any link to these…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "H) Debug, Logging & Network Monitoring",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`verbose`** | `bool` (True) | Prints logs detailing each step of crawling, interactions, or errors. |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "I) Connection & HTTP Parameters",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`method`** | `str` (\"GET\") | HTTP method to use when using AsyncHTTPCrawlerStrategy (e.g., \"GET\", \"POST\"). |\n|…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "J) Virtual Scroll Configuration",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`virtual_scroll_config`** | `VirtualScrollConfig or dict` (None) | Configuration for handling virtualized scrolling…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import VirtualScrollConfig\n\nvirtual_config = VirtualScrollConfig(\n    container_selector=\"#timeline\",    # CSS selector for scrollable container\n    scroll_count=30,                   #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "K) URL Matching Configuration",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`url_matcher`** | `UrlMatcher` (None) | Pattern(s) to match URLs against. Can be: string (glob), function, or list of…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig, MatchMode\nfrom crawl4ai.processors.pdf import PDFContentScrapingStrategy\nfrom crawl4ai.extraction_strategy import JsonCssExtractionStrategy\n\n# Simple string…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "L) Advanced Crawling Features",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`deep_crawl_strategy`** | `DeepCrawlStrategy or None` (None) | Strategy for deep/recursive crawling. Enables…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.2 Helper Methods",
        "content": "Both `BrowserConfig` and `CrawlerRunConfig` provide a `clone()` method to create modified copies:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Create a base configuration\nbase_config = CrawlerRunConfig(\n    cache_mode=CacheMode.ENABLED,\n    word_count_threshold=200\n)\n\n# Create variations using clone()\nstream_config =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Class-Level Defaults (`set_defaults` / `get_defaults` / `reset_defaults`)",
        "content": "Both config classes support class-level default overrides. When deploying in a server or cloud context, this eliminates the need to pass the same parameters at every call site.\n\n **Resolution…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import BrowserConfig, CrawlerRunConfig\n\n# Set once at application startup\nBrowserConfig.set_defaults(\n    cache_cdp_connection=True,\n    cdp_close_delay=0,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.3 Example Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def main():\n    # Configure the browser\n    browser_cfg = BrowserConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.4 Compliance & Ethics",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`check_robots_txt`** | `bool` (False) | When True, checks and respects robots.txt rules before crawling. Uses…",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    check_robots_txt=True,  # Enable robots.txt compliance\n    user_agent=\"MyBot/1.0\"  # Identify your crawler\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. LLMConfig - Setting up LLM providers",
        "content": "LLMConfig is useful to pass LLM provider config to strategies and functions that rely on LLMs to do extraction, filtering, schema generation etc. Currently it can be used in the following -\n\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.1 Parameters",
        "content": "| **Parameter** | **Type / Default** | **What It Does** |\n| --- | --- | --- |\n| **`provider`** | `\"ollama/llama3\",\"groq/llama3-70b-8192\",\"groq/llama3-8b-8192\", \"openai/gpt-4o-mini\"…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.2 Example Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "llm_config = LLMConfig(\n    provider=\"openai/gpt-4o-mini\",\n    api_token=os.getenv(\"OPENAI_API_KEY\"),\n    backoff_base_delay=1, # optional\n    backoff_max_attempts=5, # optional…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Putting It All Together",
        "content": "- **Use**  `BrowserConfig` for  **global**  browser settings: engine, headless, proxy, user agent.\n- **Use**  `CrawlerRunConfig` for each crawl’s  **context** : how to filter content, handle caching,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Create a modified copy with the clone() method\nstream_cfg = run_cfg.clone(\n    stream=True,\n    cache_mode=CacheMode.BYPASS\n)\n\n# Or set project-wide defaults once at…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "browser_type",
        "type": "chromium\", \"firefox\", \"webkit\"",
        "description": "Which browser engine to use. \"chromium\" is typical for many sites, \"firefox\" or \"webkit\" for specialized tests.",
        "default": "chromium",
        "required": false
      },
      {
        "name": "headless",
        "type": "bool",
        "description": "Headless means no visible UI. False is handy for debugging.",
        "default": "True",
        "required": false
      },
      {
        "name": "browser_mode",
        "type": "str",
        "description": "How browser is initialized: \"dedicated\" (new instance), \"builtin\" (CDP background), \"custom\" (explicit CDP), \"docker\" (container).",
        "default": "dedicated",
        "required": false
      },
      {
        "name": "use_managed_browser",
        "type": "bool",
        "description": "Launch browser via CDP for advanced control. Set automatically based on browser_mode.",
        "default": "False",
        "required": false
      },
      {
        "name": "cdp_url",
        "type": "str",
        "description": "Chrome DevTools Protocol endpoint URL (e.g., \"ws://localhost:9222/devtools/browser/\"). Set automatically based on browser_mode.",
        "default": "",
        "required": false
      },
      {
        "name": "debugging_port",
        "type": "int",
        "description": "Port for browser debugging protocol.",
        "default": "9222",
        "required": false
      },
      {
        "name": "host",
        "type": "str",
        "description": "Host for browser connection.",
        "default": "localhost",
        "required": false
      },
      {
        "name": "viewport_width",
        "type": "int",
        "description": "Initial page width (in px). Useful for testing responsive layouts.",
        "default": "1080",
        "required": false
      },
      {
        "name": "viewport_height",
        "type": "int",
        "description": "Initial page height (in px).",
        "default": "600",
        "required": false
      },
      {
        "name": "viewport",
        "type": "dict",
        "description": "Viewport dimensions dict. If set, overrides viewport_width and viewport_height.",
        "default": "",
        "required": false
      },
      {
        "name": "device_scale_factor",
        "type": "float",
        "description": "Device pixel ratio for rendering. Use 2.0 for Retina-quality screenshots. Higher values produce larger images and use more memory.",
        "default": "1.0",
        "required": false
      },
      {
        "name": "proxy",
        "type": "str",
        "description": "Deprecated. Use proxy_config instead. If set, it will be auto-converted internally.",
        "default": "",
        "required": false
      },
      {
        "name": "proxy_config",
        "type": "ProxyConfig or dict",
        "description": "For advanced or multi-proxy needs, specify ProxyConfig object or dict like {\"server\": \"...\", \"username\": \"...\", \"password\": \"...\"}.",
        "default": "",
        "required": false
      },
      {
        "name": "use_persistent_context",
        "type": "bool",
        "description": "If True, uses a persistent browser context (keep cookies, sessions across runs). Also sets use_managed_browser=True.",
        "default": "False",
        "required": false
      },
      {
        "name": "user_data_dir",
        "type": "str or None",
        "description": "Directory to store user data (profiles, cookies). Must be set if you want permanent sessions.",
        "default": "",
        "required": false
      },
      {
        "name": "chrome_channel",
        "type": "str",
        "description": "Chrome channel to launch (e.g., \"chrome\", \"msedge\"). Only for browser_type=\"chromium\". Auto-set to empty for Firefox/WebKit.",
        "default": "chromium",
        "required": false
      },
      {
        "name": "channel",
        "type": "str",
        "description": "Alias for chrome_channel.",
        "default": "chromium",
        "required": false
      },
      {
        "name": "accept_downloads",
        "type": "bool",
        "description": "Whether to allow file downloads. Requires downloads_path if True.",
        "default": "False",
        "required": false
      },
      {
        "name": "downloads_path",
        "type": "str or None",
        "description": "Directory to store downloaded files.",
        "default": "",
        "required": false
      },
      {
        "name": "storage_state",
        "type": "str or dict or None",
        "description": "In-memory storage state (cookies, localStorage) to restore browser state.",
        "default": "",
        "required": false
      },
      {
        "name": "ignore_https_errors",
        "type": "bool",
        "description": "If True, continues despite invalid certificates (common in dev/staging).",
        "default": "True",
        "required": false
      },
      {
        "name": "java_script_enabled",
        "type": "bool",
        "description": "Disable if you want no JS overhead, or if only static content is needed.",
        "default": "True",
        "required": false
      },
      {
        "name": "sleep_on_close",
        "type": "bool",
        "description": "Add a small delay when closing browser (can help with cleanup issues).",
        "default": "False",
        "required": false
      },
      {
        "name": "cookies",
        "type": "list",
        "description": "Pre-set cookies, each a dict like {\"name\": \"session\", \"value\": \"...\", \"url\": \"...\"}.",
        "default": "[]",
        "required": false
      },
      {
        "name": "headers",
        "type": "dict",
        "description": "Extra HTTP headers for every request, e.g. {\"Accept-Language\": \"en-US\"}.",
        "default": "{}",
        "required": false
      },
      {
        "name": "user_agent",
        "type": "str",
        "description": "Your custom user agent string.",
        "default": "Chrome-based UA",
        "required": false
      },
      {
        "name": "user_agent_mode",
        "type": "str",
        "description": "Set to \"random\" to randomize user agent from a pool (helps with bot detection).",
        "default": "",
        "required": false
      },
      {
        "name": "user_agent_generator_config",
        "type": "dict",
        "description": "Configuration dict for user agent generation when user_agent_mode=\"random\".",
        "default": "{}",
        "required": false
      },
      {
        "name": "text_mode",
        "type": "bool",
        "description": "If True, tries to disable images/other heavy content for speed.",
        "default": "False",
        "required": false
      },
      {
        "name": "light_mode",
        "type": "bool",
        "description": "Disables some background features for performance gains.",
        "default": "False",
        "required": false
      },
      {
        "name": "avoid_ads",
        "type": "bool",
        "description": "If True, blocks requests to common ad/tracker domains (Google Analytics, DoubleClick, Facebook, Hotjar, etc.) at the browser context level.",
        "default": "False",
        "required": false
      },
      {
        "name": "avoid_css",
        "type": "bool",
        "description": "If True, blocks loading of CSS files (.css, .less, .scss, .sass) for faster, leaner crawls when only text content is needed.",
        "default": "False",
        "required": false
      },
      {
        "name": "extra_args",
        "type": "list",
        "description": "Additional flags for the underlying browser process, e.g. [\"--disable-extensions\"].",
        "default": "[]",
        "required": false
      },
      {
        "name": "enable_stealth",
        "type": "bool",
        "description": "Enable playwright-stealth mode to bypass bot detection. Cannot be used with browser_mode=\"builtin\".",
        "default": "False",
        "required": false
      },
      {
        "name": "word_count_threshold",
        "type": "int",
        "description": "Skips text blocks below X words. Helps ignore trivial sections.",
        "default": "200",
        "required": false
      },
      {
        "name": "extraction_strategy",
        "type": "ExtractionStrategy",
        "description": "If set, extracts structured data (CSS-based, LLM-based, etc.).",
        "default": "",
        "required": false
      },
      {
        "name": "chunking_strategy",
        "type": "ChunkingStrategy",
        "description": "Strategy to chunk content before extraction. Can be customized for different chunking approaches.",
        "default": "RegexChunking()",
        "required": false
      },
      {
        "name": "markdown_generator",
        "type": "MarkdownGenerationStrategy",
        "description": "If you want specialized markdown output (citations, filtering, chunking, etc.). Can be customized with options such as content_source parameter to select the HTML input source ('cleaned_html',…",
        "default": "",
        "required": false
      },
      {
        "name": "css_selector",
        "type": "str",
        "description": "Retains only the part of the page matching this selector. Affects the entire extraction process.",
        "default": "",
        "required": false
      },
      {
        "name": "target_elements",
        "type": "List[str]",
        "description": "List of CSS selectors for elements to focus on for markdown generation and data extraction, while still processing the entire page for links, media, etc. Provides more flexibility than css_selector.",
        "default": "",
        "required": false
      },
      {
        "name": "excluded_tags",
        "type": "list",
        "description": "Removes entire tags (e.g. [\"script\", \"style\"]).",
        "default": "",
        "required": false
      },
      {
        "name": "excluded_selector",
        "type": "str",
        "description": "Like css_selector but to exclude. E.g. \"#ads, .tracker\".",
        "default": "",
        "required": false
      },
      {
        "name": "only_text",
        "type": "bool",
        "description": "If True, tries to extract text-only content.",
        "default": "False",
        "required": false
      },
      {
        "name": "prettiify",
        "type": "bool",
        "description": "If True, beautifies final HTML (slower, purely cosmetic).",
        "default": "False",
        "required": false
      },
      {
        "name": "keep_data_attributes",
        "type": "bool",
        "description": "If True, preserve data-* attributes in cleaned HTML.",
        "default": "False",
        "required": false
      },
      {
        "name": "keep_attrs",
        "type": "list",
        "description": "List of HTML attributes to keep during processing (e.g., [\"id\", \"class\", \"data-value\"]).",
        "default": "[]",
        "required": false
      },
      {
        "name": "remove_forms",
        "type": "bool",
        "description": "If True, remove all <form> elements.",
        "default": "False",
        "required": false
      },
      {
        "name": "parser_type",
        "type": "str",
        "description": "HTML parser to use (e.g., \"lxml\", \"html.parser\").",
        "default": "lxml",
        "required": false
      },
      {
        "name": "scraping_strategy",
        "type": "ContentScrapingStrategy",
        "description": "Strategy to use for content scraping. Can be customized for different scraping needs (e.g., PDF extraction).",
        "default": "LXMLWebScrapingStrategy()",
        "required": false
      },
      {
        "name": "locale",
        "type": "str or None",
        "description": "Browser's locale (e.g., \"en-US\", \"fr-FR\") for language preferences.",
        "default": "",
        "required": false
      },
      {
        "name": "timezone_id",
        "type": "str or None",
        "description": "Browser's timezone (e.g., \"America/New_York\", \"Europe/Paris\").",
        "default": "",
        "required": false
      },
      {
        "name": "geolocation",
        "type": "GeolocationConfig or None",
        "description": "GPS coordinates configuration. Use GeolocationConfig(latitude=..., longitude=..., accuracy=...).",
        "default": "",
        "required": false
      },
      {
        "name": "fetch_ssl_certificate",
        "type": "bool",
        "description": "If True, fetches and includes SSL certificate information in the result.",
        "default": "False",
        "required": false
      },
      {
        "name": "proxy_config",
        "type": "ProxyConfig, list[ProxyConfig], or None",
        "description": "Proxy configuration for this specific crawl. Pass a single proxy or an ordered list of proxies to try. See Anti-Bot & Fallback.",
        "default": "",
        "required": false
      },
      {
        "name": "proxy_rotation_strategy",
        "type": "ProxyRotationStrategy",
        "description": "Strategy for rotating proxies during crawl operations.",
        "default": "",
        "required": false
      },
      {
        "name": "max_retries",
        "type": "int",
        "description": "Number of retry rounds when anti-bot blocking is detected. Each round tries all proxies in proxy_config.",
        "default": "0",
        "required": false
      },
      {
        "name": "fallback_fetch_function",
        "type": "async (str) -> str or None",
        "description": "Async function called as last resort after all retries are exhausted. Takes URL, returns raw HTML. See Anti-Bot & Fallback.",
        "default": "",
        "required": false
      },
      {
        "name": "cache_mode",
        "type": "CacheMode or None",
        "description": "Controls how caching is handled (ENABLED, BYPASS, DISABLED, etc.). If None, typically defaults to ENABLED.",
        "default": "",
        "required": false
      },
      {
        "name": "session_id",
        "type": "str or None",
        "description": "Assign a unique ID to reuse a single browser session across multiple arun() calls.",
        "default": "",
        "required": false
      },
      {
        "name": "bypass_cache",
        "type": "bool",
        "description": "Deprecated. If True, acts like CacheMode.BYPASS. Use cache_mode instead.",
        "default": "False",
        "required": false
      },
      {
        "name": "disable_cache",
        "type": "bool",
        "description": "Deprecated. If True, acts like CacheMode.DISABLED. Use cache_mode instead.",
        "default": "False",
        "required": false
      },
      {
        "name": "no_cache_read",
        "type": "bool",
        "description": "Deprecated. If True, acts like CacheMode.WRITE_ONLY (writes cache but never reads). Use cache_mode instead.",
        "default": "False",
        "required": false
      },
      {
        "name": "no_cache_write",
        "type": "bool",
        "description": "Deprecated. If True, acts like CacheMode.READ_ONLY (reads cache but never writes). Use cache_mode instead.",
        "default": "False",
        "required": false
      },
      {
        "name": "shared_data",
        "type": "dict or None",
        "description": "Shared data to be passed between hooks and accessible across crawl operations.",
        "default": "",
        "required": false
      },
      {
        "name": "wait_until",
        "type": "str",
        "description": "Condition for navigation to \"complete\". Often \"networkidle\" or \"domcontentloaded\".",
        "default": "domcontentloaded",
        "required": false
      },
      {
        "name": "page_timeout",
        "type": "int",
        "description": "Timeout for page navigation or JS steps. Increase for slow sites.",
        "default": "60000",
        "required": false
      },
      {
        "name": "wait_for",
        "type": "str or None",
        "description": "Wait for a CSS (\"css:selector\") or JS (\"js:() => bool\") condition before content extraction.",
        "default": "",
        "required": false
      },
      {
        "name": "wait_for_timeout",
        "type": "int or None",
        "description": "Specific timeout in ms for the wait_for condition. If None, uses page_timeout.",
        "default": "",
        "required": false
      },
      {
        "name": "wait_for_images",
        "type": "bool",
        "description": "Wait for images to load before finishing. Slows down if you only want text.",
        "default": "False",
        "required": false
      },
      {
        "name": "delay_before_return_html",
        "type": "float",
        "description": "Additional pause (seconds) before final HTML is captured. Good for last-second updates.",
        "default": "0.1",
        "required": false
      },
      {
        "name": "check_robots_txt",
        "type": "bool",
        "description": "Whether to check and respect robots.txt rules before crawling. If True, caches robots.txt for efficiency.",
        "default": "False",
        "required": false
      },
      {
        "name": "mean_delay",
        "type": "float",
        "description": "If you call arun_many(), these define random delay intervals between crawls, helping avoid detection or rate limits.",
        "default": "0.1",
        "required": false
      },
      {
        "name": "max_range",
        "type": "float",
        "description": "If you call arun_many(), these define random delay intervals between crawls, helping avoid detection or rate limits.",
        "default": "0.3",
        "required": false
      },
      {
        "name": "semaphore_count",
        "type": "int",
        "description": "Max concurrency for arun_many(). Increase if you have resources for parallel crawls.",
        "default": "5",
        "required": false
      },
      {
        "name": "js_code",
        "type": "str or list[str]",
        "description": "JavaScript to run after wait_for and delay_before_return_html, on the fully-loaded page. E.g. \"document.querySelector('button')?.click();\".",
        "default": "",
        "required": false
      },
      {
        "name": "js_code_before_wait",
        "type": "str or list[str]",
        "description": "JavaScript to run before wait_for. Use for triggering loading that wait_for then checks (e.g. clicking a tab, then waiting for its content).",
        "default": "",
        "required": false
      },
      {
        "name": "c4a_script",
        "type": "str or list[str]",
        "description": "C4A script that compiles to JavaScript. Alternative to writing raw JS.",
        "default": "",
        "required": false
      },
      {
        "name": "js_only",
        "type": "bool",
        "description": "If True, indicates we're reusing an existing session and only applying JS. No full reload.",
        "default": "False",
        "required": false
      },
      {
        "name": "ignore_body_visibility",
        "type": "bool",
        "description": "Skip checking if <body> is visible. Usually best to keep True.",
        "default": "True",
        "required": false
      },
      {
        "name": "scan_full_page",
        "type": "bool",
        "description": "If True, auto-scroll the page to load dynamic content (infinite scroll).",
        "default": "False",
        "required": false
      },
      {
        "name": "scroll_delay",
        "type": "float",
        "description": "Delay between scroll steps when scanning the full page (scan_full_page=True) or capturing full-page screenshots.",
        "default": "0.2",
        "required": false
      },
      {
        "name": "max_scroll_steps",
        "type": "int or None",
        "description": "Maximum number of scroll steps during full page scan. If None, scrolls until entire page is loaded.",
        "default": "",
        "required": false
      },
      {
        "name": "process_iframes",
        "type": "bool",
        "description": "Inlines iframe content for single-page extraction.",
        "default": "False",
        "required": false
      },
      {
        "name": "flatten_shadow_dom",
        "type": "bool",
        "description": "Flattens Shadow DOM content into the light DOM before HTML capture. Resolves slots, strips shadow-scoped styles, and force-opens closed shadow roots. Essential for sites built with Web Components…",
        "default": "False",
        "required": false
      },
      {
        "name": "remove_overlay_elements",
        "type": "bool",
        "description": "Removes potential modals/popups blocking the main content.",
        "default": "False",
        "required": false
      },
      {
        "name": "remove_consent_popups",
        "type": "bool",
        "description": "Removes GDPR/cookie consent popups from known CMP providers (OneTrust, Cookiebot, TrustArc, Quantcast, Didomi, Sourcepoint, FundingChoices, etc.). Tries clicking \"Accept All\" first, then falls back…",
        "default": "False",
        "required": false
      },
      {
        "name": "simulate_user",
        "type": "bool",
        "description": "Simulate user interactions (mouse movements) to avoid bot detection.",
        "default": "False",
        "required": false
      },
      {
        "name": "override_navigator",
        "type": "bool",
        "description": "Override navigator properties in JS for stealth.",
        "default": "False",
        "required": false
      },
      {
        "name": "magic",
        "type": "bool",
        "description": "Automatic handling of popups/consent banners. Experimental.",
        "default": "False",
        "required": false
      },
      {
        "name": "adjust_viewport_to_content",
        "type": "bool",
        "description": "Resizes viewport to match page content height.",
        "default": "False",
        "required": false
      },
      {
        "name": "screenshot",
        "type": "bool",
        "description": "Capture a screenshot (base64) in result.screenshot.",
        "default": "False",
        "required": false
      },
      {
        "name": "screenshot_wait_for",
        "type": "float or None",
        "description": "Extra wait time before the screenshot.",
        "default": "",
        "required": false
      },
      {
        "name": "screenshot_height_threshold",
        "type": "int",
        "description": "If the page is taller than this, alternate screenshot strategies are used.",
        "default": "20000",
        "required": false
      },
      {
        "name": "force_viewport_screenshot",
        "type": "bool",
        "description": "If True, always captures a viewport-only screenshot regardless of page height. Faster and smaller than full-page screenshots.",
        "default": "False",
        "required": false
      },
      {
        "name": "pdf",
        "type": "bool",
        "description": "If True, returns a PDF in result.pdf.",
        "default": "False",
        "required": false
      },
      {
        "name": "capture_mhtml",
        "type": "bool",
        "description": "If True, captures an MHTML snapshot of the page in result.mhtml. MHTML includes all page resources (CSS, images, etc.) in a single file.",
        "default": "False",
        "required": false
      },
      {
        "name": "image_description_min_word_threshold",
        "type": "int",
        "description": "Minimum words for an image's alt text or description to be considered valid.",
        "default": "50",
        "required": false
      },
      {
        "name": "image_score_threshold",
        "type": "int",
        "description": "Filter out low-scoring images. The crawler scores images by relevance (size, context, etc.).",
        "default": "3",
        "required": false
      },
      {
        "name": "exclude_external_images",
        "type": "bool",
        "description": "Exclude images from other domains.",
        "default": "False",
        "required": false
      },
      {
        "name": "exclude_all_images",
        "type": "bool",
        "description": "If True, excludes all images from processing (both internal and external).",
        "default": "False",
        "required": false
      },
      {
        "name": "table_score_threshold",
        "type": "int",
        "description": "Minimum score threshold for processing a table. Lower values include more tables.",
        "default": "7",
        "required": false
      },
      {
        "name": "table_extraction",
        "type": "TableExtractionStrategy",
        "description": "Strategy for table extraction. Defaults to DefaultTableExtraction with configured threshold.",
        "default": "DefaultTableExtraction",
        "required": false
      },
      {
        "name": "exclude_social_media_domains",
        "type": "list",
        "description": "A default list can be extended. Any link to these domains is removed from final output.",
        "default": "default list",
        "required": false
      },
      {
        "name": "exclude_external_links",
        "type": "bool",
        "description": "Removes all links pointing outside the current domain.",
        "default": "False",
        "required": false
      },
      {
        "name": "exclude_social_media_links",
        "type": "bool",
        "description": "Strips links specifically to social sites (like Facebook or Twitter).",
        "default": "False",
        "required": false
      },
      {
        "name": "exclude_domains",
        "type": "list",
        "description": "Provide a custom list of domains to exclude (like [\"ads.com\", \"trackers.io\"]).",
        "default": "[]",
        "required": false
      },
      {
        "name": "exclude_internal_links",
        "type": "bool",
        "description": "If True, excludes internal links from the results.",
        "default": "False",
        "required": false
      },
      {
        "name": "score_links",
        "type": "bool",
        "description": "If True, calculates intrinsic quality scores for all links using URL structure, text quality, and contextual metrics.",
        "default": "False",
        "required": false
      },
      {
        "name": "preserve_https_for_internal_links",
        "type": "bool",
        "description": "If True, preserves HTTPS scheme for internal links even when the server redirects to HTTP. Useful for security-conscious crawling.",
        "default": "False",
        "required": false
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Prints logs detailing each step of crawling, interactions, or errors.",
        "default": "True",
        "required": false
      },
      {
        "name": "log_console",
        "type": "bool",
        "description": "Logs the page's JavaScript console output if you want deeper JS debugging.",
        "default": "False",
        "required": false
      },
      {
        "name": "capture_network_requests",
        "type": "bool",
        "description": "If True, captures network requests made by the page in result.captured_requests.",
        "default": "False",
        "required": false
      },
      {
        "name": "capture_console_messages",
        "type": "bool",
        "description": "If True, captures console messages from the page in result.console_messages.",
        "default": "False",
        "required": false
      },
      {
        "name": "method",
        "type": "str",
        "description": "HTTP method to use when using AsyncHTTPCrawlerStrategy (e.g., \"GET\", \"POST\").",
        "default": "GET",
        "required": false
      },
      {
        "name": "stream",
        "type": "bool",
        "description": "If True, enables streaming mode for arun_many() to process URLs as they complete rather than waiting for all.",
        "default": "False",
        "required": false
      },
      {
        "name": "url",
        "type": "str or None",
        "description": "URL for this specific config. Not typically set directly but used internally for URL-specific configurations.",
        "default": "",
        "required": false
      },
      {
        "name": "user_agent",
        "type": "str or None",
        "description": "Custom User-Agent string for this crawl. Can override browser-level user agent.",
        "default": "",
        "required": false
      },
      {
        "name": "user_agent_mode",
        "type": "str or None",
        "description": "Set to \"random\" to randomize user agent. Can override browser-level setting.",
        "default": "",
        "required": false
      },
      {
        "name": "user_agent_generator_config",
        "type": "dict",
        "description": "Configuration for user agent generation when user_agent_mode=\"random\".",
        "default": "{}",
        "required": false
      },
      {
        "name": "virtual_scroll_config",
        "type": "VirtualScrollConfig or dict",
        "description": "Configuration for handling virtualized scrolling on sites like Twitter/Instagram where content is replaced rather than appended.",
        "default": "",
        "required": false
      },
      {
        "name": "container_selector",
        "type": "str",
        "description": "CSS selector for the scrollable container (e.g., \"#feed\", \".timeline\")",
        "default": "",
        "required": true
      },
      {
        "name": "scroll_count",
        "type": "int",
        "description": "Maximum number of scrolls to perform",
        "default": "10",
        "required": false
      },
      {
        "name": "scroll_by",
        "type": "str or int",
        "description": "Scroll amount: \"container_height\", \"page_height\", or pixels (e.g., 500)",
        "default": "container_height",
        "required": false
      },
      {
        "name": "wait_after_scroll",
        "type": "float",
        "description": "Time in seconds to wait after each scroll for new content to load",
        "default": "0.5",
        "required": false
      },
      {
        "name": "url_matcher",
        "type": "UrlMatcher",
        "description": "Pattern(s) to match URLs against. Can be: string (glob), function, or list of mixed types. None means match ALL URLs",
        "default": "",
        "required": false
      },
      {
        "name": "match_mode",
        "type": "MatchMode",
        "description": "How to combine multiple matchers in a list: MatchMode.OR (any match) or MatchMode.AND (all must match)",
        "default": "MatchMode.OR",
        "required": false
      },
      {
        "name": "deep_crawl_strategy",
        "type": "DeepCrawlStrategy or None",
        "description": "Strategy for deep/recursive crawling. Enables automatic link following and multi-level site crawling.",
        "default": "",
        "required": false
      },
      {
        "name": "link_preview_config",
        "type": "LinkPreviewConfig or dict or None",
        "description": "Configuration for link head extraction and scoring. Fetches and scores link metadata without full page loads.",
        "default": "",
        "required": false
      },
      {
        "name": "experimental",
        "type": "dict or None",
        "description": "Dictionary for experimental/beta features not yet integrated into main parameters. Use with caution.",
        "default": "",
        "required": false
      },
      {
        "name": "check_robots_txt",
        "type": "bool",
        "description": "When True, checks and respects robots.txt rules before crawling. Uses efficient caching with SQLite backend.",
        "default": "False",
        "required": false
      },
      {
        "name": "user_agent",
        "type": "str",
        "description": "User agent string to identify your crawler. Used for robots.txt checking when enabled.",
        "default": "",
        "required": false
      },
      {
        "name": "provider",
        "type": "str",
        "description": "Which LLM provider to use.",
        "default": "openai/gpt-4o-mini",
        "required": false
      },
      {
        "name": "api_token",
        "type": "str",
        "description": "API token to use for the given provider. Optional. When not provided explicitly, api_token will be read from environment variables based on provider. For example: If a gemini model is passed as…",
        "default": "",
        "required": false
      },
      {
        "name": "base_url",
        "type": "str",
        "description": "If your provider has a custom endpoint.",
        "default": "",
        "required": false
      },
      {
        "name": "backoff_base_delay",
        "type": "int",
        "description": "Seconds to wait before the first retry when the provider throttles a request.",
        "default": "2",
        "required": false
      },
      {
        "name": "backoff_max_attempts",
        "type": "int",
        "description": "Total tries (initial call + retries) before surfacing an error.",
        "default": "3",
        "required": false
      },
      {
        "name": "backoff_exponential_factor",
        "type": "int",
        "description": "Multiplier that increases the wait time for each retry (delay = base_delay * factor^attempt).",
        "default": "2",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "BrowserConfig",
      "CrawlerRunConfig",
      "LLMConfig",
      "web crawling",
      "configuration",
      "Python"
    ],
    "prerequisites": [],
    "_content_hash": "fddadaed4dd3ea9f30daf8541e116ef96720960b6e7d84c7eab7a65d693a7e44",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/api/strategies/",
    "title": "Strategies - Crawl4AI Documentation (v0.9.x)",
    "type": "api",
    "summary": "API reference for Crawl4AI extraction and chunking strategies, covering LLMExtractionStrategy, RegexExtractionStrategy, CosineStrategy, JsonCssExtractionStrategy, and various chunking strategies with…",
    "sections": [
      {
        "heading": "Extraction Strategies",
        "content": "All extraction strategies inherit from the base `ExtractionStrategy` class and implement two key methods:\n- `extract(url: str, html: str) -> List[Dict[str, Any]]`\n- `run(url: str, sections:…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "LLMExtractionStrategy",
        "content": "Used for extracting structured data using Language Models.",
        "code_blocks": [
          {
            "language": "python",
            "code": "LLMExtractionStrategy(\n    # Required Parameters\n    provider: str = DEFAULT_PROVIDER,     # LLM provider (e.g., \"ollama/llama2\")\n    api_token: Optional[str] = None,      # API token\n\n    #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "RegexExtractionStrategy",
        "content": "Used for fast pattern-based extraction of common entities using regular expressions.",
        "code_blocks": [
          {
            "language": "python",
            "code": "RegexExtractionStrategy(\n    # Pattern Configuration\n    pattern: IntFlag = RegexExtractionStrategy.Nothing,  # Bit flags of built-in patterns to use\n    custom: Optional[Dict[str, str]] = None,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "CosineStrategy",
        "content": "Used for content similarity-based extraction and clustering.",
        "code_blocks": [
          {
            "language": "python",
            "code": "CosineStrategy(\n    # Content Filtering\n    semantic_filter: str = None,        # Topic/keyword filter\n    word_count_threshold: int = 10,     # Minimum words per cluster\n    sim_threshold: float =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "JsonCssExtractionStrategy",
        "content": "Used for CSS selector-based structured data extraction.",
        "code_blocks": [
          {
            "language": "python",
            "code": "JsonCssExtractionStrategy(\n    schema: Dict[str, Any],    # Extraction schema\n    verbose: bool = False      # Enable verbose logging\n)\n\n# Schema Structure\nschema = {\n    \"name\": str,              #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Chunking Strategies",
        "content": "All chunking strategies inherit from `ChunkingStrategy` and implement the `chunk(text: str) -> list` method.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "RegexChunking",
        "content": "Splits text based on regex patterns.",
        "code_blocks": [
          {
            "language": "python",
            "code": "RegexChunking(\n    patterns: List[str] = None  # Regex patterns for splitting\n                               # Default: [r'\\n\\n']\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "SlidingWindowChunking",
        "content": "Creates overlapping chunks with a sliding window approach.",
        "code_blocks": [
          {
            "language": "python",
            "code": "SlidingWindowChunking(\n    window_size: int = 100,    # Window size in words\n    step: int = 50             # Step size between windows\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "OverlappingWindowChunking",
        "content": "Creates chunks with specified overlap.",
        "code_blocks": [
          {
            "language": "python",
            "code": "OverlappingWindowChunking(\n    window_size: int = 1000,   # Chunk size in words\n    overlap: int = 100         # Overlap size in words\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Usage Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "LLM Extraction",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from pydantic import BaseModel\nfrom crawl4ai import LLMExtractionStrategy\nfrom crawl4ai import LLMConfig\n\n# Define schema\nclass Article(BaseModel):\n    title: str\n    content: str\n    author: str\n\n#…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Regex Extraction",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, RegexExtractionStrategy\n\n# Method 1: Use built-in patterns\nstrategy = RegexExtractionStrategy(\n    pattern =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "CSS Extraction",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy\n\n# Define schema\nschema = {\n    \"name\": \"Product List\",\n    \"baseSelector\": \".product-card\",\n    \"fields\": [\n        {\n            \"name\": \"title\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Content Chunking",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.chunking_strategy import OverlappingWindowChunking\nfrom crawl4ai import LLMConfig\n\n# Create chunking strategy\nchunker = OverlappingWindowChunking(\n    window_size=500,  # 500 words per…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Choose the Right Strategy",
        "content": "- Use `RegexExtractionStrategy` for common data types like emails, phones, URLs, dates\n- Use `JsonCssExtractionStrategy` for well-structured HTML with consistent patterns\n- Use…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Strategy Selection Guide",
        "content": "",
        "code_blocks": [
          {
            "language": "text",
            "code": "Is the target data a common type (email/phone/date/URL)? \n→ RegexExtractionStrategy\n\nDoes the page have consistent HTML structure?\n→ JsonCssExtractionStrategy or JsonXPathExtractionStrategy\n\nIs the…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Optimize Chunking",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# For long documents\nstrategy = LLMExtractionStrategy(\n    chunk_token_threshold=2000,  # Smaller chunks\n    overlap_rate=0.1           # 10% overlap\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combine Strategies for Best Performance",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# First pass: Extract structure with CSS\ncss_strategy = JsonCssExtractionStrategy(product_schema)\ncss_result = await crawler.arun(url,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Handle Errors",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "try:\n    result = await crawler.arun(\n        url=\"https://example.com\",\n        extraction_strategy=strategy\n    )\n    if result.success:\n        content =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Monitor Performance",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    verbose=True,  # Enable logging\n    word_count_threshold=20,  # Filter short content\n    top_k=5  # Limit results\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Cache Generated Patterns",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# For RegexExtractionStrategy pattern generation\nimport json\nfrom pathlib import Path\n\ncache_dir = Path(\"./pattern_cache\")\ncache_dir.mkdir(exist_ok=True)\npattern_file = cache_dir /…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "provider",
        "type": "str",
        "description": "LLM provider (e.g., \"ollama/llama2\").",
        "default": "DEFAULT_PROVIDER",
        "required": false
      },
      {
        "name": "api_token",
        "type": "Optional[str]",
        "description": "API token.",
        "default": "None",
        "required": false
      },
      {
        "name": "instruction",
        "type": "str",
        "description": "Custom extraction instruction.",
        "default": "None",
        "required": false
      },
      {
        "name": "schema",
        "type": "Dict",
        "description": "Pydantic model schema for structured data (LLMExtractionStrategy).",
        "default": "None",
        "required": false
      },
      {
        "name": "extraction_type",
        "type": "str",
        "description": "\"block\" or \"schema\".",
        "default": "\"block\"",
        "required": false
      },
      {
        "name": "chunk_token_threshold",
        "type": "int",
        "description": "Maximum tokens per chunk.",
        "default": "4000",
        "required": false
      },
      {
        "name": "overlap_rate",
        "type": "float",
        "description": "Overlap between chunks.",
        "default": "0.1",
        "required": false
      },
      {
        "name": "word_token_rate",
        "type": "float",
        "description": "Word to token conversion rate.",
        "default": "0.75",
        "required": false
      },
      {
        "name": "apply_chunking",
        "type": "bool",
        "description": "Enable/disable chunking.",
        "default": "True",
        "required": false
      },
      {
        "name": "base_url",
        "type": "str",
        "description": "Base URL for API.",
        "default": "None",
        "required": false
      },
      {
        "name": "extra_args",
        "type": "Dict",
        "description": "Additional provider arguments.",
        "default": "{}",
        "required": false
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Enable verbose logging (LLMExtractionStrategy).",
        "default": "False",
        "required": false
      },
      {
        "name": "pattern",
        "type": "IntFlag",
        "description": "Bit flags of built-in patterns to use.",
        "default": "RegexExtractionStrategy.Nothing",
        "required": false
      },
      {
        "name": "custom",
        "type": "Optional[Dict[str, str]]",
        "description": "Custom pattern dictionary {label: regex}.",
        "default": "None",
        "required": false
      },
      {
        "name": "input_format",
        "type": "str",
        "description": "\"html\", \"markdown\", \"text\" or \"fit_html\".",
        "default": "\"fit_html\"",
        "required": false
      },
      {
        "name": "semantic_filter",
        "type": "str",
        "description": "Topic/keyword filter.",
        "default": "None",
        "required": false
      },
      {
        "name": "word_count_threshold",
        "type": "int",
        "description": "Minimum words per cluster.",
        "default": "10",
        "required": false
      },
      {
        "name": "sim_threshold",
        "type": "float",
        "description": "Similarity threshold.",
        "default": "0.3",
        "required": false
      },
      {
        "name": "max_dist",
        "type": "float",
        "description": "Maximum cluster distance.",
        "default": "0.2",
        "required": false
      },
      {
        "name": "linkage_method",
        "type": "str",
        "description": "Clustering method.",
        "default": "'ward'",
        "required": false
      },
      {
        "name": "top_k",
        "type": "int",
        "description": "Top clusters to return.",
        "default": "3",
        "required": false
      },
      {
        "name": "model_name",
        "type": "str",
        "description": "Embedding model.",
        "default": "'sentence-transformers/all-MiniLM-L6-v2'",
        "required": false
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Enable verbose logging (CosineStrategy).",
        "default": "False",
        "required": false
      },
      {
        "name": "schema",
        "type": "Dict[str, Any]",
        "description": "Extraction schema (JsonCssExtractionStrategy).",
        "default": "",
        "required": true
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Enable verbose logging (JsonCssExtractionStrategy).",
        "default": "False",
        "required": false
      },
      {
        "name": "patterns",
        "type": "List[str]",
        "description": "Regex patterns for splitting. Default: [r'\\n\\n']",
        "default": "None",
        "required": false
      },
      {
        "name": "window_size",
        "type": "int",
        "description": "Window size in words (SlidingWindowChunking).",
        "default": "100",
        "required": false
      },
      {
        "name": "step",
        "type": "int",
        "description": "Step size between windows.",
        "default": "50",
        "required": false
      },
      {
        "name": "window_size",
        "type": "int",
        "description": "Chunk size in words (OverlappingWindowChunking).",
        "default": "1000",
        "required": false
      },
      {
        "name": "overlap",
        "type": "int",
        "description": "Overlap size in words.",
        "default": "100",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "ExtractionStrategy",
      "ChunkingStrategy",
      "LLM",
      "Regex",
      "CSS",
      "CosineSimilarity",
      "WebScraping",
      "DataExtraction",
      "Chunking"
    ],
    "prerequisites": [],
    "_content_hash": "6bfa35335b831a7f7000e299b102a543b49e30e89d9b8ada8e6b7a89c8ec7236",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/apps/",
    "title": "🚀 Crawl4AI Interactive Apps",
    "type": "overview",
    "summary": "Overview of Crawl4AI's interactive demo apps, including the C4A-Script editor, LLM context builder, Chrome extension assistant, and upcoming tools for scraping experiments, prompt design, and…",
    "sections": [
      {
        "heading": "🚀 Crawl4AI Interactive Apps",
        "content": "Welcome to the Crawl4AI Apps Hub - your gateway to interactive tools and demos that make web scraping more intuitive and powerful.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🛠️ Interactive Tools for Modern Web Scraping",
        "content": "Our apps are designed to make Crawl4AI more accessible and powerful. Whether you're learning browser automation, designing extraction strategies, or building complex scrapers, these tools provide…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🎯 Available Apps",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🎨 C4A-Script Interactive Editor",
        "content": "Available\n\nA visual, block-based programming environment for creating browser automation scripts. Perfect for beginners and experts alike!\n\n- Drag-and-drop visual programming\n- Real-time JavaScript…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🧠 LLM Context Builder",
        "content": "Available\n\nGenerate optimized context files for your favorite LLM when working with Crawl4AI. Get focused, relevant documentation based on your needs.\n\n- Modular context generation\n- Memory,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🕸️ Web Scraping Playground",
        "content": "Coming Soon\n\nTest your scraping strategies on real websites with instant feedback. See how different configurations affect your results.\n\n- Live website testing\n- Side-by-side result comparison\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🔍 Crawl4AI Assistant (Chrome Extension)",
        "content": "Available\n\nVisual schema builder Chrome extension - click on webpage elements to generate extraction schemas and Python code!\n\n- Visual element selection\n- Container & field selection modes\n- Smart…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🧪 Extraction Lab",
        "content": "Coming Soon\n\nExperiment with different extraction strategies and see how they perform on your content. Compare LLM vs CSS vs XPath approaches.\n\n- Strategy comparison tools\n- Performance benchmarks\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🤖 AI Prompt Designer",
        "content": "Coming Soon\n\nCraft and test prompts for LLM-based extraction. See how different prompts affect extraction quality and costs.\n\n- Prompt templates library\n- A/B testing interface\n- Token usage…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "📊 Crawl Monitor",
        "content": "Coming Soon\n\nReal-time monitoring dashboard for your crawling operations. Track performance, debug issues, and optimize your scrapers.\n\n- Real-time crawl statistics\n- Error tracking and debugging\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🚀 Why Use These Apps?",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🎯 Accelerate Learning",
        "content": "Visual tools help you understand Crawl4AI's concepts faster than reading documentation alone.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "💡 Reduce Development Time",
        "content": "Generate working code instantly instead of writing everything from scratch.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🔍 Improve Quality",
        "content": "Test and refine your approach before deploying to production.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "🤝 Community Driven",
        "content": "These tools are built based on user feedback. Have an idea? [Let us know](https://github.com/unclecode/crawl4ai/issues)!",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "📢 Stay Updated",
        "content": "Want to know when new apps are released?\n\n- ⭐ [Star us on GitHub](https://github.com/unclecode/crawl4ai) to get notifications\n- 🐦 Follow [@unclecode](https://twitter.com/unclecode) for…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Developer Resources",
        "content": "Building your own tools with Crawl4AI? Check out our [API Reference](../api/async-webcrawler/) and [Integration Guide](../advanced/advanced-features/) for comprehensive documentation.",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Web Scraping",
      "Interactive Apps",
      "Browser Automation",
      "LLM",
      "Chrome Extension",
      "Visual Programming",
      "Developer Tools"
    ],
    "prerequisites": [],
    "_content_hash": "f049f20ca197ebee5ca039c2e3364596163713d3e851eec62a7632a016d63640",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/apps/llmtxt/build/",
    "title": "Build - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page contains a detailed prompt for an AI coding assistant to build an interactive HTML/JavaScript page that lets users select and combine crawl4ai LLM context Markdown files into a single…",
    "sections": [
      {
        "heading": "Objective",
        "content": "Your task is to create an interactive HTML webpage with JavaScript functionality that allows users to select and combine different `crawl4ai` LLM context files into a single downloadable Markdown…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Core Functionality",
        "content": "- **Display `crawl4ai` Components:** The page will list all available `crawl4ai` documentation components.\n- **Select Context Types:** For each component, users can select which types of context they…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Input/Assumptions",
        "content": "- **Context Files Location:** All individual context Markdown files are located on the server in a publicly accessible folder named `llmtxt/`.\n- **File Naming Convention:** Files follow the pattern:…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Detailed UI/UX Requirements",
        "content": "- **Main Page Structure:**\n  - **Header:** \"Crawl4AI Interactive LLM Context Builder\"\n  - **Introduction:** Briefly explain the purpose of the tool (from the `USING_LLM_CONTEXTS.md` content you…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Final Output",
        "content": "- A single HTML file (e.g., `interactive_context_builder.html`).\n- Associated JavaScript code (can be inline within `<script>` tags or in a separate `.js` file).\n- Associated CSS code (can be inline…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "LLM context",
      "HTML",
      "JavaScript",
      "Markdown",
      "interactive builder",
      "AI coding assistant",
      "documentation tool"
    ],
    "prerequisites": [],
    "_content_hash": "b8361488ee19f1208dd3a37ab2a7ca88af49daaeee5dc900fe917727a1399562",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/apps/llmtxt/why/",
    "title": "Supercharging Your AI Assistant: My Journey to Better LLM Contexts for `crawl4ai`",
    "type": "guide",
    "summary": "Explains the limitations of standard llm.txt files for providing AI coding assistants with context for crawl4ai, and introduces a multi-dimensional, modular context system using memory, reasoning,…",
    "sections": [
      {
        "heading": "Introduction",
        "content": "When I started diving deep into using AI coding assistants with my own libraries, particularly `crawl4ai`, I quickly realized that the common approach to providing context via a simple `llm.txt` or…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "My Frustration with Standard `llm.txt` Files",
        "content": "My experience with generic `llm.txt` files for complex libraries like `crawl4ai` revealed several pain points:\n\n- **Information Overload & Lost Focus:** I found that when I threw a massive,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Inspiration: Selective Inclusion & Multi-Dimensional Understanding",
        "content": "I've always admired how libraries like Lodash or jQuery (in its modular days) allowed developers to pick and choose only the parts they needed, resulting in smaller, more focused bundles. This idea…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "LLM",
      "AI assistants",
      "documentation",
      "context engineering",
      "llm.txt",
      "modular contexts"
    ],
    "prerequisites": [],
    "_content_hash": "ba06eaeaa0bddbeba85a079552c363e998f56afd9fd362fb82bead465967fd94",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/basic/installation/",
    "title": "Installation 💻 - Crawl4AI Documentation (v0.9.x)",
    "type": "reference",
    "summary": "Extraction fallback content.",
    "sections": [
      {
        "heading": "Installation 💻 - Crawl4AI Documentation (v0.9.x)",
        "content": "\n\n\n##### Installation 💻\n\n\n\n\nCrawl4AI offers flexible installation options to suit various use cases. You can install it as a Python package, use it with Docker, or run it as a local server.\n\n\n\n\n##### Option 1: Python Package Installation (Recommended)\n\n\n\n\nCrawl4AI is now available on PyPI, making installation easier than ever. Choose the option that best fits your needs:\n\n\n\n\n###### Basic Installation\n\n\n\n\nFor basic web crawling and scraping tasks:\n\n\n\n\n\n###### Installation with PyTorch\n\n\n\n\nFor advanced text clustering (includes CosineSimilarity cluster strategy):\n\n\n\n\n\n###### Installation with Transformers\n\n\n\n\nFor text summarization and Hugging Face models:\n\n\n\n\n\n###### Full Installation\n\n\n\n\nFor all features:\n\n\n\n\n\n###### Development Installation\n\n\n\n\nFor contributors who plan to modify the source code:\n\n\n\n\n\n💡 After installation with \"torch\", \"transformer\", or \"all\" options, it's recommended to run the following CLI command to load the required models:\n\n\n\n\n\nThis is optional but will boost the performance and speed of the crawler. You only need to do this once after installation.\n\n\n\n\n##### Playwright Installation Note for Ubuntu\n\n\n\n\nIf you encounter issues with Playwright installation on Ubuntu, you may need to install additional dependencies:\n\n\n\n\n\n##### Option 2: Using Docker (Coming Soon)\n\n\n\n\nDocker support for Crawl4AI is currently in progress and will be available soon. This will allow you to run Crawl4AI in a containerized environment, ensuring consistency across different systems.\n\n\n\n\n##### Option 3: Local Server Installation\n\n\n\n\nFor those who prefer to run Crawl4AI as a local server, instructions will be provided once the Docker implementation is complete.\n\n\n\n\n##### Verifying Your Installation\n\n\n\n\nAfter installation, you can verify that Crawl4AI is working correctly by running a simple Python script:\n\n\n\n\n\nThis script should successfully crawl the example website and print the first 500 characters of the extracted content.\n\n\n\n\n##### Getting Help\n\n\n\n\nIf you encounter any issues during installation or usage, please check the [documentation](https://docs.crawl4ai.com/) or raise an issue on the [GitHub repository](https://github.com/unclecode/crawl4ai/issues).\n\n\n\n\nHappy crawling! 🕷️🤖\n\n\n\nPage Copy\nPage Copy\n\n\n\n\n- [Copy as Markdown\nCopy page for LLMs](#)\n\n- [View as Markdown\nOpen raw source](#)\n\n\n- [Open in ChatGPT\nAsk questions about this page](#)\n\n\n\nESC to close\n",
        "code_blocks": [
          {
            "language": "bash",
            "code": "pip install crawl4ai\nplaywright install # Install Playwright dependencies",
            "filename": ""
          },
          {
            "language": "css",
            "code": "pip install crawl4ai[torch]",
            "filename": ""
          },
          {
            "language": "css",
            "code": "pip install crawl4ai[transformer]",
            "filename": ""
          },
          {
            "language": "css",
            "code": "pip install crawl4ai[all]",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "git clone https://github.com/unclecode/crawl4ai.git\ncd crawl4ai\npip install -e \".[all]\"\nplaywright install # Install Playwright dependencies",
            "filename": ""
          },
          {
            "language": "undefined",
            "code": "crawl4ai-download-models",
            "filename": ""
          },
          {
            "language": "csharp",
            "code": "sudo apt-get install -y \\\n    libwoff1 \\\n    libopus0 \\\n    libwebp7 \\\n    libwebpdemux2 \\\n    libenchant-2-2 \\\n    libgudev-1.0-0 \\\n    libsecret-1-0 \\\n    libhyphen0 \\\n    libgdk-pixbuf2.0-0 \\\n    libegl1 \\\n    libnotify4 \\\n    libxslt1.1 \\\n    libevent-2.1-7 \\\n    libgles2 \\\n    libxcomposite1 \\\n    libatk1.0-0 \\\n    libatk-bridge2.0-0 \\\n    libepoxy0 \\\n    libgtk-3-0 \\\n    libharfbuzz-icu0 \\\n    libgstreamer-gl1.0-0 \\\n    libgstreamer-plugins-bad1.0-0 \\\n    gstreamer1.0-plugins-good \\\n    gstreamer1.0-plugins-bad \\\n    libxt6 \\\n    libxaw7 \\\n    xvfb \\\n    fonts-noto-color-emoji \\\n    libfontconfig \\\n    libfreetype6 \\\n    xfonts-cyrillic \\\n    xfonts-scalable \\\n    fonts-liberation \\\n    fonts-ipafont-gothic \\\n    fonts-wqy-zenhei \\\n    fonts-tlwg-loma-otf \\\n    fonts-freefont-ttf",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    async with AsyncWebCrawler(verbose=True) as crawler:\n        result = await crawler.arun(url=\"https://www.example.com\")\n        print(result.markdown[:500])  # Print first 500 characters\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [],
    "prerequisites": [],
    "_content_hash": "63ef09737172ff6bca9840f3be3bfbc94a5ce9fbea7393c09c7104ea6a6bad03",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/complete-sdk-reference/",
    "title": "Crawl4AI Complete SDK Documentation",
    "type": "reference",
    "summary": "Comprehensive SDK reference for Crawl4AI, covering installation, quick start, core API (AsyncWebCrawler, arun, arun_many, CrawlResult), configuration, and extraction strategies.",
    "sections": [
      {
        "heading": "Installation & Setup",
        "content": "##### Installation & Setup (2023 Edition)\n\n##### 1. Basic Installation\n\n##### 2. Initial Setup & Diagnostics\n\n###### 2.1 Run the Setup Command\n\n- Performs OS-level checks (e.g., missing libs on Linux)\n- Confirms…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "pip install crawl4ai",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crawl4ai-doctor",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(…",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "pip install crawl4ai[torch]\ncrawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "pip install crawl4ai[transformer]\ncrawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "pip install crawl4ai[all]\ncrawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crawl4ai-download-models",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "docker pull unclecode/crawl4ai:basic\ndocker run -p 11235:11235 unclecode/crawl4ai:basic",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "##### Getting Started with Crawl4AI\n\n- Run your **first crawl** using minimal configuration.\n- Experiment with a simple **CSS-based extraction** strategy.\n- Crawl a **dynamic** page that loads content…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(\"https://example.com\")…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def main():\n    browser_conf = BrowserConfig(headless=True)  # or False to see the browser…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.content_filter_strategy import PruningContentFilter\nfrom crawl4ai.markdown_generation_strategy import…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy\nfrom crawl4ai import LLMConfig\n\n# Generate a schema (one-time cost)\nhtml = \"<div class='product'><h2>Gaming Laptop</h2><span…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    schema = {\n        \"name\": \"Example…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import os\nimport json\nimport asyncio\nfrom pydantic import BaseModel, Field\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig\nfrom crawl4ai import LLMExtractionStrategy\n\nclass…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, AdaptiveCrawler\n\nasync def adaptive_example():\n    async with AsyncWebCrawler() as crawler:\n        adaptive = AdaptiveCrawler(crawler)\n\n        #…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def quick_parallel_example():\n    urls = [\n        \"https://example.com/page1\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Core API",
        "content": "##### AsyncWebCrawler\n\nThe **`AsyncWebCrawler`** is the core class for asynchronous web crawling in Crawl4AI. You typically create it **once**, optionally customize it with a **`BrowserConfig`** (e.g.,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class AsyncWebCrawler:\n    def __init__(\n        self,\n        crawler_strategy: Optional[AsyncCrawlerStrategy] = None,\n        config: Optional[BrowserConfig] = None,\n        always_bypass_cache:…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig\nbrowser_cfg = BrowserConfig(\n    browser_type=\"chromium\",\n    headless=True,\n    verbose=True\n)\ncrawler = AsyncWebCrawler(config=browser_cfg)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async with AsyncWebCrawler(config=browser_cfg) as crawler:\n    result = await crawler.arun(\"https://example.com\")\n    # The crawler automatically starts/closes resources",
            "filename": ""
          },
          {
            "language": "python",
            "code": "crawler = AsyncWebCrawler(config=browser_cfg)\nawait crawler.start()\nresult1 = await crawler.arun(\"https://example.com\")\nresult2 = await crawler.arun(\"https://another.com\")\nawait crawler.close()",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def arun(\n    url: str,\n    config: Optional[CrawlerRunConfig] = None,\n    # Legacy parameters for backward compatibility...",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import CrawlerRunConfig, CacheMode\nrun_cfg = CrawlerRunConfig(\n    cache_mode=CacheMode.BYPASS,\n    css_selector=\"main.article\",\n    word_count_threshold=10,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def arun_many(\n    urls: List[str],\n    config: Optional[CrawlerRunConfig] = None,\n    # Legacy parameters maintained for backwards compatibility...",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\nimport json\n\nasync def main():\n    # 1. Browser config…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_cfg = CrawlerRunConfig(css_selector=\".main-content\", word_count_threshold=20)\nresult = await crawler.arun(url=\"...\", config=run_cfg)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`arun()` Parameter Guide (New Approach)",
        "content": "In Crawl4AI’s **latest** configuration model, nearly all parameters that once went directly to `arun()` are now part of **`CrawlerRunConfig`**. When calling `arun()`, you provide:\n\nBelow is an…",
        "code_blocks": [
          {
            "language": "python",
            "code": "await crawler.arun(\n    url=\"https://example.com\",  \n    config=my_run_config\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    run_config = CrawlerRunConfig(\n        verbose=True,            # Detailed logging…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    cache_mode=CacheMode.BYPASS\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    word_count_threshold=10,   # Ignore text blocks <10 words\n    only_text=False,           # If True, tries to remove non-text elements\n    keep_data_attributes=False…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    css_selector=\".main-content\",  # Focus on .main-content region only\n    excluded_tags=[\"form\", \"nav\"], # Remove entire tag blocks\n    remove_forms=True,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    exclude_external_links=True,         # Remove external links from final content\n    exclude_social_media_links=True,     # Remove links to known social sites…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    exclude_external_images=True  # Strip images from other domains\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    wait_for=\"css:.dynamic-content\", # Wait for .dynamic-content\n    delay_before_return_html=2.0,    # Wait 2s before capturing final HTML\n    page_timeout=60000,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    js_code=[\n        \"window.scrollTo(0, document.body.scrollHeight);\",\n        \"document.querySelector('.load-more')?.click();\"\n    ],\n    js_only=False\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    magic=True,\n    simulate_user=True,\n    override_navigator=True\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    session_id=\"my_session123\"\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    screenshot=True,             # Grab a screenshot as base64\n    screenshot_wait_for=1.0,     # Wait 1s before capturing\n    pdf=True,                    # Also…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    extraction_strategy=my_css_or_llm_strategy\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    # Example schema\n    schema = {\n        \"name\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`arun_many(...)` Reference",
        "content": "> **Note**: This function is very similar to [`arun()`](./arun.md) but focused on **concurrent** or **batch** crawling. If you’re unfamiliar with `arun()` usage, please read that doc first, then…",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def arun_many(\n    urls: Union[List[str], List[Any]],\n    config: Optional[Union[CrawlerRunConfig, List[CrawlerRunConfig]]] = None,\n    dispatcher: Optional[BaseDispatcher] = None,\n    ...\n) ->…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Minimal usage: The default dispatcher will be used\nresults = await crawler.arun_many(\n    urls=[\"https://site1.com\", \"https://site2.com\"],\n    config=CrawlerRunConfig(stream=False)  # Default…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    stream=True,  # Enable streaming mode\n    cache_mode=CacheMode.BYPASS\n)\n\n# Process results as they complete\nasync for result in await crawler.arun_many(…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "dispatcher = MemoryAdaptiveDispatcher(\n    memory_threshold_percent=70.0,\n    max_session_permit=10\n)\nresults = await crawler.arun_many(\n    urls=[\"https://site1.com\", \"https://site2.com\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import CrawlerRunConfig, MatchMode\nfrom crawl4ai.processors.pdf import PDFContentScrapingStrategy\nfrom crawl4ai.extraction_strategy import JsonCssExtractionStrategy\nfrom…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "`CrawlResult` Reference",
        "content": "The **`CrawlResult`** class encapsulates everything returned after a single crawl operation. It provides the **raw or processed content**, details on links and media, plus optional metadata (like…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class CrawlResult(BaseModel):\n    url: str\n    html: str\n    success: bool\n    cleaned_html: Optional[str] = None\n    fit_html: Optional[str] = None  # Preprocessed HTML optimized for extraction…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "print(result.url)  # e.g., \"https://example.com/\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if not result.success:\n    print(f\"Crawl failed: {result.error_message}\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.status_code == 404:\n    print(\"Page not found!\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if not result.success:\n    print(\"Error:\", result.error_message)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# If you used session_id=\"login_session\" in CrawlerRunConfig, see it here:\nprint(\"Session:\", result.session_id)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.response_headers:\n    print(\"Server:\", result.response_headers.get(\"Server\", \"Unknown\"))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.ssl_certificate:\n    print(\"Issuer:\", result.ssl_certificate.issuer)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Possibly large\nprint(len(result.html))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "print(result.cleaned_html[:500])  # Show a snippet",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.markdown:\n    md_res = result.markdown\n    print(\"Raw MD:\", md_res.raw_markdown[:300])\n    print(\"Citations MD:\", md_res.markdown_with_citations[:300])\n    print(\"References:\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "print(result.markdown.raw_markdown[:200])\nprint(result.markdown.fit_markdown)\nprint(result.markdown.fit_html)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "images = result.media.get(\"images\", [])\nfor img in images:\n    if img.get(\"score\", 0) > 5:\n        print(\"High-value image:\", img[\"src\"])",
            "filename": ""
          },
          {
            "language": "python",
            "code": "for link in result.links[\"internal\"]:\n    print(f\"Internal link to {link['href']} with text {link['text']}\")",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.extracted_content:\n    data = json.loads(result.extracted_content)\n    print(data)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.downloaded_files:\n    for file_path in result.downloaded_files:\n        print(\"Downloaded:\", file_path)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import base64\nif result.screenshot:\n    with open(\"page.png\", \"wb\") as f:\n        f.write(base64.b64decode(result.screenshot))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.pdf:\n    with open(\"page.pdf\", \"wb\") as f:\n        f.write(result.pdf)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.mhtml:\n    with open(\"page.mhtml\", \"w\", encoding=\"utf-8\") as f:\n        f.write(result.mhtml)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.metadata:\n    print(\"Title:\", result.metadata.get(\"title\"))\n    print(\"Author:\", result.metadata.get(\"author\"))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Example usage:\nfor result in results:\n    if result.success and result.dispatch_result:\n        dr = result.dispatch_result\n        print(f\"URL: {result.url}, Task ID: {dr.task_id}\")…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "crawler_strategy",
        "type": "Optional[AsyncCrawlerStrategy]",
        "description": "(Advanced) Provide a custom crawler strategy if needed.",
        "default": "None",
        "required": false
      },
      {
        "name": "config",
        "type": "Optional[BrowserConfig]",
        "description": "A BrowserConfig object specifying how the browser is set up.",
        "default": "None",
        "required": false
      },
      {
        "name": "always_bypass_cache",
        "type": "bool",
        "description": "(Deprecated) Use CrawlerRunConfig.cache_mode instead.",
        "default": "False",
        "required": false
      },
      {
        "name": "always_by_pass_cache",
        "type": "Optional[bool]",
        "description": "(Deprecated) Use CrawlerRunConfig.cache_mode instead.",
        "default": "None",
        "required": false
      },
      {
        "name": "base_directory",
        "type": "str",
        "description": "Folder for storing caches/logs (if relevant).",
        "default": "",
        "required": false
      },
      {
        "name": "thread_safe",
        "type": "bool",
        "description": "If True, attempts some concurrency safeguards. Usually False.",
        "default": "False",
        "required": false
      },
      {
        "name": "url",
        "type": "str",
        "description": "The URL to crawl.",
        "default": "",
        "required": true
      },
      {
        "name": "config (arun)",
        "type": "Optional[CrawlerRunConfig]",
        "description": "A CrawlerRunConfig object that sets up everything about a crawl—content filtering, caching, session reuse, JS code, screenshots, etc.",
        "default": "None",
        "required": false
      },
      {
        "name": "urls",
        "type": "Union[List[str], List[Any]]",
        "description": "A list of URLs (or tasks) to crawl.",
        "default": "",
        "required": true
      },
      {
        "name": "config (arun_many)",
        "type": "Optional[Union[CrawlerRunConfig, List[CrawlerRunConfig]]]",
        "description": "Either a single CrawlerRunConfig applying to all URLs, or a list of CrawlerRunConfig objects with url_matcher patterns.",
        "default": "None",
        "required": false
      },
      {
        "name": "dispatcher",
        "type": "Optional[BaseDispatcher]",
        "description": "A concurrency controller (e.g. MemoryAdaptiveDispatcher).",
        "default": "None",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "web crawling",
      "async",
      "Python",
      "SDK",
      "API",
      "BrowserConfig",
      "CrawlerRunConfig",
      "AsyncWebCrawler",
      "arun",
      "arun_many",
      "CrawlResult",
      "extraction",
      "markdown",
      "CSS",
      "LLM",
      "installation",
      "quick start"
    ],
    "prerequisites": [],
    "_content_hash": "e5c904273e832ef9cbc66504a09e31f2f81e26d27d29d07f9f974b745ff18e16",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/adaptive-crawling/",
    "title": "Adaptive Web Crawling",
    "type": "guide",
    "summary": "Adaptive Web Crawling is a Crawl4AI guide to intelligent crawling, using coverage, consistency, and saturation metrics to decide when enough information has been collected. It covers configuration,…",
    "sections": [
      {
        "heading": "Introduction",
        "content": "Traditional web crawlers follow predetermined patterns, crawling pages blindly without knowing when they've gathered enough information. **Adaptive Crawling** changes this paradigm by introducing…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Concepts",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "The Problem It Solves",
        "content": "When crawling websites for specific information, you face two challenges:\n1. **Under-crawling**: Stopping too early and missing crucial information\n2. **Over-crawling**: Wasting resources by crawling…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How It Works",
        "content": "The AdaptiveCrawler uses three metrics to measure information sufficiency:\n\n- **Coverage**: How well your collected pages cover the query terms\n- **Consistency**: Whether the information is coherent…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai import AsyncWebCrawler, AdaptiveCrawler\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        # Create an adaptive crawler (config is optional)\n        adaptive =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Options",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "from crawl4ai import AdaptiveConfig\n\nconfig = AdaptiveConfig(\n    confidence_threshold=0.8,    # Stop when 80% confident (default: 0.7)\n    max_pages=30,               # Maximum pages to crawl…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Crawling Strategies",
        "content": "Adaptive Crawling supports two distinct strategies for determining information sufficiency:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Statistical Strategy (Default)",
        "content": "The statistical strategy uses pure information theory and term-based analysis:\n\n- **Fast and efficient** - No API calls or model loading\n- **Term-based coverage** - Analyzes query term presence and…",
        "code_blocks": [
          {
            "language": "",
            "code": "# Default configuration uses statistical strategy\nconfig = AdaptiveConfig(\n    strategy=\"statistical\",  # This is the default\n    confidence_threshold=0.8\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Embedding Strategy",
        "content": "The embedding strategy uses semantic embeddings for deeper understanding:\n\n- **Semantic understanding** - Captures meaning beyond exact term matches\n- **Query expansion** - Automatically generates…",
        "code_blocks": [
          {
            "language": "",
            "code": "# Configure embedding strategy with local embeddings\nconfig = AdaptiveConfig(\n    strategy=\"embedding\",\n    embedding_model=\"sentence-transformers/all-MiniLM-L6-v2\",  # Default…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Strategy Comparison",
        "content": "| Feature | Statistical | Embedding |\n| --- | --- | --- |\n| **Speed** | Very fast | Moderate (API calls) |\n| **Cost** | Free | Depends on provider |\n| **Accuracy** | Good for exact terms | Excellent…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Embedding Strategy Configuration",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "config = AdaptiveConfig(\n    strategy=\"embedding\",\n\n    # Model configuration\n    embedding_model=\"sentence-transformers/all-MiniLM-L6-v2\",\n    embedding_llm_config=None,  # Use for API-based…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Handling Irrelevant Queries",
        "content": "The embedding strategy can detect when a query is completely unrelated to the content:",
        "code_blocks": [
          {
            "language": "",
            "code": "# This will stop quickly with low confidence\nresult = await adaptive.digest(\n    start_url=\"https://docs.python.org/3/\",\n    query=\"how to cook pasta\"  # Irrelevant to Python docs\n)\n\n# Check if query…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "When to Use Adaptive Crawling",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Perfect For:",
        "content": "- **Research Tasks**: Finding comprehensive information about a topic\n- **Question Answering**: Gathering sufficient context to answer specific queries\n- **Knowledge Base Building**: Creating focused…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Not Recommended For:",
        "content": "- **Full Site Archiving**: When you need every page regardless of content\n- **Structured Data Extraction**: When targeting specific, known page patterns\n- **Real-time Monitoring**: When you need…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Understanding the Output",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Confidence Score",
        "content": "The confidence score (0-1) indicates how sufficient the gathered information is:\n- **0.0-0.3**: Insufficient information, needs more crawling\n- **0.3-0.6**: Partial information, may answer basic…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Statistics Display",
        "content": "The summary shows:\n- Pages crawled vs. confidence achieved\n- Coverage, consistency, and saturation scores\n- Crawling efficiency metrics",
        "code_blocks": [
          {
            "language": "",
            "code": "adaptive.print_stats(detailed=False)  # Summary table\nadaptive.print_stats(detailed=True)   # Detailed metrics",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Persistence and Resumption",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Saving Progress",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "config = AdaptiveConfig(\n    save_state=True,\n    state_path=\"my_crawl_state.json\"\n)\n\n# Crawl will auto-save progress\nresult = await adaptive.digest(start_url, query)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Resuming a Crawl",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Resume from saved state\nresult = await adaptive.digest(\n    start_url,\n    query,\n    resume_from=\"my_crawl_state.json\"\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Exporting Knowledge Base",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Export collected pages to JSONL\nadaptive.export_knowledge_base(\"knowledge_base.jsonl\")\n\n# Import into another session\nnew_adaptive = AdaptiveCrawler(crawler)\nawait…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Query Formulation",
        "content": "- Use specific, descriptive queries\n- Include key terms you expect to find\n- Avoid overly broad queries",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. Threshold Tuning",
        "content": "- Start with default (0.7) for general use\n- Lower to 0.5-0.6 for exploratory crawling\n- Raise to 0.8+ for exhaustive coverage",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3. Performance Optimization",
        "content": "- Use appropriate `max_pages` limits\n- Adjust `top_k_links` based on site structure\n- Enable caching for repeat crawls",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4. Link Selection",
        "content": "- The crawler prioritizes links based on:\n- Relevance to query\n- Expected information gain\n- URL structure and depth",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Research Assistant",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Gather information about a programming concept\nresult = await adaptive.digest(\n    start_url=\"https://realpython.com\",\n    query=\"python decorators implementation patterns\"\n)\n\n# Get the most…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Knowledge Base Builder",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Build a focused knowledge base about machine learning\nqueries = [\n    \"supervised learning algorithms\",\n    \"neural network architectures\",\n    \"model evaluation metrics\"\n]\n\nfor query in queries:…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "API Documentation Crawler",
        "content": "",
        "code_blocks": [
          {
            "language": "",
            "code": "# Intelligently crawl API documentation\nconfig = AdaptiveConfig(\n    confidence_threshold=0.85,  # Higher threshold for completeness\n    max_pages=30\n)\n\nadaptive = AdaptiveCrawler(crawler,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Next Steps",
        "content": "- Learn about [Advanced Adaptive Strategies](../../advanced/adaptive-strategies/)\n- Explore the [AdaptiveCrawler API Reference](../../api/adaptive-crawler/)\n- See more…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "FAQ",
        "content": "**Q: How is this different from traditional crawling?**\nA: Traditional crawling follows fixed patterns (BFS/DFS). Adaptive crawling makes intelligent decisions about which links to follow and when to…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Adaptive Web Crawling",
      "AsyncWebCrawler",
      "AdaptiveCrawler",
      "AdaptiveConfig",
      "statistical strategy",
      "embedding strategy",
      "web scraping",
      "coverage",
      "consistency",
      "saturation",
      "LLM embeddings"
    ],
    "prerequisites": [],
    "_content_hash": "7d9cebf27816307af12ee711138bf2158c0c4c272a9fcfd6da4cd0f6a8a10c66",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/ask-ai/",
    "title": "Ask AI - Crawl4AI Documentation (v0.9.x)",
    "type": "api",
    "summary": "This page documents the Ask AI feature in Crawl4AI, which enables users to ask questions about crawled web content using LLM providers. It covers the ask_ai method, LLM configuration, and usage…",
    "sections": [
      {
        "heading": "Overview",
        "content": "The Ask AI feature in Crawl4AI allows you to ask questions about the content you have crawled. Instead of manually parsing and analyzing the extracted content, you can leverage Large Language Models…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "To use Ask AI, you first need to crawl a page and then pass the extracted content along with your question to the ask_ai method. The method requires an LLMConfig object that specifies which LLM…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, LLMConfig\n\nasync def main():\n    llm_config = LLMConfig(provider=\"openai/gpt-4o\", api_token=\"your-api-token\")\n    async with AsyncWebCrawler() as…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "LLM Configuration",
        "content": "The LLMConfig class is used to configure the LLM provider for Ask AI. It supports a wide range of providers through the litellm library, including OpenAI, Anthropic, Google Gemini, Azure OpenAI, and…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import LLMConfig\n\n# OpenAI\nllm_config = LLMConfig(\n    provider=\"openai/gpt-4o\",\n    api_token=\"your-openai-api-token\"\n)\n\n# Anthropic\nllm_config = LLMConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Usage",
        "content": "You can customize the behavior of the LLM by providing a system prompt, adjusting the temperature, and setting the maximum number of tokens in the response. This allows you to tailor the AI's…",
        "code_blocks": [
          {
            "language": "python",
            "code": "answer = await crawler.ask_ai(\n    question=\"Extract all product names and prices from this page.\",\n    context=result.markdown,\n    llm_config=llm_config,\n    system_prompt=\"You are a helpful…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "question",
        "type": "str",
        "description": "The question you want to ask about the crawled content.",
        "default": "",
        "required": true
      },
      {
        "name": "context",
        "type": "str",
        "description": "The crawled content (typically result.markdown) that provides context for the question.",
        "default": "",
        "required": true
      },
      {
        "name": "llm_config",
        "type": "LLMConfig",
        "description": "Configuration object specifying the LLM provider, API token, and model parameters.",
        "default": "",
        "required": true
      },
      {
        "name": "system_prompt",
        "type": "str",
        "description": "Optional system prompt to guide the LLM's behavior and response format.",
        "default": "None",
        "required": false
      },
      {
        "name": "temperature",
        "type": "float",
        "description": "Controls the randomness of the LLM's output. Lower values produce more deterministic responses.",
        "default": "0.7",
        "required": false
      },
      {
        "name": "max_tokens",
        "type": "int",
        "description": "Maximum number of tokens to generate in the response.",
        "default": "1024",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "ask-ai",
      "llm",
      "openai",
      "anthropic",
      "gemini",
      "ollama",
      "web-crawling",
      "ai",
      "litellm"
    ],
    "prerequisites": [],
    "_content_hash": "15509eab59f3548f25437fa0c97901e3185795ea4f1697c62720362f556baccd",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/browser-crawler-config/",
    "title": "Browser, Crawler & LLM Configuration (Quick Overview)",
    "type": "guide",
    "summary": "Overview of the three core configuration classes in Crawl4AI — BrowserConfig, CrawlerRunConfig, and LLMConfig — explaining their most commonly used parameters, helper methods, and how to combine them…",
    "sections": [
      {
        "heading": "Overview",
        "content": "Crawl4AI's flexibility stems from two key classes:\n\n- **`BrowserConfig`**  – Dictates  **how**  the browser is launched and behaves (e.g., headless or visible, proxy, user agent).\n\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. BrowserConfig Essentials",
        "content": "###### Key Fields to Note\n\n1.⠀ **`browser_type`** \n\n   - Options: `\"chromium\"`, `\"firefox\"`, or `\"webkit\"`.\n\n   - Defaults to `\"chromium\"`.\n\n   - If you need a different engine, specify it here.\n\n2.⠀…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class BrowserConfig:\n    def __init__(\n        browser_type=\"chromium\",\n        headless=True,\n        browser_mode=\"dedicated\",\n        use_managed_browser=False,\n        cdp_url=None,…",
            "filename": ""
          },
          {
            "language": "json",
            "code": "{\n    \"server\": \"http://proxy.example.com:8080\", \n    \"username\": \"...\", \n    \"password\": \"...\"\n}",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Create a base browser config\nbase_browser = BrowserConfig(\n    browser_type=\"chromium\",\n    headless=True,\n    text_mode=True\n)\n\n# Create a visible browser config for debugging\ndebug_browser =…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import BrowserConfig, CrawlerRunConfig\n\n# At application startup — one time\nBrowserConfig.set_defaults(\n    cache_cdp_connection=True,\n    cdp_close_delay=0,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig\n\nbrowser_conf = BrowserConfig(\n    browser_type=\"firefox\",\n    headless=False,\n    text_mode=True\n)\n\nasync with…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. CrawlerRunConfig Essentials",
        "content": "###### Key Fields to Note\n\n1.⠀ **`word_count_threshold`** :\n\n   - The minimum word count before a block is considered.\n\n   - If your site has lots of short paragraphs or items, you can lower it.\n\n2.⠀…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class CrawlerRunConfig:\n    def __init__(\n        word_count_threshold=200,\n        extraction_strategy=None,\n        chunking_strategy=RegexChunking(),\n        markdown_generator=None,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Create a base configuration\nbase_config = CrawlerRunConfig(\n    cache_mode=CacheMode.ENABLED,\n    word_count_threshold=200,\n    wait_until=\"networkidle\"\n)\n\n# Create variations for different use…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. LLMConfig Essentials",
        "content": "###### Key fields to note\n\n1.⠀ **`provider`** :\n\n- Which LLM provider to use. \n- Possible values are `\"ollama/llama3\",\"groq/llama3-70b-8192\",\"groq/llama3-8b-8192\", \"openai/gpt-4o-mini\"…",
        "code_blocks": [
          {
            "language": "python",
            "code": "llm_config = LLMConfig(\n    provider=\"openai/gpt-4o-mini\",\n    api_token=os.getenv(\"OPENAI_API_KEY\"),\n    backoff_base_delay=1, # optional\n    backoff_max_attempts=5, # optional…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Putting It All Together",
        "content": "In a typical scenario, you define  **one**  `BrowserConfig` for your crawler session, then create  **one or more**  `CrawlerRunConfig` & `LLMConfig` depending on each call's needs:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode, LLMConfig, LLMContentFilter, DefaultMarkdownGenerator\nfrom crawl4ai import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Next Steps",
        "content": "For a  **detailed list**  of available parameters (including advanced ones), see:\n\n- [BrowserConfig, CrawlerRunConfig & LLMConfig Reference](../../api/parameters/)\n\nYou can explore topics like:\n\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6. Conclusion",
        "content": "**BrowserConfig** ,  **CrawlerRunConfig**  and  **LLMConfig**  give you straightforward ways to define:\n\n- **Which**  browser to launch, how it should run, and any proxy or user agent needs.\n-…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "BrowserConfig",
      "CrawlerRunConfig",
      "LLMConfig",
      "Configuration",
      "Browser",
      "Crawler",
      "LLM",
      "AsyncWebCrawler",
      "Python"
    ],
    "prerequisites": [],
    "_content_hash": "2922145978d76df016e57c1b86293a18fef666ff4473ffc505d04b17d6e2c03d",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/c4a-script/",
    "title": "C4A-Script - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "A comprehensive guide to C4A-Script, a human-readable DSL for web automation, covering syntax, commands, examples, and advanced features.",
    "sections": [
      {
        "heading": "What is C4A-Script?",
        "content": "C4A-Script is a powerful, human-readable domain-specific language (DSL) designed for web automation and interaction. Think of it as a simplified programming language that anyone can read and write,…",
        "code_blocks": [
          {
            "language": "text",
            "code": "# Navigate and interact in plain English\nGO https://example.com\nWAIT `#search-box` 5\nTYPE \"Hello World\"\nCLICK `button[type=\"submit\"]`\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Getting Started: Your First Script",
        "content": "Let's create a simple script that searches for something on a website:\n\nThat's it! In just a few lines, you've automated a complete search workflow.",
        "code_blocks": [
          {
            "language": "text",
            "code": "# My first C4A-Script\nGO https://duckduckgo.com\n\n# Wait for the search box to appear\nWAIT `input[name=\"q\"]` 10\n\n# Type our search query\nTYPE \"Crawl4AI\"\n\n# Press Enter to search\nPRESS Enter\n\n# Wait…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Interactive Tutorial & Live Demo",
        "content": "Want to learn by doing? We've got you covered:\n\n**🚀 [Live Demo](https://docs.crawl4ai.com/apps/c4a-script/)** - Try C4A-Script in your browser right now!\n\n**📁 [Tutorial…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "# Clone and navigate to the tutorial\ncd docs/examples/c4a_script/tutorial/\n\n# Install dependencies\npip install -r requirements.txt\n\n# Launch the tutorial server\npython server.py\n\n# Open…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Core Concepts",
        "content": "###### Commands and Syntax\n\nC4A-Script uses simple, English-like commands. Each command does one specific thing:\n\n###### Selectors: Finding Elements\n\nC4A-Script uses CSS selectors to identify elements on…",
        "code_blocks": [
          {
            "language": "text",
            "code": "# Comments start with #\nCOMMAND parameter1 parameter2\n\n# Most commands use CSS selectors in backticks\nCLICK `#submit-button`\n\n# Text content goes in quotes\nTYPE \"Hello, World!\"\n\n# Numbers are used…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# By ID\nCLICK `#login-button`\n\n# By class\nCLICK `.submit-btn`\n\n# By attribute\nCLICK `button[type=\"submit\"]`\n\n# By accessible attributes\nCLICK `button[aria-label=\"Search\"][title=\"Search\"]`\n\n# Complex…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Set a variable\nSETVAR username = \"john@example.com\"\nSETVAR password = \"secret123\"\n\n# Use variables (prefix with $)\nTYPE $username\nPRESS Tab\nTYPE $password\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Command Categories",
        "content": "###### 🧭 Navigation Commands\n\nMove around the web like a user would:\n\n| Command | Purpose | Example |\n| --- | --- | --- |\n| `GO` | Navigate to URL | `GO https://example.com` |\n| `RELOAD` | Refresh…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Real-World Examples",
        "content": "###### Example 1: Login Flow\n\n###### Example 2: E-commerce Shopping\n\n###### Example 3: Form Automation with Conditions",
        "code_blocks": [
          {
            "language": "text",
            "code": "# Complete login automation\nGO https://myapp.com/login\n\n# Wait for page to load\nWAIT `#login-form` 5\n\n# Fill credentials\nCLICK `#email`\nTYPE \"user@example.com\"\nPRESS Tab\nTYPE \"mypassword\"\n\n# Submit…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Shopping automation with variables\nSETVAR product = \"laptop\"\nSETVAR budget = \"1000\"\n\nGO https://shop.example.com\nWAIT `#search-box` 3\n\n# Search for product\nTYPE $product\nPRESS Enter\nWAIT…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Smart form filling with error handling\nGO https://forms.example.com\n\n# Check if user is already logged in\nIF (EXISTS `.user-menu`) THEN GO https://forms.example.com/new\nIF (NOT EXISTS `.user-menu`)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Visual Programming with Blockly",
        "content": "C4A-Script includes a powerful visual programming interface built on Google Blockly. Perfect for:\n\n- **Non-programmers** who want to create automation\n- **Rapid prototyping** of automation…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Advanced Features",
        "content": "###### Recording Mode\n\nThe tutorial interface includes a recording feature that watches your browser interactions and automatically generates C4A-Script commands:\n\n- Click \"Record\" in the tutorial…",
        "code_blocks": [
          {
            "language": "text",
            "code": "# Use comments for debugging\n# This will wait up to 10 seconds for the element\nWAIT `#slow-loading-element` 10\n\n# Check if element exists before clicking\nIF (EXISTS `#optional-button`) THEN CLICK…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\n# Use C4A-Script for interaction before crawling\nscript = \"\"\"\nGO https://example.com\nCLICK `#load-more-content`\nWAIT `.dynamic-content`…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "###### 1. Always Wait for Elements\n\n###### 2. Use Descriptive Comments\n\n###### 3. Handle Variable Conditions\n\n###### 4. Use Variables for Reusability",
        "code_blocks": [
          {
            "language": "text",
            "code": "# Bad: Clicking immediately\nCLICK `#button`\n\n# Good: Wait for element to appear\nWAIT `#button` 5\nCLICK `#button`\nCopy",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Login to user account\nGO https://myapp.com/login\nWAIT `#login-form` 5\n\n# Enter credentials\nTYPE \"user@example.com\"\nPRESS Tab\nTYPE \"password123\"\n\n# Submit and wait for redirect\nCLICK…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Handle different page states\nIF (EXISTS `.cookie-banner`) THEN CLICK `.accept-cookies`\nIF (EXISTS `.popup-modal`) THEN CLICK `.close-modal`\n\n# Proceed with main workflow\nCLICK `#main-action`\nCopy",
            "filename": ""
          },
          {
            "language": "text",
            "code": "# Define once, use everywhere\nSETVAR base_url = \"https://myapp.com\"\nSETVAR test_email = \"test@example.com\"\n\nGO $base_url/login\nSET `#email` $test_email\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Getting Help",
        "content": "- **📖 [Complete Examples](/examples/c4a_script/)** - Real-world automation scripts\n- **🎮 [Interactive Tutorial](/examples/c4a_script/tutorial/)** - Hands-on learning environment\n- **📋 [API…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What's Next?",
        "content": "Ready to dive deeper? Check out:\n\n- **[API Reference](/api/c4a-script-reference/)** - Complete command documentation\n- **[Tutorial Examples](/examples/c4a_script/)** - Copy-paste ready scripts\n-…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "C4A-Script",
      "web automation",
      "DSL",
      "Blockly",
      "UI testing",
      "crawling",
      "Crawl4AI"
    ],
    "prerequisites": [],
    "_content_hash": "d5a92ef5fde4ecfed1dd3be08243ba8b38c8587d20ac6c49ab792a8461b00b69",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/cache-modes/",
    "title": "Crawl4AI Cache System and Migration Guide",
    "type": "guide",
    "summary": "This page explains the new CacheMode enum introduced in Crawl4AI v0.5.0, which replaces old boolean cache flags, and provides migration examples and a mapping table for transitioning from legacy…",
    "sections": [
      {
        "heading": "Overview",
        "content": "Starting from version 0.5.0, Crawl4AI introduces a new caching system that replaces the old boolean flags with a more intuitive `CacheMode` enum. This change simplifies cache control and makes the…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Old vs New Approach",
        "content": "The old system used multiple boolean flags:\n- `bypass_cache`: Skip cache entirely\n- `disable_cache`: Disable all caching\n- `no_cache_read`: Don't read from cache\n- `no_cache_write`: Don't write to…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Migration Example",
        "content": "Old Code (Deprecated)\n\nNew Code (Recommended)",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler\n\nasync def old_code(crawler: AsyncWebCrawler):\n    # Legacy `bypass_cache` / `disable_cache` / `no_cache_read` / `no_cache_write`\n    # were removed in v0.5+.…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CacheMode\nfrom crawl4ai.async_configs import CrawlerRunConfig\n\nasync def use_proxy():\n    # Use CacheMode in CrawlerRunConfig\n    config =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Common Migration Patterns",
        "content": "| Legacy Flag | Replacement |\n| --- | --- |\n| `bypass_cache` | `cache_mode=CacheMode.BYPASS` |\n| `disable_cache` | `cache_mode=CacheMode.DISABLED` |\n| `no_cache_read` |…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "cache",
      "CacheMode",
      "migration",
      "async",
      "web crawling"
    ],
    "prerequisites": [],
    "_content_hash": "0f07f0b8f75bba367aa9dca5c564ffde49558e1480995b64a49670e277cbd775",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/cli/",
    "title": "Command Line Interface - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page provides a comprehensive guide to using the Crawl4AI CLI (`crwl`), covering installation, basic usage, configuration options (browser, crawler, extraction), advanced features like LLM Q&A…",
    "sections": [
      {
        "heading": "Installation",
        "content": "The Crawl4AI CLI will be installed automatically when you install the library.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "The Crawl4AI CLI (`crwl`) provides a simple interface to the Crawl4AI library:",
        "code_blocks": [
          {
            "language": "bash",
            "code": "# Basic crawling\ncrwl https://example.com\n\n# Get markdown output\ncrwl https://example.com -o markdown\n\n# Verbose JSON output with cache bypass\ncrwl https://example.com -o json -v --bypass-cache\n\n#…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Quick Example of Advanced Usage",
        "content": "If you clone the repository and run the following command, you will receive the content of the page in JSON format according to a JSON-CSS schema:",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crwl \"https://www.infoq.com/ai-ml-data-eng/\" -e docs/examples/cli/extract_css.yml -s docs/examples/cli/css_schema.json -o json;\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Browser Configuration",
        "content": "Browser settings can be configured via YAML file or command line parameters:",
        "code_blocks": [
          {
            "language": "yaml",
            "code": "# browser.yml\nheadless: true\nviewport_width: 1280\nuser_agent_mode: \"random\"\nverbose: true\nignore_https_errors: true\nCopy",
            "filename": "browser.yml"
          },
          {
            "language": "bash",
            "code": "# Using config file\ncrwl https://example.com -B browser.yml\n\n# Using direct parameters\ncrwl https://example.com -b \"headless=true,viewport_width=1280,user_agent_mode=random\"\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Crawler Configuration",
        "content": "Control crawling behavior:",
        "code_blocks": [
          {
            "language": "yaml",
            "code": "# crawler.yml\ncache_mode: \"bypass\"\nwait_until: \"networkidle\"\npage_timeout: 30000\ndelay_before_return_html: 0.5\nword_count_threshold: 100\nscan_full_page: true\nscroll_delay: 0.3\nprocess_iframes:…",
            "filename": "crawler.yml"
          },
          {
            "language": "bash",
            "code": "# Using config file\ncrwl https://example.com -C crawler.yml\n\n# Using direct parameters\ncrwl https://example.com -c \"css_selector=#main,delay_before_return_html=2,scan_full_page=true\"\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Extraction Configuration",
        "content": "Two types of extraction are supported:\n\n- CSS/XPath-based extraction:",
        "code_blocks": [
          {
            "language": "yaml",
            "code": "# extract_css.yml\ntype: \"json-css\"\nparams:\n  verbose: true\nCopy",
            "filename": "extract_css.yml"
          },
          {
            "language": "json",
            "code": "// css_schema.json\n{\n  \"name\": \"ArticleExtractor\",\n  \"baseSelector\": \".article\",\n  \"fields\": [\n    {\n      \"name\": \"title\",\n      \"selector\": \"h1.title\",\n      \"type\": \"text\"\n    },\n    {…",
            "filename": "css_schema.json"
          },
          {
            "language": "yaml",
            "code": "# extract_llm.yml\ntype: \"llm\"\nprovider: \"openai/gpt-4\"\ninstruction: \"Extract all articles with their titles and links\"\napi_token: \"your-token\"\nparams:\n  temperature: 0.3\n  max_tokens: 1000\nCopy",
            "filename": "extract_llm.yml"
          },
          {
            "language": "json",
            "code": "// llm_schema.json\n{\n  \"title\": \"Article\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"title\": {\n      \"type\": \"string\",\n      \"description\": \"The title of the article\"\n    },\n    \"link\": {…",
            "filename": "llm_schema.json"
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Features",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "LLM Q&A",
        "content": "Ask questions about crawled content:\n\nFirst-time setup:\n- Prompts for LLM provider and API token\n- Saves configuration in `~/.crawl4ai/global.yml`\n- Supports various providers (openai/gpt-4,…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "# Simple question\ncrwl https://example.com -q \"What is the main topic discussed?\"\n\n# View content then ask questions\ncrwl https://example.com -o markdown  # See content first\ncrwl https://example.com…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Structured Data Extraction",
        "content": "Extract structured data using CSS selectors:\n\nOr using LLM-based extraction:",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crwl https://example.com \\\n    -e extract_css.yml \\\n    -s css_schema.json \\\n    -o json\nCopy",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crwl https://example.com \\\n    -e extract_llm.yml \\\n    -s llm_schema.json \\\n    -o json\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Content Filtering",
        "content": "Filter content for relevance:",
        "code_blocks": [
          {
            "language": "yaml",
            "code": "# filter_bm25.yml\ntype: \"bm25\"\nquery: \"target content\"\nthreshold: 1.0\n\n# filter_pruning.yml\ntype: \"pruning\"\nquery: \"focus topic\"\nthreshold: 0.48\nCopy",
            "filename": "filter_bm25.yml"
          },
          {
            "language": "bash",
            "code": "crwl https://example.com -f filter_bm25.yml -o markdown-fit\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Output Formats",
        "content": "- `all` - Full crawl result including metadata\n- `json` - Extracted structured data (when using extraction)\n- `markdown` / `md` - Raw markdown output\n- `markdown-fit` / `md-fit` - Filtered markdown…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Complete Examples",
        "content": "- Basic Extraction:\n- Structured Data Extraction:\n- LLM Extraction with Filtering:\n- Interactive Q&A:",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crwl https://example.com \\\n    -B browser.yml \\\n    -C crawler.yml \\\n    -o json\nCopy",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crwl https://example.com \\\n    -e extract_css.yml \\\n    -s css_schema.json \\\n    -o json \\\n    -v\nCopy",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "crwl https://example.com \\\n    -B browser.yml \\\n    -e extract_llm.yml \\\n    -s llm_schema.json \\\n    -f filter_bm25.yml \\\n    -o json\nCopy",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "# First crawl and view\ncrwl https://example.com -o markdown\n\n# Then ask questions\ncrwl https://example.com -q \"What are the main points?\"\ncrwl https://example.com -q \"Summarize the conclusions\"\nCopy",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices & Tips",
        "content": "- **Configuration Management** :\n  - Keep common configurations in YAML files\n  - Use CLI parameters for quick overrides\n  - Store sensitive data (API tokens) in `~/.crawl4ai/global.yml`\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Recap",
        "content": "The Crawl4AI CLI provides:\n- Flexible configuration via files and parameters\n- Multiple extraction strategies (CSS, XPath, LLM)\n- Content filtering and optimization\n- Interactive Q&A capabilities\n-…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "CLI",
      "crwl",
      "web crawling",
      "configuration",
      "extraction",
      "LLM",
      "Q&A",
      "content filtering",
      "output formats"
    ],
    "prerequisites": [],
    "_content_hash": "fdd3d822790e5350b3a98e07b46af70911d3437c50d15cb88c94faeb662f53db",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/content-selection/",
    "title": "Content Selection",
    "type": "api",
    "summary": "This page explains how to select, filter, and refine content from crawls using CrawlerRunConfig parameters, including CSS selectors, content filtering, iframe handling, shadow DOM flattening, and…",
    "sections": [
      {
        "heading": "1. CSS-Based Selection",
        "content": "Crawl4AI provides multiple ways to select, filter, and refine the content from your crawls. Whether you need to target a specific CSS region, exclude entire tags, filter out external links, or remove…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1.1 Using css_selector",
        "content": "A straightforward way to limit your crawl results to a certain region of the page is css_selector in CrawlerRunConfig:\n\nResult: Only elements matching that selector remain in result.cleaned_html.",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    config = CrawlerRunConfig(\n        # e.g., first 30 items from Hacker News…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1.2 Using target_elements",
        "content": "The target_elements parameter provides more flexibility by allowing you to target multiple elements for content extraction while preserving the entire page context for other features:\n\nKey…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    config = CrawlerRunConfig(\n        # Target article body and sidebar, but not other content…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Content Filtering & Exclusions",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 Basic Overview",
        "content": "Explanation:\n\n- word_count_threshold: Ignores text blocks under X words. Helps skip trivial blocks like short nav or disclaimers.\n- excluded_tags: Removes entire tags (<form>, , <footer>,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    # Content thresholds\n    word_count_threshold=10,        # Minimum words per block\n\n    # Tag exclusions\n    excluded_tags=['form', 'header', 'footer', 'nav'],\n\n    #…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "[\n    'facebook.com',\n    'twitter.com',\n    'x.com',\n    'linkedin.com',\n    'instagram.com',\n    'pinterest.com',\n    'tiktok.com',\n    'snapchat.com',\n    'reddit.com',\n]",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.2 Example Usage",
        "content": "Note: If these parameters remove too much, reduce or disable them accordingly.",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    config = CrawlerRunConfig(\n        css_selector=\"main.content\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Handling Iframes",
        "content": "Some sites embed content in <iframe> tags. If you want that inline:\n\nUsage:",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    # Merge iframe content into the final output\n    process_iframes=True,\n    remove_overlay_elements=True,\n    # Remove GDPR/cookie consent popups (OneTrust, Cookiebot,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    config = CrawlerRunConfig(\n        process_iframes=True,\n        remove_overlay_elements=True\n    )…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.1 Flattening Shadow DOM",
        "content": "Sites built with Web Components (Stencil, Lit, Shoelace, Angular Elements, etc.) render content inside Shadow DOM — an encapsulated sub-tree that is invisible to normal page serialization. The…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    # Flatten shadow DOM into the main document\n    flatten_shadow_dom=True,\n    # Give web components time to hydrate\n    wait_until=\"load\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    config = CrawlerRunConfig(\n        flatten_shadow_dom=True,\n        wait_until=\"load\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Structured Extraction Examples",
        "content": "You can combine content selection with a more advanced extraction strategy. For instance, a CSS-based or LLM-based extraction strategy can run on the filtered HTML.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4.1 Pattern-Based with JsonCssExtractionStrategy",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    # Minimal schema for repeated items…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4.2 LLM-Based Extraction",
        "content": "Here, the crawler:\n\n- Filters out external links (exclude_external_links=True).\n- Ignores very short text blocks (word_count_threshold=20).\n- Passes the final HTML to your LLM strategy for an…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom pydantic import BaseModel, Field\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig\nfrom crawl4ai import LLMExtractionStrategy\n\nclass…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Comprehensive Example",
        "content": "Below is a short function that unifies CSS selection, exclusion logic, and a pattern-based extraction, demonstrating how you can fine-tune your final data:\n\nWhy This Works:\n- CSS scoping with…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def extract_main_articles(url: str):\n    schema = {…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Scraping Modes",
        "content": "Crawl4AI uses LXMLWebScrapingStrategy (LXML-based) as the default scraping strategy for HTML content processing. This strategy offers excellent performance, especially for large HTML…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LXMLWebScrapingStrategy\n\nasync def main():\n    # Default configuration already uses LXMLWebScrapingStrategy\n    config = CrawlerRunConfig()…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import ContentScrapingStrategy, ScrapingResult, MediaItem, Media, Link, Links\n\nclass CustomScrapingStrategy(ContentScrapingStrategy):\n    def scrap(self, url: str, html: str, **kwargs)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Combining CSS Selection Methods",
        "content": "You can combine css_selector and target_elements in powerful ways to achieve fine-grained control over your output:\n\nThis approach gives you the best of both worlds:\n- Markdown generation and content…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def main():\n    # Target specific content but preserve page context\n    config = CrawlerRunConfig(\n        #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Conclusion",
        "content": "By mixing target_elements or css_selector scoping, content filtering parameters, and advanced extraction strategies, you can precisely choose which data to keep. Key parameters in CrawlerRunConfig…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "css_selector",
        "type": "string",
        "description": "A CSS selector to limit crawl results to a certain region of the page. Only elements matching that selector remain in result.cleaned_html.",
        "default": "",
        "required": false
      },
      {
        "name": "target_elements",
        "type": "array of strings",
        "description": "Array of CSS selectors to focus markdown generation and data extraction on those elements, while preserving full page context for links and media.",
        "default": "",
        "required": false
      },
      {
        "name": "word_count_threshold",
        "type": "integer",
        "description": "Minimum words per block. Ignores text blocks under X words.",
        "default": "",
        "required": false
      },
      {
        "name": "excluded_tags",
        "type": "array of strings",
        "description": "List of HTML tags to remove from the content.",
        "default": "",
        "required": false
      },
      {
        "name": "exclude_external_links",
        "type": "boolean",
        "description": "If True, strips out external links and may remove them from result.links.",
        "default": "",
        "required": false
      },
      {
        "name": "exclude_social_media_links",
        "type": "boolean",
        "description": "If True, removes links pointing to known social media domains.",
        "default": "",
        "required": false
      },
      {
        "name": "exclude_domains",
        "type": "array of strings",
        "description": "A custom list of domains to block if discovered in links.",
        "default": "",
        "required": false
      },
      {
        "name": "exclude_social_media_domains",
        "type": "array of strings",
        "description": "A curated list of social media domains to exclude. Override or add to it.",
        "default": "",
        "required": false
      },
      {
        "name": "exclude_external_images",
        "type": "boolean",
        "description": "If True, discards images not hosted on the same domain as the main page (or its subdomains).",
        "default": "",
        "required": false
      },
      {
        "name": "process_iframes",
        "type": "boolean",
        "description": "If True, merges iframe content into the final output.",
        "default": "",
        "required": false
      },
      {
        "name": "remove_overlay_elements",
        "type": "boolean",
        "description": "If True, removes overlay elements.",
        "default": "",
        "required": false
      },
      {
        "name": "remove_consent_popups",
        "type": "boolean",
        "description": "If True, removes GDPR/cookie consent popups (OneTrust, Cookiebot, etc.).",
        "default": "",
        "required": false
      },
      {
        "name": "flatten_shadow_dom",
        "type": "boolean",
        "description": "If True, flattens shadow DOM into the main document.",
        "default": "",
        "required": false
      },
      {
        "name": "wait_until",
        "type": "string",
        "description": "Wait condition for page load (e.g., 'load').",
        "default": "",
        "required": false
      },
      {
        "name": "delay_before_return_html",
        "type": "float",
        "description": "Delay in seconds before returning HTML.",
        "default": "",
        "required": false
      },
      {
        "name": "cache_mode",
        "type": "CacheMode",
        "description": "Caching behavior (e.g., CacheMode.BYPASS).",
        "default": "",
        "required": false
      },
      {
        "name": "extraction_strategy",
        "type": "ExtractionStrategy",
        "description": "Strategy for structured extraction (e.g., JsonCssExtractionStrategy, LLMExtractionStrategy).",
        "default": "",
        "required": false
      },
      {
        "name": "scraping_strategy",
        "type": "ScrapingStrategy",
        "description": "Strategy for HTML processing (e.g., LXMLWebScrapingStrategy).",
        "default": "",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "content selection",
      "CSS selector",
      "filtering",
      "iframes",
      "shadow DOM",
      "extraction",
      "CrawlerRunConfig"
    ],
    "prerequisites": [],
    "_content_hash": "87bb60a4881985a437b92e6aa3ae7756f79d0fd8e15eab8b1fc05e883649bd3b",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/crawler-result/",
    "title": "Crawl Result and Output",
    "type": "api",
    "summary": "Describes the CrawlResult object returned by Crawl4AI's arun() method, including all fields, markdown generation, structured extraction, and additional outputs like links, media, tables, screenshots,…",
    "sections": [
      {
        "heading": "1. The `CrawlResult` Model",
        "content": "Below is the core schema. Each field captures a different aspect of the crawl’s result:\n\n```\nclass MarkdownGenerationResult(BaseModel):\n    raw_markdown: str\n    markdown_with_citations: str…",
        "code_blocks": [
          {
            "language": "python",
            "code": "class MarkdownGenerationResult(BaseModel):\n    raw_markdown: str\n    markdown_with_citations: str\n    references_markdown: str\n    fit_markdown: Optional[str] = None\n    fit_html: Optional[str] =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. HTML Variants",
        "content": "###### `html`: Raw HTML\n\nCrawl4AI preserves the exact HTML as `result.html`. Useful for:\n\n- Debugging page issues or checking the original content.\n- Performing your own specialized parse if…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    excluded_tags=[\"form\", \"header\", \"footer\"],\n    keep_data_attributes=False\n)\nresult = await crawler.arun(\"https://example.com\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Markdown Generation",
        "content": "###### 3.1 `markdown`\n\n- **`markdown`**: The current location for detailed markdown output, returning a **`MarkdownGenerationResult`** object.\n- **`markdown_v2`**: Removed in v0.5. Accessing it now…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\n\nconfig = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Structured Extraction: `extracted_content`",
        "content": "If you run a JSON-based extraction strategy (CSS, XPath, LLM, etc.), the structured data is **not** stored in `markdown`—it’s placed in **`result.extracted_content`** as a JSON string (or sometimes…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    schema = {\n        \"name\": \"Example…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. More Fields: Links, Media, Tables and More",
        "content": "###### 5.1 `links`\n\nA dictionary, typically with `\"internal\"` and `\"external\"` lists. Each entry might have `href`, `text`, `title`, etc. This is automatically captured if you haven’t disabled link…",
        "code_blocks": [
          {
            "language": "python",
            "code": "print(result.links[\"internal\"][:3])  # Show first 3 internal links",
            "filename": ""
          },
          {
            "language": "python",
            "code": "images = result.media.get(\"images\", [])\nfor img in images:\n    print(\"Image URL:\", img[\"src\"], \"Alt:\", img.get(\"alt\"))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    table_score_threshold=5  # Lower value = more tables detected (default: 7)\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Save the PDF\nwith open(\"page.pdf\", \"wb\") as f:\n    f.write(result.pdf)\n\n# Save the MHTML\nif result.mhtml:\n    with open(\"page.mhtml\", \"w\", encoding=\"utf-8\") as f:\n        f.write(result.mhtml)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Accessing These Fields",
        "content": "After you run:\n\n```\nresult = await crawler.arun(url=\"https://example.com\", config=some_config)\n```\n\nCheck any field:\n\n```\nif result.success:\n    print(result.status_code, result.response_headers)…",
        "code_blocks": [
          {
            "language": "python",
            "code": "result = await crawler.arun(url=\"https://example.com\", config=some_config)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "if result.success:\n    print(result.status_code, result.response_headers)\n    print(\"Links found:\", len(result.links.get(\"internal\", [])))\n    if result.markdown:\n        print(\"Markdown snippet:\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Next Steps",
        "content": "- **Markdown Generation**: Dive deeper into how to configure `DefaultMarkdownGenerator` and various filters.\n- **Content Filtering**: Learn how to use `BM25ContentFilter` and…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "url",
        "type": "str",
        "description": "The final or actual URL crawled (in case of redirects).",
        "default": "",
        "required": true
      },
      {
        "name": "html",
        "type": "str",
        "description": "Original, unmodified page HTML. Good for debugging or custom processing.",
        "default": "",
        "required": true
      },
      {
        "name": "fit_html",
        "type": "Optional[str]",
        "description": "Preprocessed HTML optimized for extraction and content filtering.",
        "default": "",
        "required": false
      },
      {
        "name": "success",
        "type": "bool",
        "description": "True if the crawl completed without major errors, else False.",
        "default": "",
        "required": true
      },
      {
        "name": "cleaned_html",
        "type": "Optional[str]",
        "description": "Sanitized HTML with scripts/styles removed; can exclude tags if configured via excluded_tags etc.",
        "default": "",
        "required": false
      },
      {
        "name": "media",
        "type": "Dict[str, List[Dict]]",
        "description": "Extracted media info (images, audio, etc.), each with attributes like src, alt, score, etc.",
        "default": "{}",
        "required": false
      },
      {
        "name": "links",
        "type": "Dict[str, List[Dict]]",
        "description": "Extracted link data, split by internal and external. Each link usually has href, text, etc.",
        "default": "{}",
        "required": false
      },
      {
        "name": "downloaded_files",
        "type": "Optional[List[str]]",
        "description": "If accept_downloads=True in BrowserConfig, this lists the filepaths of saved downloads.",
        "default": "",
        "required": false
      },
      {
        "name": "js_execution_result",
        "type": "Optional[Dict[str, Any]]",
        "description": "Results from JavaScript execution during crawling.",
        "default": "",
        "required": false
      },
      {
        "name": "screenshot",
        "type": "Optional[str]",
        "description": "Screenshot of the page (base64-encoded) if screenshot=True.",
        "default": "",
        "required": false
      },
      {
        "name": "pdf",
        "type": "Optional[bytes]",
        "description": "PDF of the page if pdf=True.",
        "default": "",
        "required": false
      },
      {
        "name": "mhtml",
        "type": "Optional[str]",
        "description": "MHTML snapshot of the page if capture_mhtml=True. Contains the full page with all resources.",
        "default": "",
        "required": false
      },
      {
        "name": "markdown",
        "type": "Optional[Union[str, MarkdownGenerationResult]]",
        "description": "It holds a MarkdownGenerationResult. Over time, this will be consolidated into markdown. The generator can provide raw markdown, citations, references, and optionally fit_markdown.",
        "default": "",
        "required": false
      },
      {
        "name": "extracted_content",
        "type": "Optional[str]",
        "description": "The output of a structured extraction (CSS/LLM-based) stored as JSON string or other text.",
        "default": "",
        "required": false
      },
      {
        "name": "metadata",
        "type": "Optional[dict]",
        "description": "Additional info about the crawl or extracted data.",
        "default": "",
        "required": false
      },
      {
        "name": "error_message",
        "type": "Optional[str]",
        "description": "If success=False, contains a short description of what went wrong.",
        "default": "",
        "required": false
      },
      {
        "name": "session_id",
        "type": "Optional[str]",
        "description": "The ID of the session used for multi-page or persistent crawling.",
        "default": "",
        "required": false
      },
      {
        "name": "response_headers",
        "type": "Optional[dict]",
        "description": "HTTP response headers, if captured.",
        "default": "",
        "required": false
      },
      {
        "name": "status_code",
        "type": "Optional[int]",
        "description": "HTTP status code (e.g., 200 for OK).",
        "default": "",
        "required": false
      },
      {
        "name": "ssl_certificate",
        "type": "Optional[SSLCertificate]",
        "description": "SSL certificate info if fetch_ssl_certificate=True.",
        "default": "",
        "required": false
      },
      {
        "name": "dispatch_result",
        "type": "Optional[DispatchResult]",
        "description": "Additional concurrency and resource usage information when crawling URLs in parallel.",
        "default": "",
        "required": false
      },
      {
        "name": "redirected_url",
        "type": "Optional[str]",
        "description": "The URL after any redirects (different from url which is the final URL).",
        "default": "",
        "required": false
      },
      {
        "name": "redirected_status_code",
        "type": "Optional[int]",
        "description": "HTTP status code of the final redirect destination (e.g., 200). None for non-HTTP requests (raw HTML, local files).",
        "default": "",
        "required": false
      },
      {
        "name": "network_requests",
        "type": "Optional[List[Dict[str, Any]]]",
        "description": "List of network requests, responses, and failures captured during the crawl if capture_network_requests=True.",
        "default": "",
        "required": false
      },
      {
        "name": "console_messages",
        "type": "Optional[List[Dict[str, Any]]]",
        "description": "List of browser console messages captured during the crawl if capture_console_messages=True.",
        "default": "",
        "required": false
      },
      {
        "name": "tables",
        "type": "List[Dict]",
        "description": "Table data extracted from HTML tables with structure [{headers, rows, caption, summary}].",
        "default": "[]",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "CrawlResult",
      "Crawl4AI",
      "web crawling",
      "markdown",
      "HTML",
      "extraction",
      "screenshot",
      "PDF",
      "MHTML",
      "links",
      "media",
      "tables"
    ],
    "prerequisites": [],
    "_content_hash": "063e3f4281c08f314e6bf9bf48594c354f7f99f9dc0fb73ee54b291188518438",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/deep-crawling/",
    "title": "Deep Crawling - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This tutorial explains how to perform configurable deep crawling with Crawl4AI, covering BFS, DFS, and BestFirst strategies, streaming vs non-streaming results, filters, scorers, crash recovery,…",
    "sections": [
      {
        "heading": "Introduction",
        "content": "One of Crawl4AI's most powerful features is its ability to perform **configurable deep crawling** that can explore websites beyond a single page. With fine-tuned control over crawl depth, domain…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Quick Example",
        "content": "Here's a minimal code snippet that implements a basic deep crawl using the **BFSDeepCrawlStrategy**:\n\n**What's happening?** \n- `BFSDeepCrawlStrategy(max_depth=2, include_external=False)` instructs…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.deep_crawling import BFSDeepCrawlStrategy\nfrom crawl4ai.content_scraping_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Understanding Deep Crawling Strategy Options",
        "content": "###### 2.1 BFSDeepCrawlStrategy (Breadth-First Search)\n\nThe **BFSDeepCrawlStrategy** uses a breadth-first approach, exploring all links at one depth before moving deeper:\n\n**Key parameters:** \n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\n# Basic configuration\nstrategy = BFSDeepCrawlStrategy(\n    max_depth=2,               # Crawl initial page + 2 levels deep…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling import DFSDeepCrawlStrategy\n\n# Basic configuration\nstrategy = DFSDeepCrawlStrategy(\n    max_depth=2,               # Crawl initial page + 2 levels deep…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling import BestFirstCrawlingStrategy\nfrom crawl4ai.deep_crawling.scorers import KeywordRelevanceScorer\n\n# Create a scorer\nscorer = KeywordRelevanceScorer(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Streaming vs. Non-Streaming Results",
        "content": "Crawl4AI can return results in two modes:\n\n###### 3.1 Non-Streaming Mode (Default)\n\n**When to use non-streaming mode:** \n- You need the complete dataset before processing\n- You're performing batch…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=1),\n    stream=False  # Default behavior\n)\n\nasync with AsyncWebCrawler() as crawler:\n    # Wait for ALL results to be…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=1),\n    stream=True  # Enable streaming\n)\n\nasync with AsyncWebCrawler() as crawler:\n    # Returns an async iterator…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Filtering Content with Filter Chains",
        "content": "Filters help you narrow down which pages to crawl. Combine multiple filters using **FilterChain** for powerful targeting.\n\n###### 4.1 Basic URL Pattern Filter\n\n###### 4.2 Combining Multiple Filters\n\n###…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling.filters import FilterChain, URLPatternFilter\n\n# Only follow URLs containing \"blog\" or \"docs\"\nurl_filter = URLPatternFilter(patterns=[\"*blog*\", \"*docs*\"])\n\nconfig =…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling.filters import (\n    FilterChain,\n    URLPatternFilter,\n    DomainFilter,\n    ContentTypeFilter\n)\n\n# Create a chain of filters\nfilter_chain = FilterChain([\n    # Only…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Using Scorers for Prioritized Crawling",
        "content": "Scorers assign priority values to discovered URLs, helping the crawler focus on the most relevant content first.\n\n###### 5.1 KeywordRelevanceScorer\n\n**How scorers work:** \n- Evaluate each discovered URL…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling.scorers import KeywordRelevanceScorer\nfrom crawl4ai.deep_crawling import BestFirstCrawlingStrategy\n\n# Create a keyword relevance scorer\nkeyword_scorer =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Advanced Filtering Techniques",
        "content": "###### 6.1 SEO Filter for Quality Assessment\n\nThe **SEOFilter** helps you identify pages with strong SEO characteristics:\n\n###### 6.2 Content Relevance Filter\n\nThe **ContentRelevanceFilter** analyzes the…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling.filters import FilterChain, SEOFilter\n\n# Create an SEO filter that looks for specific keywords in page metadata\nseo_filter = SEOFilter(\n    threshold=0.5,  # Minimum score…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling.filters import FilterChain, ContentRelevanceFilter\n\n# Create a content relevance filter\nrelevance_filter = ContentRelevanceFilter(\n    query=\"Web crawling and data…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Building a Complete Advanced Crawler",
        "content": "This example combines multiple techniques for a sophisticated crawl:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.content_scraping_strategy import LXMLWebScrapingStrategy\nfrom crawl4ai.deep_crawling import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Limiting and Controlling Crawl Size",
        "content": "###### 8.1 Using max_pages\n\nYou can limit the total number of pages crawled with the `max_pages` parameter:\n\nThis feature is useful for:\n- Controlling API costs\n- Setting predictable execution times\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Limit to exactly 20 pages regardless of depth\nstrategy = BFSDeepCrawlStrategy(\n    max_depth=3,\n    max_pages=20\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Only follow links with scores above 0.4\nstrategy = DFSDeepCrawlStrategy(\n    max_depth=2,\n    url_scorer=KeywordRelevanceScorer(keywords=[\"api\", \"guide\", \"reference\"]),\n    score_threshold=0.4  #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "9. Common Pitfalls & Tips",
        "content": "1. **Set realistic limits.** Be cautious with `max_depth` values > 3, which can exponentially increase crawl size. Use `max_pages` to set hard limits.\n\n2. **Don't neglect the scoring component.**…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=2),\n    preserve_https_for_internal_links=True  # Keep HTTPS even if server redirects to HTTP\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "10. Crash Recovery for Long-Running Crawls",
        "content": "For production deployments, especially in cloud environments where instances can be terminated unexpectedly, Crawl4AI provides built-in crash recovery support for all deep crawl strategies.\n\n###### 10.1…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling import BFSDeepCrawlStrategy\nimport json\n\n# Callback to save state after each URL\nasync def save_state_to_redis(state: dict):\n    await redis.set(\"crawl_state\",…",
            "filename": ""
          },
          {
            "language": "json",
            "code": "{\n    \"strategy_type\": \"bfs\",  # or \"dfs\", \"best_first\"\n    \"visited\": [\"url1\", \"url2\", ...],  # Already crawled URLs\n    \"pending\": [{\"url\": \"...\", \"parent_url\": \"...\"}],  # Queue/stack…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\n# Load saved state (e.g., from Redis, database, or file)\nsaved_state =…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\n\ncaptured_state = None\n\nasync def capture_state(state: dict):\n    global captured_state\n    captured_state = state\n\nstrategy = BFSDeepCrawlStrategy(\n    max_depth=2,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nimport json\nimport redis.asyncio as redis\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\nREDIS_KEY =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "11. Cancellation Support for Deep Crawls",
        "content": "For production environments like cloud platforms, you often need to stop a running crawl mid-execution—whether the user changed their mind, specified the wrong URL, or wants to control costs.…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\nasync def check_if_cancelled():\n    # Check Redis, database, or any external source\n    job = await redis.get(f\"job:{job_id}\")\n    return…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "strategy = BFSDeepCrawlStrategy(max_depth=3, max_pages=1000)\n\n# In another coroutine or thread:\nstrategy.cancel()  # Thread-safe, stops before next URL",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async with AsyncWebCrawler() as crawler:\n    results = await crawler.arun(url, config=config)\n\nif strategy.cancelled:\n    print(f\"Crawl was cancelled after {len(results)} pages\")\nelse:…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def handle_state(state: dict):\n    if state.get(\"cancelled\"):\n        print(\"Crawl was cancelled!\")\n        print(f\"Crawled {state['pages_crawled']} pages before cancellation\")\n    # Save state…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nimport json\nimport redis.asyncio as redis\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\nasync def…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "12. Prefetch Mode for Fast URL Discovery",
        "content": "When you need to quickly discover URLs without full page processing, use **prefetch mode** . This is ideal for two-phase crawling where you first map the site, then selectively process specific…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nconfig = CrawlerRunConfig(prefetch=True)\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\"https://example.com\",…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def two_phase_crawl(start_url: str):\n    async with AsyncWebCrawler() as crawler:\n        #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "13. Summary & Next Steps",
        "content": "In this **Deep Crawling with Crawl4AI** tutorial, you learned to:\n\n- Configure **BFSDeepCrawlStrategy** , **DFSDeepCrawlStrategy** , and **BestFirstCrawlingStrategy**\n- Process results in streaming…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "deep-crawling",
      "BFS",
      "DFS",
      "BestFirst",
      "filters",
      "scorers",
      "crash-recovery",
      "cancellation",
      "prefetch",
      "Crawl4AI"
    ],
    "prerequisites": [],
    "_content_hash": "50643d9a5b6878246f6b51df53789536119960a5b00753956507d86cfcdad2af",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/domain-mapping/",
    "title": "Domain Mapping: Discover Every URL Under a Domain",
    "type": "reference",
    "summary": "This page describes DomainMapper in Crawl4AI, which discovers every URL under a domain using 8 discovery sources, including sitemaps, Common Crawl, Wayback Machine, Certificate Transparency, path…",
    "sections": [
      {
        "heading": "What Is Domain Mapping?",
        "content": "Domain mapping goes beyond URL seeding. Instead of checking a single sitemap or index, `DomainMapper` combines **8 discovery sources** to find every URL under a domain — including subdomains you…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "DomainMapper vs AsyncUrlSeeder",
        "content": "| Aspect | AsyncUrlSeeder | DomainMapper |\n| --- | --- | --- |\n| **Scope** | Single host, listed URLs only | Entire domain + all subdomains |\n| **Sources** | Sitemap + Common Crawl | 8 sources…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "Or via `AsyncWebCrawler`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import DomainMapper, DomainMapperConfig\n\nasync def main():\n    async with DomainMapper() as mapper:\n        results = await mapper.scan(\"example.com\")\n\n    print(f\"Found…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, DomainMapperConfig\n\nasync with AsyncWebCrawler() as crawler:\n    results = await crawler.amap_domain(\"example.com\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "The 8 Discovery Sources",
        "content": "DomainMapper combines these sources, each catching URLs the others miss:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. `sitemap` — Sitemap Discovery",
        "content": "Checks `/sitemap.xml`, `/sitemap_index.xml`, and `robots.txt` `Sitemap:` directives **on every discovered host** — not just the root domain.",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"sitemap\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. `cc` — Common Crawl",
        "content": "Queries the Common Crawl CDX API for `*.domain.tld/*`, catching URLs and subdomains the web's largest public crawl has indexed.",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"cc\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. `wayback` — Wayback Machine",
        "content": "Queries the Internet Archive's CDX API. Often has different coverage than Common Crawl — including historical pages that have since been removed.",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"wayback\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. `crt` — Certificate Transparency",
        "content": "Queries [crt.sh](https://crt.sh) for SSL certificates issued to `*.domain.tld`. This is the single most effective subdomain discovery technique — it found 14 subdomains for `superdesign.dev` that no…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"crt\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. `probe` — Common Path Probing",
        "content": "Tries ~25 well-known paths on each discovered host (`/docs`, `/api`, `/login`, `/dashboard`, `/openapi.json`, etc.). Combined with soft-404 detection to avoid false positives.",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"probe\")\n\n# Add custom paths to probe\nconfig = DomainMapperConfig(\n    source=\"probe\",\n    probe_paths=[\"/custom-api\", \"/internal/status\"]\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. `robots` — robots.txt Path Mining",
        "content": "Parses `Disallow:` and `Allow:` lines from `robots.txt`. These are confirmed real paths the site acknowledges exist — often revealing admin panels, APIs, and internal tools that aren't linked…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"robots\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. `feed` — RSS/Atom Feed Parsing",
        "content": "Discovers and parses RSS/Atom feeds at common paths (`/feed`, `/rss`, `/atom.xml`, etc.). Feeds are curated lists of content URLs maintained by the site.",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"feed\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. `homepage` — Homepage Link Extraction",
        "content": "Fetches each host's homepage via HTTP and extracts all internal links using `quick_extract_links()`. Also mines `<link rel=\"alternate|preload|prefetch\">` tags from the `` for additional URLs.…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = DomainMapperConfig(source=\"homepage\")",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining Sources",
        "content": "Sources are combined with `+`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Default: most useful combination\nconfig = DomainMapperConfig(source=\"sitemap+cc+crt+probe\")\n\n# Maximum coverage: all 8 sources\nconfig = DomainMapperConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "How It Works: The Three Phases",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Phase 1: Host Discovery",
        "content": "DomainMapper first discovers all subdomains under your domain:\n\nEach discovered host is validated with an HTTP HEAD request. Hosts that don't respond are dropped.",
        "code_blocks": [
          {
            "language": "text",
            "code": "superdesign.dev\n├── crt.sh           → docs, app, cloud, insights, staging-api, ui2web, ...\n├── Wayback CDX      → api, app, docs, www, ...\n├── Common Crawl     → app, www, ...\n└── DNS guessing     →…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Phase 2: Per-Host Scanning",
        "content": "For each validated host, DomainMapper runs all enabled sources in parallel:",
        "code_blocks": [
          {
            "language": "text",
            "code": "docs.superdesign.dev\n├── Soft-404 fingerprint  → (404 returns proper error — no SPA issue)\n├── robots.txt            → 1 sitemap URL, 1 disallow path\n├── Sitemap parsing       → 19 URLs\n├── Path…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Phase 3: Post-Processing",
        "content": "All discovered URLs go through:\n\n- **URL normalization** — using `normalize_url()` to canonicalize\n- **Deduplication** — by normalized URL, merging source attribution\n- **Nonsense filtering** —…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Soft-404 Detection",
        "content": "Many modern SPAs return HTTP 200 for every URL — even pages that don't exist. DomainMapper detects this:\n\n- **Fingerprinting**: Fetches a guaranteed-nonexistent URL (e.g., `/c4ai-probe-a1b2c3d4`) on…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Soft-404 detection is on by default\nconfig = DomainMapperConfig(soft_404_detection=True)\n\n# Disable if you want raw results\nconfig = DomainMapperConfig(soft_404_detection=False)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Reference",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "DomainMapperConfig",
        "content": "| Parameter | Type | Default | Description |\n| --- | --- | --- | --- |\n| `source` | str | `\"sitemap+cc+crt+probe\"` | Discovery sources joined by `+` |\n| `max_urls` | int | `-1` | Maximum URLs to…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Output Format",
        "content": "Each result is a dict:",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n    \"url\": \"https://docs.superdesign.dev/quickstart\",\n    \"host\": \"docs.superdesign.dev\",\n    \"source\": \"homepage+sitemap\",     # which source(s) found it\n    \"status\": \"valid\",                #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Practical Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Discover and Crawl Documentation",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, DomainMapperConfig, CrawlerRunConfig\n\nasync def crawl_all_docs():\n    async with AsyncWebCrawler() as crawler:\n        # Step 1: Discover all…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Security Audit: Find Exposed Services",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def audit_domain():\n    async with DomainMapper() as mapper:\n        results = await mapper.scan(\"company.com\", DomainMapperConfig(\n            source=\"crt+probe+robots\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Compare Subdomains Across a Domain",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def map_infrastructure():\n    async with DomainMapper() as mapper:\n        results = await mapper.scan(\"company.com\", DomainMapperConfig(\n            source=\"crt+probe\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Tips and Best Practices",
        "content": "- **Start with the default sources** (`sitemap+cc+crt+probe`). Add `wayback`, `robots`, `feed`, and `homepage` if you need maximum coverage.\n- **Use `extract_head=False` for speed** when you just…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [URL Seeding](../url-seeding/) — simpler, single-host URL discovery from sitemaps and Common Crawl\n- [Deep Crawling](../deep-crawling/) — follow links dynamically within pages\n- [Multi-URL…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "source",
        "type": "str",
        "description": "Discovery sources joined by `+`",
        "default": "sitemap+cc+crt+probe",
        "required": false
      },
      {
        "name": "max_urls",
        "type": "int",
        "description": "Maximum URLs to return (-1 = unlimited)",
        "default": "-1",
        "required": false
      },
      {
        "name": "concurrency",
        "type": "int",
        "description": "Max concurrent requests across all hosts",
        "default": "50",
        "required": false
      },
      {
        "name": "hits_per_sec",
        "type": "int",
        "description": "Rate limit in requests/second",
        "default": "10",
        "required": false
      },
      {
        "name": "force",
        "type": "bool",
        "description": "Bypass all caches",
        "default": "False",
        "required": false
      },
      {
        "name": "extract_head",
        "type": "bool",
        "description": "Fetch and parse `<head>` metadata",
        "default": "True",
        "required": false
      },
      {
        "name": "filter_nonsense_urls",
        "type": "bool",
        "description": "Filter static assets and utility URLs",
        "default": "True",
        "required": false
      },
      {
        "name": "soft_404_detection",
        "type": "bool",
        "description": "Fingerprint and filter soft-404 pages",
        "default": "True",
        "required": false
      },
      {
        "name": "query",
        "type": "str",
        "description": "BM25 relevance query (requires `extract_head=True`)",
        "default": "None",
        "required": false
      },
      {
        "name": "score_threshold",
        "type": "float",
        "description": "Minimum relevance score (0.0-1.0)",
        "default": "None",
        "required": false
      },
      {
        "name": "scoring_method",
        "type": "str",
        "description": "Scoring algorithm",
        "default": "bm25",
        "required": false
      },
      {
        "name": "probe_paths",
        "type": "List[str]",
        "description": "Extra paths to probe on each host",
        "default": "None",
        "required": false
      },
      {
        "name": "common_subdomains",
        "type": "List[str]",
        "description": "Extra subdomain prefixes to guess",
        "default": "None",
        "required": false
      },
      {
        "name": "use_browser_for_homepage",
        "type": "bool",
        "description": "Use Playwright for JS-rendered homepages",
        "default": "False",
        "required": false
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Override logger verbose setting",
        "default": "None",
        "required": false
      },
      {
        "name": "cache_ttl_hours",
        "type": "int",
        "description": "Hours before cached results expire",
        "default": "24",
        "required": false
      },
      {
        "name": "dns_timeout",
        "type": "float",
        "description": "Timeout for DNS resolution (seconds)",
        "default": "3.0",
        "required": false
      },
      {
        "name": "http_timeout",
        "type": "float",
        "description": "Timeout for HTTP requests (seconds)",
        "default": "10.0",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "DomainMapper",
      "Crawl4AI",
      "URL discovery",
      "subdomain discovery",
      "sitemap",
      "Common Crawl",
      "Wayback Machine",
      "Certificate Transparency",
      "crt.sh",
      "robots.txt",
      "RSS",
      "Atom",
      "soft-404 detection",
      "BM25",
      "web crawling",
      "Playwright"
    ],
    "prerequisites": [],
    "_content_hash": "7102ad96de4c61548fae9a581a5c5567cbd46785c82556c04a450db14b7edd74",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/examples/",
    "title": "Code Examples",
    "type": "overview",
    "summary": "This page provides a comprehensive list of example scripts that demonstrate various features and capabilities of Crawl4AI, organized by category with links to code and guides.",
    "sections": [
      {
        "heading": "Overview",
        "content": "This page provides a comprehensive list of example scripts that demonstrate various features and capabilities of Crawl4AI. Each example is designed to showcase specific functionality, making it…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Getting Started Examples",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Hello World | A simple introductory example demonstrating basic usage of AsyncWebCrawler with JavaScript execution and content filtering. |…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Proxies",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| **NSTProxy** | [NSTProxy](https://www.nstproxy.com/?utm_source=crawl4ai) Seamlessly integrates with crawl4ai — no setup required. Access…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Browser & Crawling Features",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Built-in Browser | Demonstrates how to use the built-in browser capabilities. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Advanced Crawling & Deep Crawling",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Deep Crawling | An extensive tutorial on deep crawling capabilities, demonstrating BFS and BestFirst strategies, stream vs. non-stream…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Extraction Strategies",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Extraction Strategies | Demonstrates different extraction strategies with various input formats (markdown, HTML, fit_markdown) and JSON-based…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "E-commerce & Specialized Crawling",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Amazon Product Extraction | Demonstrates how to extract structured product data from Amazon search results using CSS selectors. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Anti-Bot & Stealth Features",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Stealth Mode Quick Start | Five practical examples showing how to use stealth mode for bypassing basic bot detection. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Customization & Security",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Hooks | Illustrates how to use hooks at different stages of the crawling process for advanced customization. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Docker & Deployment",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Docker Config | Demonstrates how to create and use Docker configuration objects. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Application Examples",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Research Assistant | Demonstrates how to build a research assistant using Crawl4AI. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Content Generation & Markdown",
        "content": "| Example | Description | Link |\n| --- | --- | --- |\n| Content Source | Demonstrates how to work with different content sources in markdown generation. | [View…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Running the Examples",
        "content": "To run any of these examples, you'll need to have Crawl4AI installed:\n\nThen, you can run an example script like this:\n\nFor examples that require additional dependencies or environment variables,…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "pip install crawl4ai",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "python -m docs.examples.hello_world",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Contributing New Examples",
        "content": "If you've created an interesting example that demonstrates a unique use case or feature of Crawl4AI, we encourage you to contribute it to our examples collection. Please see our [contribution…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "examples",
      "web scraping",
      "crawling",
      "python",
      "asyncio",
      "docker",
      "stealth mode",
      "extraction"
    ],
    "prerequisites": [],
    "_content_hash": "a2397bbef492fa03cdb67287d4d86d37c5508d9221b900ec22564c126d2953d5",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/fit-markdown/",
    "title": "Fit Markdown with Pruning & BM25",
    "type": "guide",
    "summary": "Explains how to use Fit Markdown with Pruning and BM25 content filters in Crawl4AI to extract concise, relevant content from web pages.",
    "sections": [
      {
        "heading": "Overview",
        "content": "**Fit Markdown** is a specialized **filtered** version of your page’s markdown, focusing on the most relevant content. By default, Crawl4AI converts the entire HTML into a broad **raw_markdown**.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. How “Fit Markdown” Works",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1.1 The `content_filter`",
        "content": "In **`CrawlerRunConfig`**, you can specify a **`content_filter`** to shape how content is pruned or ranked before final markdown generation. A filter’s logic is applied **before** or **during** the…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1.2 Common Filters",
        "content": "1. **PruningContentFilter** – Scores each node by text density, link density, and tag importance, discarding those below a threshold.\n2. **BM25ContentFilter** – Focuses on textual relevance using…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. PruningContentFilter",
        "content": "**Pruning** discards less relevant nodes based on **text density, link density, and tag importance**. It’s a heuristic-based approach—if certain sections appear too “thin” or too “spammy,” they’re…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 Usage Example",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.content_filter_strategy import PruningContentFilter\nfrom crawl4ai.markdown_generation_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.2 Key Parameters",
        "content": "- **`min_word_threshold`** (int): If a block has fewer words than this, it’s pruned.\n- **`threshold_type`** (str):\n  - `\"fixed\"` → each node must exceed `threshold` (0–1).\n  - `\"dynamic\"` → node…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3. BM25ContentFilter",
        "content": "**BM25** is a classical text ranking algorithm often used in search engines. If you have a **user query** or rely on page metadata to derive a query, BM25 can identify which text chunks best match…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.1 Usage Example",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.content_filter_strategy import BM25ContentFilter\nfrom crawl4ai.markdown_generation_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3.2 Parameters",
        "content": "- **`user_query`** (str, optional): E.g. `\"machine learning\"`. If blank, the filter tries to glean a query from page metadata.\n- **`bm25_threshold`** (float, default 1.0):\n  - Higher → fewer chunks…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4. Accessing the “Fit” Output",
        "content": "After the crawl, your “fit” content is found in **`result.markdown.fit_markdown`**.\n\nIf the content filter is **BM25**, you might see additional logic or references in `fit_markdown` that highlight…",
        "code_blocks": [
          {
            "language": "python",
            "code": "fit_md = result.markdown.fit_markdown\nfit_html = result.markdown.fit_html",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Code Patterns Recap",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "5.1 Pruning",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "prune_filter = PruningContentFilter(\n    threshold=0.5,\n    threshold_type=\"fixed\",\n    min_word_threshold=10\n)\nmd_generator = DefaultMarkdownGenerator(content_filter=prune_filter)\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5.2 BM25",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "bm25_filter = BM25ContentFilter(\n    user_query=\"health benefits fruit\",\n    bm25_threshold=1.2\n)\nmd_generator = DefaultMarkdownGenerator(content_filter=bm25_filter)\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Combining with “word_count_threshold” & Exclusions",
        "content": "Remember you can also specify:\n\nThus, **multi-level** filtering occurs:\n\n- The crawler’s `excluded_tags` are removed from the HTML first.\n- The content filter (Pruning, BM25, or custom) prunes or…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    word_count_threshold=10,\n    excluded_tags=[\"nav\", \"footer\", \"header\"],\n    exclude_external_links=True,\n    markdown_generator=DefaultMarkdownGenerator(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Custom Filters",
        "content": "If you need a different approach (like a specialized ML model or site-specific heuristics), you can create a new class inheriting from `RelevantContentFilter` and implement `filter_content(html)`.…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.content_filter_strategy import RelevantContentFilter\n\nclass MyCustomFilter(RelevantContentFilter):\n    def filter_content(self, html, min_word_threshold=None):\n        # parse HTML,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Final Thoughts",
        "content": "**Fit Markdown** is a crucial feature for:\n\n- **Summaries**: Quickly get the important text from a cluttered page.\n- **Search**: Combine with **BM25** to produce content relevant to a query.\n- **AI…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Fit Markdown",
      "PruningContentFilter",
      "BM25ContentFilter",
      "Content Filtering",
      "Markdown Generation",
      "Web Scraping",
      "AsyncWebCrawler"
    ],
    "prerequisites": [],
    "_content_hash": "a6f76ddc88c73a2a4fc0e99e521d0a957b9aaf19776d2feea79986b71364305f",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/installation/",
    "title": "Installation & Setup (2023 Edition)",
    "type": "guide",
    "summary": "Installation and setup guide for Crawl4AI, covering basic install, diagnostics, verification, optional advanced dependencies, Docker, and local server mode.",
    "sections": [
      {
        "heading": "1. Basic Installation",
        "content": "This installs the  **core**  Crawl4AI library along with essential dependencies.  **No**  advanced features (like transformers or PyTorch) are included yet.",
        "code_blocks": [
          {
            "language": "bash",
            "code": "pip install crawl4ai",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Initial Setup & Diagnostics",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 Run the Setup Command",
        "content": "After installing, call:\n\n **What does it do?** \n- Installs or updates required browser dependencies for both regular and undetected modes\n- Performs OS-level checks (e.g., missing libs on Linux)\n-…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crawl4ai-setup",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2.2 Diagnostics",
        "content": "Optionally, you can run  **diagnostics**  to confirm everything is functioning:\n\nThis command attempts to:\n- Check Python version compatibility\n- Verify Playwright installation\n- Inspect environment…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crawl4ai-doctor",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Verifying Installation: A Simple Crawl (Skip this step if you already run `crawl4ai-doctor`)",
        "content": "Below is a minimal Python script demonstrating a  **basic**  crawl. It uses our new  **`BrowserConfig`**  and  **`CrawlerRunConfig`**  for clarity, though no custom settings are passed in this…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Advanced Installation (Optional)",
        "content": "**Warning** : Only install these  **if you truly need them** . They bring in larger dependencies, including big models, which can increase disk usage and memory load significantly.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4.1 Torch, Transformers, or All",
        "content": "- **Text Clustering (Torch)** \n\n  Installs PyTorch-based features (e.g., cosine similarity or advanced semantic chunking).\n\n- **Transformers** \n\n  Adds Hugging Face-based summarization or generation…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "pip install crawl4ai[torch]\ncrawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "pip install crawl4ai[transformer]\ncrawl4ai-setup",
            "filename": ""
          },
          {
            "language": "bash",
            "code": "pip install crawl4ai[all]\ncrawl4ai-setup",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "(Optional) Pre-Fetching Models",
        "content": "This step caches large models locally (if needed).  **Only do this**  if your workflow requires them.",
        "code_blocks": [
          {
            "language": "bash",
            "code": "crawl4ai-download-models",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Docker (Experimental)",
        "content": "We provide a  **temporary**  Docker approach for testing.  **It’s not stable and may break**  with future releases. We plan a major Docker revamp in a future stable version, 2025 Q1. If you still…",
        "code_blocks": [
          {
            "language": "bash",
            "code": "docker pull unclecode/crawl4ai:basic\ndocker run -p 11235:11235 unclecode/crawl4ai:basic",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Local Server Mode (Legacy)",
        "content": "Some older docs mention running Crawl4AI as a local server. This approach has been  **partially replaced**  by the new Docker-based prototype and upcoming stable server release. You can experiment,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Summary",
        "content": "1. **Install** with `pip install crawl4ai` and run `crawl4ai-setup`.\n2. **Diagnose** with `crawl4ai-doctor` if you see errors.\n3. **Verify** by crawling `example.com` with minimal `BrowserConfig` +…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "crawl4ai",
      "installation",
      "setup",
      "pip",
      "docker",
      "playwright",
      "web-crawling"
    ],
    "prerequisites": [],
    "_content_hash": "4812e8da37ab9fc451dfaf6f6029a5be4a927b79bd28be0f19f4adc8980dcc58",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/link-media/",
    "title": "Link & Media - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This tutorial covers how to extract and filter links (internal/external) and media (images, videos, audio) from crawled pages using Crawl4AI, including advanced link head extraction with scoring,…",
    "sections": [
      {
        "heading": "1. Link Extraction",
        "content": "When you call `arun()` or `arun_many()` on a URL, Crawl4AI automatically extracts links and stores them in the `links` field of `CrawlResult`. By default, the crawler tries to distinguish…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\"https://www.example.com\")\n    if result.success:\n        internal_links =…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "result.links = {\n  \"internal\": [\n    {\n      \"href\": \"https://kidocode.com/\",\n      \"text\": \"\",\n      \"title\": \"\",\n      \"base_domain\": \"kidocode.com\"\n    },\n    {\n      \"href\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Advanced Link Head Extraction & Scoring",
        "content": "Ever wanted to not just extract links, but also get the actual content (title, description, metadata) from those linked pages? And score them for relevance? This is exactly what Link Head Extraction…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai import LinkPreviewConfig\n\nasync def extract_link_heads_example():\n    \"\"\"\n    Complete example showing link head…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "✅ Successfully crawled: https://docs.python.org/3/\n📄 Page title: 3.13.5 Documentation\n🔗 Found 53 internal links\n🌍 Found 1 external links\n🧠 Links with head data extracted: 10\n\n🏆 Top 3 Links with Full…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import LinkPreviewConfig\n\nlink_preview_config = LinkPreviewConfig(\n    # BASIC SETTINGS\n    verbose=True,                    # Show detailed logs (recommended for learning)\n\n    # LINK…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# High intrinsic score indicators:\n# ✅ Clean URL structure (docs.python.org/api/reference)\n# ✅ Meaningful link text (\"API Reference Guide\")\n# ✅ Relevant to page context\n# ✅ Not buried deep in…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Example: query = \"machine learning tutorial\"\n# High contextual score: Link to \"Complete Machine Learning Guide\"\n# Low contextual score: Link to \"Privacy Policy\"",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# When both scores available: (intrinsic * 0.3) + (contextual * 0.7)\n# When only intrinsic: uses intrinsic score\n# When only contextual: uses contextual score\n# When neither: not calculated",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def research_assistant():\n    config = CrawlerRunConfig(\n        link_preview_config=LinkPreviewConfig(\n            include_internal=True,\n            include_external=True,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def api_discovery():\n    config = CrawlerRunConfig(\n        link_preview_config=LinkPreviewConfig(\n            include_internal=True,\n            include_patterns=[\"*/api/*\", \"*/reference/*\"],…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "async def quality_analysis():\n    config = CrawlerRunConfig(\n        link_preview_config=LinkPreviewConfig(\n            include_internal=True,\n            max_links=200,\n            concurrency=20,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Check your configuration:\nconfig = CrawlerRunConfig(\n    link_preview_config=LinkPreviewConfig(\n        verbose=True   # ← Enable to see what's happening\n    )\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Make sure scoring is enabled:\nconfig = CrawlerRunConfig(\n    score_links=True,  # ← Enable intrinsic scoring\n    link_preview_config=LinkPreviewConfig(\n        query=\"your search terms\"  # ← For…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Optimize performance:\nlink_preview_config = LinkPreviewConfig(\n    max_links=20,      # ← Reduce number\n    concurrency=10,    # ← Increase parallelism\n    timeout=3,         # ← Shorter timeout…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Domain Filtering",
        "content": "Some websites contain hundreds of third-party or affiliate links. You can filter out certain domains at **crawl time** by configuring the crawler. The most relevant parameters in `CrawlerRunConfig`…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    crawler_cfg = CrawlerRunConfig(\n        exclude_external_links=True,          # No links…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "crawler_cfg = CrawlerRunConfig(\n    exclude_domains=[\"suspiciousads.com\"]\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Media Extraction",
        "content": "###### 4.1 Accessing `result.media`\n\nBy default, Crawl4AI collects images, audio and video URLs it finds on the page. These are stored in `result.media`, a dictionary keyed by media type (e.g.,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "if result.success:\n    # Get images\n    images_info = result.media.get(\"images\", [])\n    print(f\"Found {len(images_info)} images in total.\")\n    for i, img in enumerate(images_info[:3]):  # Inspect…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "result.media = {\n  \"images\": [\n    {\n      \"src\": \"https://cdn.prod.website-files.com/.../Group%2089.svg\",\n      \"alt\": \"coding school for kids\",\n      \"desc\": \"Trial Class Degrees degrees All…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "crawler_cfg = CrawlerRunConfig(\n    exclude_external_images=True\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    crawler_cfg = CrawlerRunConfig(\n        capture_mhtml=True  # Enable MHTML capture\n    )\n\n    async with…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Putting It All Together: Link & Media Filtering",
        "content": "Here’s a combined example demonstrating how to filter out external links, skip certain domains, and exclude external images:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    # Suppose we want to keep only internal links, remove certain domains, \n    # and discard…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Common Pitfalls & Tips",
        "content": "1. **Conflicting Flags**:\n   - `exclude_external_links=True` but then also specifying `exclude_social_media_links=True` is typically fine, but understand that the first setting already discards *all*…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "link extraction",
      "media extraction",
      "domain filtering",
      "link scoring",
      "BM25",
      "MHTML",
      "image exclusion"
    ],
    "prerequisites": [],
    "_content_hash": "72ccc256d91223666d13632980480a94e948a4cb63e0f61d9a7a0461b3cdd6f9",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/llmtxt/",
    "title": "Llmtxt - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page documents the Llmtxt feature in Crawl4AI, which provides LLM-friendly text for crawled content. The provided raw content contains only navigation and UI elements, so the actual…",
    "sections": [
      {
        "heading": "Llmtxt",
        "content": "The provided raw content for this page contains only navigation and UI elements. No actual documentation text was found in the provided content.",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Llmtxt",
      "LLM",
      "Documentation"
    ],
    "prerequisites": [],
    "_content_hash": "c28c00b435e8391d2f7b5557e1cd6507779051daa7b371dba3d4d30277aa9e9e",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/local-files/",
    "title": "Prefix-Based Input Handling in Crawl4AI",
    "type": "guide",
    "summary": "This guide demonstrates how to use Crawl4AI to crawl web URLs, local HTML files, and raw HTML strings using prefix-based input handling with the unified `url` parameter and `CrawlerRunConfig`.",
    "sections": [
      {
        "heading": "Crawling a Web URL",
        "content": "To crawl a live web page, provide the URL starting with `http://` or `https://`, using a `CrawlerRunConfig` object:",
        "code_blocks": [
          {
            "language": "",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig\n\nasync def crawl_web():\n    config = CrawlerRunConfig(cache_mode=CacheMode.BYPASS)\n    async with AsyncWebCrawler() as…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Crawling a Local HTML File",
        "content": "To crawl a local HTML file, prefix the file path with `file://`.",
        "code_blocks": [
          {
            "language": "",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig\n\nasync def crawl_local_file():\n    local_file_path = \"/path/to/apple.html\"  # Replace with your file path\n    file_url…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Crawling Raw HTML Content",
        "content": "To crawl raw HTML content, prefix the HTML string with `raw:`.",
        "code_blocks": [
          {
            "language": "",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CacheMode\nfrom crawl4ai.async_configs import CrawlerRunConfig\n\nasync def crawl_raw_html():\n    raw_html = \"<html><body><h1>Hello,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complete Example",
        "content": "Below is a comprehensive script that:\n\n- Crawls the Wikipedia page for \"Apple.\"\n- Saves the HTML content to a local file (`apple.html`).\n- Crawls the local HTML file and verifies the markdown length…",
        "code_blocks": [
          {
            "language": "",
            "code": "import os\nimport sys\nimport asyncio\nfrom pathlib import Path\nfrom crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig\n\nasync def main():\n    wikipedia_url =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "With the unified `url` parameter and prefix-based handling in **Crawl4AI** , you can seamlessly handle web URLs, local HTML files, and raw HTML content. Use `CrawlerRunConfig` for flexible and…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "AsyncWebCrawler",
      "CrawlerRunConfig",
      "web crawling",
      "local files",
      "raw HTML",
      "Python",
      "prefix-based input"
    ],
    "prerequisites": [],
    "_content_hash": "e8b6548dee2e482c8681eb28e789cb308ffd5c1eaa0c249c27df72b5aac221f1",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/markdown-generation/",
    "title": "Markdown Generation Basics",
    "type": "guide",
    "summary": "This tutorial explains how to generate clean, structured markdown from web pages using Crawl4AI's DefaultMarkdownGenerator, including configuration options, content filters (BM25, Pruning, LLM), and…",
    "sections": [
      {
        "heading": "Prerequisites",
        "content": "> **Prerequisites** \n> \n> - You’ve completed or read [AsyncWebCrawler Basics](../simple-crawling/) to understand how to run a simple crawl.\n> \n> - You know how to configure `CrawlerRunConfig`.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Quick Example",
        "content": "Here’s a minimal code snippet that uses the **DefaultMarkdownGenerator** with no additional filtering:\n\n**What’s happening?** \n\n- `CrawlerRunConfig( markdown_generator = DefaultMarkdownGenerator() )`…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\n\nasync def main():\n    config = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. How Markdown Generation Works",
        "content": "Under the hood, **DefaultMarkdownGenerator** uses a specialized HTML-to-text approach that:\n\n- Preserves headings, code blocks, bullet points, etc.\n- Removes extraneous tags (scripts, styles) that…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.1 HTML-to-Text Conversion (Forked & Modified)",
        "content": "Under the hood, **DefaultMarkdownGenerator** uses a specialized HTML-to-text approach that:\n\n- Preserves headings, code blocks, bullet points, etc.\n- Removes extraneous tags (scripts, styles) that…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.2 Link Citations & References",
        "content": "By default, the generator can convert `<a href=\"...\">` elements into `[text][1]` citations, then place the actual links at the bottom of the document. This is handy for research workflows that demand…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2.3 Optional Content Filters",
        "content": "Before or after the HTML-to-Markdown step, you can apply a **content filter** (like BM25 or Pruning) to reduce noise and produce a “fit_markdown”—a heavily pruned version focusing on the page’s main…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3. Configuring the Default Markdown Generator",
        "content": "You can tweak the output by passing an `options` dict to `DefaultMarkdownGenerator`. For example:\n\nSome commonly used `options`:\n\n- **`ignore_links`** (bool): Whether to remove all hyperlinks in the…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Example: ignore all links, don't escape…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Selecting the HTML Source for Markdown Generation",
        "content": "The `content_source` parameter allows you to control which HTML content is used as input for markdown generation. This gives you flexibility in how the HTML is processed before conversion to markdown.",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Option 1: Use the raw HTML directly from the…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "HTML Source Options",
        "content": "- **`\"cleaned_html\"`** (default): Uses the HTML after it has been processed by the scraping strategy. This HTML is typically cleaner and more focused on content, with some boilerplate removed.\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "When to Use Each Option",
        "content": "- Use **`\"cleaned_html\"`** (default) for most cases where you want a balance of content preservation and noise removal.\n- Use **`\"raw_html\"`** when you need to preserve all original content, or when…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "5. Content Filters",
        "content": "**Content filters** selectively remove or rank sections of text before turning them into Markdown. This is especially helpful if your page has ads, nav bars, or other clutter you don’t want.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "5.1 BM25ContentFilter",
        "content": "If you have a **search query**, BM25 is a good choice:\n\n- **`user_query`**: The term you want to focus on. BM25 tries to keep only content blocks relevant to that query.\n- **`bm25_threshold`**: Raise…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\nfrom crawl4ai.content_filter_strategy import BM25ContentFilter\nfrom crawl4ai import CrawlerRunConfig\n\nbm25_filter =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5.2 PruningContentFilter",
        "content": "If you **don’t** have a specific query, or if you just want a robust “junk remover,” use `PruningContentFilter`. It analyzes text density, link density, HTML structure, and known patterns (like…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai.content_filter_strategy import PruningContentFilter\n\nprune_filter = PruningContentFilter(\n    threshold=0.5,\n    threshold_type=\"fixed\",  # or \"dynamic\"\n    min_word_threshold=50\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5.3 LLMContentFilter",
        "content": "For intelligent content filtering and high-quality markdown generation, you can use the **LLMContentFilter**. This filter leverages LLMs to generate relevant markdown while preserving the original…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, LLMConfig, DefaultMarkdownGenerator\nfrom crawl4ai.content_filter_strategy import LLMContentFilter\n\nasync def main():\n    #…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "filter = LLMContentFilter(\n    instruction=\"\"\"\n    Extract the main educational content while preserving its original wording and substance completely.\n    1. Maintain the exact language and…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "filter = LLMContentFilter(\n    instruction=\"\"\"\n    Focus on extracting specific types of content:\n    - Technical documentation\n    - Code examples\n    - API references\n    Reformat the content into…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Using Fit Markdown",
        "content": "When a content filter is active, the library produces two forms of markdown inside `result.markdown`:\n\n1. **`raw_markdown`**: The full unfiltered markdown.\n2. **`fit_markdown`**: A “fit” version…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\nfrom crawl4ai.content_filter_strategy import…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. The `MarkdownGenerationResult` Object",
        "content": "If your library stores detailed markdown output in an object like `MarkdownGenerationResult`, you’ll see fields such as:\n\n- **`raw_markdown`**: The direct HTML-to-markdown transformation (no…",
        "code_blocks": [
          {
            "language": "python",
            "code": "md_obj = result.markdown  # your library’s naming may vary\nprint(\"RAW:\\n\", md_obj.raw_markdown)\nprint(\"CITED:\\n\", md_obj.markdown_with_citations)\nprint(\"REFERENCES:\\n\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Combining Filters (BM25 + Pruning) in Two Passes",
        "content": "You might want to **prune out** noisy boilerplate first (with `PruningContentFilter`), and then **rank what’s left** against a user query (with `BM25ContentFilter`). You don’t have to crawl the page…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Two-Pass Example",
        "content": "###### What’s Happening?\n\n1. **Raw HTML**: We crawl once and store the raw HTML in `result.html`.\n2. **PruningContentFilter**: Takes HTML + optional parameters. It extracts blocks of text or partial…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.content_filter_strategy import PruningContentFilter, BM25ContentFilter\nfrom bs4 import BeautifulSoup\n\nasync def…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Tips & Variations",
        "content": "- **Plain Text vs. HTML**: If your pruned output is mostly text, BM25 can still handle it; just keep in mind it expects a valid string input. If you supply partial HTML (like `\"<p>some text</p>\"`),…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "One-Pass Combination?",
        "content": "If your codebase or pipeline design allows applying multiple filters in one pass, you could do so. But often it’s simpler—and more transparent—to run them sequentially, analyzing each step’s…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "9. Common Pitfalls & Tips",
        "content": "1. **No Markdown Output?** \n   - Make sure the crawler actually retrieved HTML. If the site is heavily JS-based, you may need to enable dynamic rendering or wait for elements.\n   - Check if your…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "10. Summary & Next Steps",
        "content": "In this **Markdown Generation Basics** tutorial, you learned to:\n\n- Configure the **DefaultMarkdownGenerator** with HTML-to-text options.\n- Select different HTML sources using the `content_source`…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "markdown",
      "crawl4ai",
      "content filtering",
      "BM25",
      "pruning",
      "LLM",
      "html2text",
      "DefaultMarkdownGenerator"
    ],
    "prerequisites": [],
    "_content_hash": "839bf650d07cc204d93f9b3f31904a9f2dcbe4b6fbdc1a999a85eb4700c59303",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/page-interaction/",
    "title": "Page Interaction - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page explains how to interact with dynamic webpages using Crawl4AI, covering JavaScript execution, wait conditions, multi-step flows, Shadow DOM flattening, and virtual scrolling.",
    "sections": [
      {
        "heading": "Page Interaction",
        "content": "Crawl4AI provides powerful features for interacting with **dynamic** webpages, handling JavaScript execution, waiting for conditions, and managing multi-step flows. By combining **js_code**,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. JavaScript Execution",
        "content": "###### Basic Execution\n\n**`js_code`** in **`CrawlerRunConfig`** accepts either a single JS string or a list of JS snippets. It runs **after** `wait_for` and `delay_before_return_html` — so the page is…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Single JS command\n    config = CrawlerRunConfig(\n        js_code=\"window.scrollTo(0,…",
            "filename": ""
          },
          {
            "language": "text",
            "code": "1. Page navigation (page.goto)\n2. js_code_before_wait     ← triggers loading / clicks tabs\n3. wait_for                ← waits for content to appear\n4. delay_before_return_html ← extra safety…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    # Click a tab first\n    js_code_before_wait=\"document.querySelector('#specs-tab')?.click();\",\n    # Then wait for the tab content to appear…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Wait Conditions",
        "content": "###### 2.1 CSS-Based Waiting\n\nSometimes, you just want to wait for a specific element to appear. For example:\n\n**Key param**:\n- **`wait_for=\"css:...\"`**: Tells the crawler to wait until that CSS…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    config = CrawlerRunConfig(\n        # Wait for at least 30 items on Hacker News…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "wait_condition = \"\"\"() => {\n    const items = document.querySelectorAll('.athing');\n    return items.length > 50;  // Wait for at least 51 items\n}\"\"\"\n\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Handling Dynamic Content",
        "content": "Many modern sites require **multiple steps**: scrolling, clicking “Load More,” or updating via JavaScript. Below are typical patterns.\n\n###### 3.1 Load More Example (Hacker News “More” Link)\n\n**Key…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def main():\n    # Step 1: Load initial Hacker News page\n    config = CrawlerRunConfig(…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "js_form_interaction = \"\"\"\ndocument.querySelector('#your-search').value = 'TypeScript commits';\ndocument.querySelector('form').submit();\n\"\"\"\n\nconfig = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Timing Control",
        "content": "1. **`page_timeout`** (ms): Overall page load or script execution time limit.\n2. **`delay_before_return_html`** (seconds): Wait an extra moment before capturing the final HTML.\n3. **`mean_delay`** &…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    page_timeout=60000,  # 60s limit\n    delay_before_return_html=2.5\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Multi-Step Interaction Example",
        "content": "Below is a simplified script that does multiple “Load More” clicks on GitHub’s TypeScript commits page. It **re-uses** the same session to accumulate new commits each time. The code includes the…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def multi_page_commits():\n    browser_cfg = BrowserConfig(\n        headless=False,  # Visible…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Combine Interaction with Extraction",
        "content": "Once dynamic content is loaded, you can attach an **`extraction_strategy`** (like `JsonCssExtractionStrategy` or `LLMExtractionStrategy`). For example:\n\nWhen done, check `result.extracted_content`…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy\n\nschema = {\n    \"name\": \"Commits\",\n    \"baseSelector\": \"li.Box-sc-g0xbh4-0\",\n    \"fields\": [\n        {\"name\": \"title\", \"selector\": \"h4.markdown-title\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Shadow DOM Flattening",
        "content": "Sites built with **Web Components** (Stencil, Lit, Shoelace, etc.) render content inside Shadow DOM — an encapsulated sub-tree that is invisible to normal page serialization. Set…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    flatten_shadow_dom=True,\n    wait_until=\"load\",\n    delay_before_return_html=3.0,  # give components time to hydrate\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Relevant `CrawlerRunConfig` Parameters",
        "content": "Below are the key interaction-related parameters in `CrawlerRunConfig`. For a full list, see [Configuration Parameters](../../api/parameters/).\n\n- **`js_code`**: JavaScript to run after `wait_for` +…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "9. Conclusion",
        "content": "Crawl4AI's **page interaction** features let you:\n\n1. **Execute JavaScript** for scrolling, clicks, or form filling.\n2. **Wait** for CSS or custom JS conditions before capturing data.\n3. **Handle**…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "10. Virtual Scrolling",
        "content": "For sites that use **virtual scrolling** (where content is replaced rather than appended as you scroll, like Twitter or Instagram), Crawl4AI provides a dedicated `VirtualScrollConfig`:\n\n###### Virtual…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, VirtualScrollConfig\n\nasync def crawl_twitter_timeline():\n    # Configure virtual scroll for Twitter-like feeds\n    virtual_config =…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "JavaScript execution",
      "wait_for",
      "session_id",
      "Shadow DOM",
      "virtual scrolling",
      "dynamic content",
      "web scraping",
      "CrawlerRunConfig"
    ],
    "prerequisites": [],
    "_content_hash": "8afa8d987012363882641cd5c008b02ff6551be27d2077c3b82a7f1a78afb4a6",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/quickstart/",
    "title": "Quick Start - Crawl4AI Documentation (v0.9.x)",
    "type": "reference",
    "summary": "Extraction fallback content.",
    "sections": [
      {
        "heading": "Quick Start - Crawl4AI Documentation (v0.9.x)",
        "content": "\n\n\n##### Getting Started with Crawl4AI\n\n\n\n\nWelcome to  **Crawl4AI** , an open-source LLM-friendly Web Crawler & Scraper. In this tutorial, you’ll:\n\n\n\n\n\n\n- Run your  **first crawl**  using minimal configuration.\n\n- Generate  **Markdown**  output (and learn how it’s influenced by content filters).\n\n- Experiment with a simple  **CSS-based extraction**  strategy.\n\n- See a glimpse of  **LLM-based extraction**  (including open-source and closed-source model options).\n\n- Crawl a  **dynamic**  page that loads content via JavaScript.\n\n\n\n\n\n\n##### 1. Introduction\n\n\n\n\nCrawl4AI provides:\n\n\n\n\n\n\n- An asynchronous crawler,  **`AsyncWebCrawler`** .\n\n- Configurable browser and run settings via  **`BrowserConfig`**  and  **`CrawlerRunConfig`** .\n\n- Automatic HTML-to-Markdown conversion via  **`DefaultMarkdownGenerator`**  (supports optional filters).\n\n- Multiple extraction strategies (LLM-based or “traditional” CSS/XPath-based).\n\n\n\n\n\nBy the end of this guide, you’ll have performed a basic crawl, generated Markdown, tried out two extraction strategies, and crawled a dynamic page that uses “Load More” buttons or JavaScript updates.\n\n\n\n\n\n##### 2. Your First Crawl\n\n\n\n\nHere’s a minimal Python script that creates an  **`AsyncWebCrawler`** , fetches a webpage, and prints the first 300 characters of its Markdown output:\n\n\n\n\n\n **What’s happening?** \n-  **`AsyncWebCrawler`**  launches a headless browser (Chromium by default).\n- It fetches `https://example.com`.\n- Crawl4AI automatically converts the HTML into Markdown.\n\n\n\n\nYou now have a simple, working crawl!\n\n\n\n\n\n##### 3. Basic Configuration (Light Introduction)\n\n\n\n\nCrawl4AI’s crawler can be heavily customized using two main classes:\n\n\n\n\n1.  **`BrowserConfig`** : Controls browser behavior (headless or full UI, user agent, JavaScript toggles, etc.).\n\n2.  **`CrawlerRunConfig`** : Controls how each crawl runs (caching, extraction, timeouts, hooking, etc.).\n\n\n\n\nBelow is an example with minimal usage:\n\n\n\n\n\n> IMPORTANT: By default cache mode is set to `CacheMode.BYPASS` to have fresh content. Set `CacheMode.ENABLED` to enable caching.\n\n\n\n\nWe’ll explore more advanced config in later tutorials (like enabling proxies, PDF output, multi-tab sessions, etc.). For now, just note how you pass these objects to manage crawling.\n\n\n\n\n\n##### 4. Generating Markdown Output\n\n\n\n\nBy default, Crawl4AI automatically generates Markdown from each crawled page. However, the exact output depends on whether you specify a  **markdown generator**  or  **content filter** .\n\n\n\n\n\n\n- **`result.markdown`** :\n\n  The direct HTML-to-Markdown conversion.\n\n- **`result.markdown.fit_markdown`** :\n\n  The same content after applying any configured  **content filter**  (e.g., `PruningContentFilter`).\n\n\n\n\n\n###### Example: Using a Filter with `DefaultMarkdownGenerator`\n\n\n\n\n\n **Note** : If you do  **not**  specify a content filter or markdown generator, you’ll typically see only the raw Markdown. `PruningContentFilter` may adds around `50ms` in processing time. We’ll dive deeper into these strategies in a dedicated  **Markdown Generation**  tutorial.\n\n\n\n\n\n##### 5. Simple Data Extraction (CSS-based)\n\n\n\n\nCrawl4AI can also extract structured data (JSON) using CSS or XPath selectors. Below is a minimal CSS-based example:\n\n\n\n\n> **New!**  Crawl4AI now provides a powerful utility to automatically generate extraction schemas using LLM. This is a one-time cost that gives you a reusable schema for fast, LLM-free extractions:\n\n\n\n\n\nFor a complete guide on schema generation and advanced usage, see [No-LLM Extraction Strategies](../../extraction/no-llm-strategies/).\n\n\n\n\nHere's a basic extraction example:\n\n\n\n\n\n **Why is this helpful?** \n- Great for repetitive page structures (e.g., item listings, articles).\n- No AI usage or costs.\n- The crawler returns a JSON string you can parse or store.\n\n\n\n\n> Tips: You can pass raw HTML to the crawler instead of a URL. To do so, prefix the HTML with `raw://`.\n\n\n\n\n\n##### 6. Simple Data Extraction (LLM-based)\n\n\n\n\nFor more complex or irregular pages, a language model can parse text intelligently into a structure you define. Crawl4AI supports  **open-source**  or  **closed-source**  providers:\n\n\n\n\n\n\n- **Open-Source Models**  (e.g., `ollama/llama3.3`, `no_token`)\n\n- **OpenAI Models**  (e.g., `openai/gpt-4`, requires `api_token`)\n\n- Or any provider supported by the underlying library\n\n\n\n\n\nBelow is an example using  **open-source**  style (no token) and closed-source:\n\n\n\n\n\n **What’s happening?** \n- We define a Pydantic schema (`PricingInfo`) describing the fields we want.\n- The LLM extraction strategy uses that schema and your instructions to transform raw text into structured JSON.\n- Depending on the  **provider**  and  **api_token** , you can use local models or a remote API.\n\n\n\n\n\n##### 7. Adaptive Crawling (New!)\n\n\n\n\nCrawl4AI now includes intelligent adaptive crawling that automatically determines when sufficient information has been gathered. Here's a quick example:\n\n\n\n\n\n **What's special about adaptive crawling?** \n-  **Automatic stopping** : Stops when sufficient information is gathered\n-  **Intelligent link selection** : Follows only relevant links\n-  **Confidence scoring** : Know how complete your information is\n\n\n\n\n[Learn more about Adaptive Crawling →](../adaptive-crawling/)\n\n\n\n\n\n##### 8. Multi-URL Concurrency (Preview)\n\n\n\n\nIf you need to crawl multiple URLs in  **parallel** , you can use `arun_many()`. By default, Crawl4AI employs a  **MemoryAdaptiveDispatcher** , automatically adjusting concurrency based on system resources. Here’s a quick glimpse:\n\n\n\n\n\nThe example above shows two ways to handle multiple URLs:\n1.  **Streaming mode**  (`stream=True`): Process results as they become available using `async for`\n2.  **Batch mode**  (`stream=False`): Wait for all results to complete\n\n\n\n\nFor more advanced concurrency (e.g., a  **semaphore-based**  approach,  **adaptive memory usage throttling** , or customized rate limiting), see [Advanced Multi-URL Crawling](../../advanced/multi-url-crawling/).\n\n\n\n\n\n##### 8. Dynamic Content Example\n\n\n\n\nSome sites require multiple “page clicks” or dynamic JavaScript updates. Below is an example showing how to  **click**  a “Next Page” button and wait for new commits to load on GitHub, using  **`BrowserConfig`**  and  **`CrawlerRunConfig`** :\n\n\n\n\n\n **Key Points** :\n\n\n\n\n\n\n- **`BrowserConfig(headless=False)`** : We want to watch it click “Next Page.”\n\n- **`CrawlerRunConfig(...)`** : We specify the extraction strategy, pass `session_id` to reuse the same page.\n\n- **`js_code`**  and  **`wait_for`**  are used for subsequent pages (`page > 0`) to click the “Next” button and wait for new commits to load.\n\n- **`js_only=True`**  indicates we’re not re-navigating but continuing the existing session.\n\n- Finally, we call `kill_session()` to clean up the page and browser session.\n\n\n\n\n\n\n##### 9. Next Steps\n\n\n\n\nCongratulations! You have:\n\n\n\n\n\n\n- Performed a basic crawl and printed Markdown.\n\n- Used  **content filters**  with a markdown generator.\n\n- Extracted JSON via  **CSS**  or  **LLM**  strategies.\n\n- Handled  **dynamic**  pages with JavaScript triggers.\n\n\n\n\n\nIf you’re ready for more, check out:\n\n\n\n\n\n\n- **Installation** : A deeper dive into advanced installs, Docker usage (experimental), or optional dependencies.\n\n- **Hooks & Auth** : Learn how to run custom JavaScript or handle logins with cookies, local storage, etc.\n\n- **Deployment** : Explore ephemeral testing in Docker or plan for the upcoming stable Docker release.\n\n- **Browser Management** : Delve into user simulation, stealth modes, and concurrency best practices.\n\n\n\n\n\nCrawl4AI is a powerful, flexible tool. Enjoy building out your scrapers, data pipelines, or AI-driven extraction flows. Happy crawling!\n\n\n\nPage Copy\nPage Copy\n\n\n\n\n- [Copy as Markdown\nCopy page for LLMs](#)\n\n- [View as Markdown\nOpen raw source](#)\n\n\n- [Open in ChatGPT\nAsk questions about this page](#)\n\n\n\nESC to close\n",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\n\nasync def main():\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(\"https://example.com\")\n        print(result.markdown[:300])  # Print first 300 chars\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def main():\n    browser_conf = BrowserConfig(headless=True)  # or False to see the browser\n    run_conf = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS\n    )\n\n    async with AsyncWebCrawler(config=browser_conf) as crawler:\n        result = await crawler.arun(\n            url=\"https://example.com\",\n            config=run_conf\n        )\n        print(result.markdown)\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai.content_filter_strategy import PruningContentFilter\nfrom crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator\n\nmd_generator = DefaultMarkdownGenerator(\n    content_filter=PruningContentFilter(threshold=0.4, threshold_type=\"fixed\")\n)\n\nconfig = CrawlerRunConfig(\n    cache_mode=CacheMode.BYPASS,\n    markdown_generator=md_generator\n)\n\nasync with AsyncWebCrawler() as crawler:\n    result = await crawler.arun(\"https://news.ycombinator.com\", config=config)\n    print(\"Raw Markdown length:\", len(result.markdown.raw_markdown))\n    print(\"Fit Markdown length:\", len(result.markdown.fit_markdown))",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy\nfrom crawl4ai import LLMConfig\n\n# Generate a schema (one-time cost)\nhtml = \"<div class='product'><h2>Gaming Laptop</h2><span class='price'>$999.99</span></div>\"\n\n# Using OpenAI (requires API token)\nschema = JsonCssExtractionStrategy.generate_schema(\n    html,\n    llm_config = LLMConfig(provider=\"openai/gpt-4o\",api_token=\"your-openai-token\")  # Required for OpenAI\n)\n\n# Or using Ollama (open source, no token needed)\nschema = JsonCssExtractionStrategy.generate_schema(\n    html,\n    llm_config = LLMConfig(provider=\"ollama/llama3.3\", api_token=None)  # Not needed for Ollama\n)\n\n# Use the schema for fast, repeated extractions\nstrategy = JsonCssExtractionStrategy(schema)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nimport json\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def main():\n    schema = {\n        \"name\": \"Example Items\",\n        \"baseSelector\": \"div.item\",\n        \"fields\": [\n            {\"name\": \"title\", \"selector\": \"h2\", \"type\": \"text\"},\n            {\"name\": \"link\", \"selector\": \"a\", \"type\": \"attribute\", \"attribute\": \"href\"}\n        ]\n    }\n\n    raw_html = \"<div class='item'><h2>Item 1</h2><a href='https://example.com/item1'>Link 1</a></div>\"\n\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(\n            url=\"raw://\" + raw_html,\n            config=CrawlerRunConfig(\n                cache_mode=CacheMode.BYPASS,\n                extraction_strategy=JsonCssExtractionStrategy(schema)\n            )\n        )\n        # The JSON output is stored in 'extracted_content'\n        data = json.loads(result.extracted_content)\n        print(data)\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import os\nimport json\nimport asyncio\nfrom pydantic import BaseModel, Field\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig\nfrom crawl4ai import LLMExtractionStrategy\n\nclass OpenAIModelFee(BaseModel):\n    model_name: str = Field(..., description=\"Name of the OpenAI model.\")\n    input_fee: str = Field(..., description=\"Fee for input token for the OpenAI model.\")\n    output_fee: str = Field(\n        ..., description=\"Fee for output token for the OpenAI model.\"\n    )\n\nasync def extract_structured_data_using_llm(\n    provider: str, api_token: str = None, extra_headers: Dict[str, str] = None\n):\n    print(f\"\\n--- Extracting Structured Data with {provider} ---\")\n\n    if api_token is None and provider != \"ollama\":\n        print(f\"API token is required for {provider}. Skipping this example.\")\n        return\n\n    browser_config = BrowserConfig(headless=True)\n\n    extra_args = {\"temperature\": 0, \"top_p\": 0.9, \"max_tokens\": 2000}\n    if extra_headers:\n        extra_args[\"extra_headers\"] = extra_headers\n\n    crawler_config = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        word_count_threshold=1,\n        page_timeout=80000,\n        extraction_strategy=LLMExtractionStrategy(\n            llm_config = LLMConfig(provider=provider,api_token=api_token),\n            schema=OpenAIModelFee.model_json_schema(),\n            extraction_type=\"schema\",\n            instruction=\"\"\"From the crawled content, extract all mentioned model names along with their fees for input and output tokens. \n            Do not miss any models in the entire content.\"\"\",\n            extra_args=extra_args,\n        ),\n    )\n\n    async with AsyncWebCrawler(config=browser_config) as crawler:\n        result = await crawler.arun(\n            url=\"https://openai.com/api/pricing/\", config=crawler_config\n        )\n        print(result.extracted_content)\n\nif __name__ == \"__main__\":\n\n    asyncio.run(\n        extract_structured_data_using_llm(\n            provider=\"openai/gpt-4o\", api_token=os.getenv(\"OPENAI_API_KEY\")\n        )\n    )",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, AdaptiveCrawler\n\nasync def adaptive_example():\n    async with AsyncWebCrawler() as crawler:\n        adaptive = AdaptiveCrawler(crawler)\n\n        # Start adaptive crawling\n        result = await adaptive.digest(\n            start_url=\"https://docs.python.org/3/\",\n            query=\"async context managers\"\n        )\n\n        # View results\n        adaptive.print_stats()\n        print(f\"Crawled {len(result.crawled_urls)} pages\")\n        print(f\"Achieved {adaptive.confidence:.0%} confidence\")\n\nif __name__ == \"__main__\":\n    asyncio.run(adaptive_example())",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\n\nasync def quick_parallel_example():\n    urls = [\n        \"https://example.com/page1\",\n        \"https://example.com/page2\",\n        \"https://example.com/page3\"\n    ]\n\n    run_conf = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        stream=True  # Enable streaming mode\n    )\n\n    async with AsyncWebCrawler() as crawler:\n        # Stream results as they complete\n        async for result in await crawler.arun_many(urls, config=run_conf):\n            if result.success:\n                print(f\"[OK] {result.url}, length: {len(result.markdown.raw_markdown)}\")\n            else:\n                print(f\"[ERROR] {result.url} => {result.error_message}\")\n\n        # Or get all results at once (default behavior)\n        run_conf = run_conf.clone(stream=False)\n        results = await crawler.arun_many(urls, config=run_conf)\n        for res in results:\n            if res.success:\n                print(f\"[OK] {res.url}, length: {len(res.markdown.raw_markdown)}\")\n            else:\n                print(f\"[ERROR] {res.url} => {res.error_message}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(quick_parallel_example())",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def extract_structured_data_using_css_extractor():\n    print(\"\\n--- Using JsonCssExtractionStrategy for Fast Structured Output ---\")\n    schema = {\n        \"name\": \"KidoCode Courses\",\n        \"baseSelector\": \"section.charge-methodology .w-tab-content > div\",\n        \"fields\": [\n            {\n                \"name\": \"section_title\",\n                \"selector\": \"h3.heading-50\",\n                \"type\": \"text\",\n            },\n            {\n                \"name\": \"section_description\",\n                \"selector\": \".charge-content\",\n                \"type\": \"text\",\n            },\n            {\n                \"name\": \"course_name\",\n                \"selector\": \".text-block-93\",\n                \"type\": \"text\",\n            },\n            {\n                \"name\": \"course_description\",\n                \"selector\": \".course-content-text\",\n                \"type\": \"text\",\n            },\n            {\n                \"name\": \"course_icon\",\n                \"selector\": \".image-92\",\n                \"type\": \"attribute\",\n                \"attribute\": \"src\",\n            },\n        ],\n    }\n\n    browser_config = BrowserConfig(headless=True, java_script_enabled=True)\n\n    js_click_tabs = \"\"\"\n    (async () => {\n        const tabs = document.querySelectorAll(\"section.charge-methodology .tabs-menu-3 > div\");\n        for(let tab of tabs) {\n            tab.scrollIntoView();\n            tab.click();\n            await new Promise(r => setTimeout(r, 500));\n        }\n    })();\n    \"\"\"\n\n    crawler_config = CrawlerRunConfig(\n        cache_mode=CacheMode.BYPASS,\n        extraction_strategy=JsonCssExtractionStrategy(schema),\n        js_code=[js_click_tabs],\n    )\n\n    async with AsyncWebCrawler(config=browser_config) as crawler:\n        result = await crawler.arun(\n            url=\"https://www.kidocode.com/degrees/technology\", config=crawler_config\n        )\n\n        companies = json.loads(result.extracted_content)\n        print(f\"Successfully extracted {len(companies)} companies\")\n        print(json.dumps(companies[0], indent=2))\n\nasync def main():\n    await extract_structured_data_using_css_extractor()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [],
    "prerequisites": [],
    "_content_hash": "8773ee69dcfa284a361cf43db1bedc0b6ec9dc755bff766a8d0ec29275b10c30",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/simple-crawling/",
    "title": "Simple Crawling",
    "type": "guide",
    "summary": "This guide covers the basics of web crawling with Crawl4AI, including setting up a crawler, making requests, understanding responses, and handling errors.",
    "sections": [
      {
        "heading": "Basic Usage",
        "content": "Set up a simple crawl using `BrowserConfig` and `CrawlerRunConfig`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\nfrom crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig\n\nasync def main():\n    browser_config = BrowserConfig()  # Default browser…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Understanding the Response",
        "content": "The `arun()` method returns a `CrawlResult` object with several useful properties. Here's a quick overview (see [CrawlResult](../../api/crawl-result/) for complete details):",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    markdown_generator=DefaultMarkdownGenerator(\n        content_filter=PruningContentFilter(threshold=0.6),\n        options={\"ignore_links\": True}\n    )\n)\n\nresult = await…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Adding Basic Options",
        "content": "Customize your crawl using `CrawlerRunConfig`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig(\n    word_count_threshold=10,        # Minimum words per content block\n    exclude_external_links=True,    # Remove external links\n    remove_overlay_elements=True,   #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Handling Errors",
        "content": "Always check if the crawl was successful:",
        "code_blocks": [
          {
            "language": "python",
            "code": "run_config = CrawlerRunConfig()\nresult = await crawler.arun(url=\"https://example.com\", config=run_config)\n\nif not result.success:\n    print(f\"Crawl failed: {result.error_message}\")\n    print(f\"Status…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Logging and Debugging",
        "content": "Enable verbose logging in `BrowserConfig`:",
        "code_blocks": [
          {
            "language": "python",
            "code": "browser_config = BrowserConfig(verbose=True)\n\nasync with AsyncWebCrawler(config=browser_config) as crawler:\n    run_config = CrawlerRunConfig()\n    result = await…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complete Example",
        "content": "Here's a more comprehensive example demonstrating common usage patterns:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler\nfrom crawl4ai.async_configs import BrowserConfig, CrawlerRunConfig, CacheMode\n\nasync def main():\n    browser_config = BrowserConfig(verbose=True)…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "web crawling",
      "AsyncWebCrawler",
      "BrowserConfig",
      "CrawlerRunConfig",
      "CrawlResult",
      "Python",
      "asyncio"
    ],
    "prerequisites": [],
    "_content_hash": "7d81ab3ce1a8c8b51c59417b112969fd4ac67e9fad3fd09086de8c487f0d956d",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/table_extraction/",
    "title": "Table Extraction Strategies - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page covers Crawl4AI's table extraction strategies, including the default algorithm, LLM-based extraction, and custom strategies. It explains the strategy design pattern, configuration options,…",
    "sections": [
      {
        "heading": "Overview",
        "content": "**New in v0.7.3+** : Table extraction now follows the **Strategy Design Pattern** , providing unprecedented flexibility and power for handling different table structures. Don't worry - **your…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What's Changed?",
        "content": "- **Architecture** : Table extraction now uses pluggable strategies\n- **Backward Compatible** : Your existing code with `table_score_threshold` continues to work\n- **More Power** : Choose from…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Key Points",
        "content": "✅ **Old code still works** - No breaking changes\n✅ **Same default behavior** - Uses the proven extraction algorithm\n✅ **New capabilities** - Add LLM extraction or custom strategies when needed\n✅…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Quick Start",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "The Simplest Way (Works Like Before)",
        "content": "If you're already using Crawl4AI, nothing changes:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def extract_tables():\n    async with AsyncWebCrawler() as crawler:\n        # This works exactly like before - uses…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Using the Old Configuration (Still Supported)",
        "content": "Your existing code with `table_score_threshold` continues to work:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# This old approach STILL WORKS - we maintain backward compatibility\nconfig = CrawlerRunConfig(\n    table_score_threshold=7  # Internally creates…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Table Extraction Strategies",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Understanding the Strategy Pattern",
        "content": "The strategy pattern allows you to choose different table extraction algorithms at runtime. Think of it as having different tools in a toolbox - you pick the right one for the job:\n\n- **No explicit…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Available Strategies",
        "content": "| Strategy | Description | Use Case | Cost | When to Use |\n| --- | --- | --- | --- | --- |\n| `DefaultTableExtraction` | **RECOMMENDED** : Same algorithm as before v0.7.3 | General purpose (default) |…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "DefaultTableExtraction",
        "content": "The default strategy uses a sophisticated scoring system to identify data tables:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import DefaultTableExtraction, CrawlerRunConfig\n\n# Customize the default extraction\ntable_strategy = DefaultTableExtraction(\n    table_score_threshold=7,  # Scoring threshold (default:…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Scoring System",
        "content": "The scoring system evaluates multiple factors:\n\n| Factor | Score Impact | Description |\n| --- | --- | --- |\n| Has `<thead>` | +2 | Semantic table structure |\n| Has `<tbody>` | +1 | Organized table…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "LLMTableExtraction (Use Sparingly!)",
        "content": "**⚠️ WARNING** : Only use this when `DefaultTableExtraction` fails with complex tables!\n\nLLMTableExtraction uses AI to understand complex table structures that traditional parsers struggle with. It…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import LLMTableExtraction, LLMConfig, CrawlerRunConfig\n\n# Configure LLM (costs money per call!)\nllm_config = LLMConfig(\n    provider=\"groq/llama-3.3-70b-versatile\",  # Fast provider for…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "When to Use LLMTableExtraction",
        "content": "✅ **Use ONLY when** :\n- Tables have complex merged cells (rowspan/colspan) that break DefaultTableExtraction\n- Nested tables that need semantic understanding\n- Tables with irregular structures\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How Smart Chunking Works",
        "content": "LLMTableExtraction automatically handles large tables through intelligent chunking:\n\n- **Automatic Detection** : Tables exceeding the token threshold are automatically split\n- **Smart Splitting** :…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Performance Optimization for LLMTableExtraction",
        "content": "**Provider Recommendations by Table Size** :\n\n| Table Size | Recommended Providers | Why |\n| --- | --- | --- |\n| Small (<50 rows) | Any provider | Fast enough |\n| Medium (50-200 rows) | Groq,…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "NoTableExtraction",
        "content": "Disable table extraction for better performance when tables aren't needed:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import NoTableExtraction, CrawlerRunConfig\n\nconfig = CrawlerRunConfig(\n    table_extraction=NoTableExtraction()\n)\n\n# Tables won't be extracted, improving performance\nresult = await…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Extracted Table Structure",
        "content": "Each extracted table contains:",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n    \"headers\": [\"Column 1\", \"Column 2\", ...],  # Column headers\n    \"rows\": [                                   # Data rows\n        [\"Row 1 Col 1\", \"Row 1 Col 2\", ...],\n        [\"Row 2 Col 1\", \"Row…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Options",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Configuration",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    # Table extraction settings\n    table_score_threshold=7,      # Default threshold (backward compatible)\n    table_extraction=strategy,     # Optional: custom strategy…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Configuration",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import DefaultTableExtraction, CrawlerRunConfig\n\n# Fine-tuned extraction\nstrategy = DefaultTableExtraction(\n    table_score_threshold=5,      # Lower = more permissive\n    min_rows=3,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Working with Extracted Tables",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Convert to Pandas DataFrame",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import pandas as pd\n\nasync def tables_to_dataframes(url):\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(url)\n\n        dataframes = []\n        for table_data in…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Filter Tables by Criteria",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def extract_large_tables(url):\n    async with AsyncWebCrawler() as crawler:\n        # Configure minimum size requirements\n        strategy = DefaultTableExtraction(\n            min_rows=10,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Export Tables to Different Formats",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "import json\nimport csv\n\nasync def export_tables(url):\n    async with AsyncWebCrawler() as crawler:\n        result = await crawler.arun(url)\n\n        for i, table in enumerate(result.tables):…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Creating Custom Strategies",
        "content": "Extend `TableExtractionStrategy` to create custom extraction logic:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Example: Financial Table Extractor",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import TableExtractionStrategy\nfrom typing import List, Dict, Any\nimport re\n\nclass FinancialTableExtractor(TableExtractionStrategy):\n    \"\"\"Extract tables containing financial…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Example: Specific Table Extractor",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "class SpecificTableExtractor(TableExtractionStrategy):\n    \"\"\"Extract only tables matching specific criteria.\"\"\"\n\n    def __init__(self, \n                 required_headers=None,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining with Other Strategies",
        "content": "Table extraction works seamlessly with other Crawl4AI strategies:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import (\n    AsyncWebCrawler,\n    CrawlerRunConfig,\n    DefaultTableExtraction,\n    LLMExtractionStrategy,\n    JsonCssExtractionStrategy\n)\n\nasync def combined_extraction(url):\n    async…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Considerations",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Optimization Tips",
        "content": "- **Disable when not needed** : Use `NoTableExtraction` if tables aren't required\n- **Target specific areas** : Use `css_selector` to limit processing scope\n- **Set minimum thresholds** : Filter out…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Optimized configuration for large pages\nconfig = CrawlerRunConfig(\n    # Only process main content area\n    css_selector=\"article.main-content\",\n\n    # Exclude navigation and sidebars…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Migration Guide",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Important: Your Code Still Works!",
        "content": "**No changes required!** The transition to the strategy pattern is **fully backward compatible** .",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How It Works Internally",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "v0.7.2 and Earlier",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Old way - directly passing table_score_threshold\nconfig = CrawlerRunConfig(\n    table_score_threshold=7\n)\n# Internally: No strategy pattern, direct implementation",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "v0.7.3+ (Current)",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Old way STILL WORKS - we handle it internally\nconfig = CrawlerRunConfig(\n    table_score_threshold=7\n)\n# Internally: Automatically creates DefaultTableExtraction(table_score_threshold=7)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Taking Advantage of New Features",
        "content": "While your old code works, you can now use the strategy pattern for more control:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Option 1: Keep using the old way (perfectly fine!)\nconfig = CrawlerRunConfig(\n    table_score_threshold=7  # Still supported\n)\n\n# Option 2: Use the new strategy pattern (more flexibility)\nfrom…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Summary",
        "content": "- ✅ **No breaking changes** - Old code works as-is\n- ✅ **Same defaults** - DefaultTableExtraction is automatically used\n- ✅ **Gradual adoption** - Use new features when you need them\n- ✅ **Full…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Choose the Right Strategy (Cost-Conscious Approach)",
        "content": "**Decision Flow** :\n\n**Strategy Selection Guide** :\n- **DefaultTableExtraction** : Use for 99% of cases - it's free and effective\n- **LLMTableExtraction** : Only for complex tables with merged cells…",
        "code_blocks": [
          {
            "language": "text",
            "code": "1. Do you need tables? \n   → No: Use NoTableExtraction\n   → Yes: Continue to #2\n\n2. Try DefaultTableExtraction first (FREE)\n   → Works? Done! ✅\n   → Fails? Continue to #3\n\n3. Is the table critical…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Validate Extracted Data",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "def validate_table(table):\n    \"\"\"Validate table data quality.\"\"\"\n    # Check structure\n    if not table.get('rows'):\n        return False\n\n    # Check consistency\n    if table.get('headers'):…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Handle Edge Cases",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "async def robust_table_extraction(url):\n    \"\"\"Extract tables with error handling.\"\"\"\n    async with AsyncWebCrawler() as crawler:\n        try:\n            config = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Troubleshooting",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Common Issues and Solutions",
        "content": "| Issue | Cause | Solution |\n| --- | --- | --- |\n| No tables extracted | Score too high | Lower `table_score_threshold` |\n| Layout tables included | Score too low | Increase `table_score_threshold`…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Debug Logging",
        "content": "Enable verbose logging to understand extraction decisions:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import logging\n\n# Configure logging\nlogging.basicConfig(level=logging.DEBUG)\n\n# Enable verbose mode in strategy\nstrategy = DefaultTableExtraction(\n    table_score_threshold=7,\n    verbose=True  #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "See Also",
        "content": "- [Extraction Strategies](extraction-strategies.md) - Overview of all extraction strategies\n- [Content Selection](../content-selection/) - Using CSS selectors and filters\n- [Performance…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "table extraction",
      "DefaultTableExtraction",
      "LLMTableExtraction",
      "NoTableExtraction",
      "strategy pattern",
      "web scraping",
      "Python",
      "pandas",
      "CSS selector"
    ],
    "prerequisites": [],
    "_content_hash": "2dd4bfebc2729b05a77bd032fa05da5e4b979a68a4f5781b9f01bd9046943692",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/core/url-seeding/",
    "title": "URL Seeding: The Smart Way to Crawl at Scale",
    "type": "guide",
    "summary": "This page explains how to use URL seeding to discover and filter URLs before crawling, covering configuration, smart filtering with BM25 scoring, and scaling across multiple domains.",
    "sections": [
      {
        "heading": "Why URL Seeding?",
        "content": "Web crawling comes in different flavors, each with its own strengths. Let's understand when to use URL seeding versus deep crawling.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Deep Crawling: Real-Time Discovery",
        "content": "Deep crawling is perfect when you need:\n- **Fresh, real-time data** - discovering pages as they're created\n- **Dynamic exploration** - following links based on content\n- **Selective extraction** -…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Deep crawling example: Explore a website dynamically\nimport asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai.deep_crawling import BFSDeepCrawlStrategy\n\nasync def…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "URL Seeding: Bulk Discovery",
        "content": "URL seeding shines when you want:\n- **Comprehensive coverage** - get thousands of URLs in seconds\n- **Bulk processing** - filter before crawling\n- **Resource efficiency** - know exactly what you'll…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# URL seeding example: Analyze all documentation\nfrom crawl4ai import AsyncUrlSeeder, SeedingConfig\n\nseeder = AsyncUrlSeeder()\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "The Trade-offs",
        "content": "| Aspect | Deep Crawling | URL Seeding |\n| --- | --- | --- |\n| **Coverage** | Discovers pages dynamically | Gets most existing URLs instantly |\n| **Freshness** | Finds brand new pages | May miss very…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "When to Use Each",
        "content": "**Choose Deep Crawling when:** \n- You need the absolute latest content\n- You're searching for specific information\n- The site structure is unknown or dynamic\n- You want to stop as soon as you find…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Your First URL Seeding Adventure",
        "content": "Let's see the magic in action. We'll discover blog posts about Python, filter for tutorials, and crawl only those pages.\n\n**What just happened?** \n- We discovered all blog URLs from the sitemap+cc\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncUrlSeeder, AsyncWebCrawler, SeedingConfig, CrawlerRunConfig\n\nasync def smart_blog_crawler():\n    # Step 1: Create our URL discoverer\n    seeder =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Understanding the URL Seeder",
        "content": "Now that you've seen the magic, let's understand how it works.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "Creating a URL seeder is simple:\n\nThe seeder can discover URLs from two powerful sources:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import AsyncUrlSeeder\n\n# Method 1: Manual cleanup\nseeder = AsyncUrlSeeder()\ntry:\n    config = SeedingConfig(source=\"sitemap\")\n    urls = await seeder.urls(\"example.com\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "1. Sitemaps (Fastest)",
        "content": "Sitemaps are XML files that websites create specifically to list all their URLs. It's like getting a menu at a restaurant - everything is listed upfront.\n\n**Sitemap Index Support**: For large…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Discover from sitemap\nconfig = SeedingConfig(source=\"sitemap\")\nurls = await seeder.urls(\"example.com\", config)",
            "filename": ""
          },
          {
            "language": "xml",
            "code": "<!-- Example sitemap index -->\n<sitemapindex>\n  <sitemap>\n    <loc>https://techcrunch.com/sitemap-1.xml</loc>\n  </sitemap>\n  <sitemap>\n    <loc>https://techcrunch.com/sitemap-2.xml</loc>…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Common Crawl (Most Comprehensive)",
        "content": "Common Crawl is a massive public dataset that regularly crawls the entire web. It's like having access to a pre-built index of the internet.",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Discover from Common Crawl\nconfig = SeedingConfig(source=\"cc\")\nurls = await seeder.urls(\"example.com\", config)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Both Sources (Maximum Coverage)",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Use both sources\nconfig = SeedingConfig(source=\"sitemap+cc\")\nurls = await seeder.urls(\"example.com\", config)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Magic: SeedingConfig",
        "content": "The `SeedingConfig` object is your control panel. Here's everything you can configure:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Pattern Matching Examples",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Match all blog posts\nconfig = SeedingConfig(pattern=\"*/blog/*\")\n\n# Match only HTML files\nconfig = SeedingConfig(pattern=\"*.html\")\n\n# Match product pages\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "URL Validation: Live Checking",
        "content": "Sometimes you need to know if URLs are actually accessible. That's where live checking comes in:\n\n**When to use live checking:** \n- Before a large crawling operation\n- When working with older…",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = SeedingConfig(\n    source=\"sitemap\",\n    live_check=True,  # Verify each URL is accessible\n    concurrency=20    # Check 20 URLs in parallel\n)\nasync with AsyncUrlSeeder() as seeder:\n    urls…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "The Power of Metadata: Head Extraction",
        "content": "This is where URL seeding gets really powerful. Instead of crawling entire pages, you can extract just the metadata:",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = SeedingConfig(\n    extract_head=True  # Extract metadata from <head> section\n)\nasync with AsyncUrlSeeder() as seeder:\n    urls = await seeder.urls(\"example.com\", config)\n\n# Now each URL has…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "What Can We Extract?",
        "content": "The head extraction gives you a treasure trove of information:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Example of extracted head_data\n{\n    \"title\": \"10 Python Tips for Beginners\",\n    \"charset\": \"utf-8\",\n    \"lang\": \"en\",\n    \"meta\": {\n        \"description\": \"Learn essential Python tips...\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Smart URL-Based Filtering (No Head Extraction)",
        "content": "When `extract_head=False` but you still provide a query, the seeder uses intelligent URL-based scoring:\n\nThis approach is much faster than head extraction while still providing intelligent filtering!",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Fast filtering based on URL structure alone\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=False,  # Don't fetch page metadata\n    query=\"python tutorial async\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Understanding Results",
        "content": "Each URL in the results has this structure:\n\nLet's see a real example:",
        "code_blocks": [
          {
            "language": "python",
            "code": "{\n    \"url\": \"https://example.com/blog/python-tips.html\",\n    \"status\": \"valid\",        # \"valid\", \"not_valid\", or \"unknown\"\n    \"head_data\": {            # Only if extract_head=True\n        \"title\":…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,\n    live_check=True\n)\nasync with AsyncUrlSeeder() as seeder:\n    urls = await seeder.urls(\"blog.example.com\", config)\n\n# Analyze…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Smart Filtering with BM25 Scoring",
        "content": "Now for the really cool part - intelligent filtering based on relevance!",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Introduction to Relevance Scoring",
        "content": "BM25 is a ranking algorithm that scores how relevant a document is to a search query. With URL seeding, we can score URLs based on their metadata *before* crawling them.\n\nThink of it like this:\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Query-Based Discovery",
        "content": "Here's how to use BM25 scoring:",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,           # Required for scoring\n    query=\"python async tutorial\",  # What we're looking for\n    scoring_method=\"bm25\",       #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Real Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Finding Documentation Pages",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Find API documentation\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,\n    query=\"API reference documentation endpoints\",\n    scoring_method=\"bm25\",\n    score_threshold=0.5,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Discovering Product Pages",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Find specific products\nconfig = SeedingConfig(\n    source=\"sitemap+cc\",  # Use both sources\n    extract_head=True,\n    query=\"wireless headphones noise canceling\",\n    scoring_method=\"bm25\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Filtering News Articles",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Find recent news about AI\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,\n    query=\"artificial intelligence machine learning breakthrough\",\n    scoring_method=\"bm25\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Complex Query Patterns",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Multi-concept queries\nqueries = [\n    \"python async await concurrency tutorial\",\n    \"data science pandas numpy visualization\",\n    \"web scraping beautifulsoup selenium automation\",\n    \"machine…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Scaling Up: Multiple Domains",
        "content": "When you need to discover URLs across multiple websites, URL seeding really shines.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "The `many_urls` Method",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Discover URLs from multiple domains in parallel\ndomains = [\"site1.com\", \"site2.com\", \"site3.com\"]\n\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    extract_head=True,\n    query=\"python tutorial\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Cross-Domain Examples",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Competitor Analysis",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Analyze content strategies across competitors\ncompetitors = [\n    \"competitor1.com\",\n    \"competitor2.com\", \n    \"competitor3.com\"\n]\n\nconfig = SeedingConfig(\n    source=\"sitemap\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Industry Research",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Research Python tutorials across educational sites\neducational_sites = [\n    \"realpython.com\",\n    \"pythontutorial.net\",\n    \"learnpython.org\",\n    \"python.org\"\n]\n\nconfig = SeedingConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Multi-Site Monitoring",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Monitor news about your company across multiple sources\nnews_sites = [\n    \"techcrunch.com\",\n    \"theverge.com\",\n    \"wired.com\",\n    \"arstechnica.com\"\n]\n\ncompany_name = \"YourCompany\"\n\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Integration Patterns",
        "content": "Let's put everything together in a real-world example.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Building a Research Assistant",
        "content": "Here's a complete example that discovers, scores, filters, and crawls intelligently:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom datetime import datetime\nfrom crawl4ai import AsyncUrlSeeder, AsyncWebCrawler, SeedingConfig, CrawlerRunConfig\n\nclass ResearchAssistant:\n    def __init__(self):…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Optimization Tips",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# First run - populate cache\nconfig = SeedingConfig(source=\"sitemap\", extract_head=True, force=True)\nurls = await seeder.urls(\"example.com\", config)\n\n# Subsequent runs - use cache (much…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# For many small requests (like HEAD checks)\nconfig = SeedingConfig(concurrency=50, hits_per_sec=20)\n\n# For fewer large requests (like full head extraction)\nconfig = SeedingConfig(concurrency=10,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# When crawling many URLs\nasync with AsyncWebCrawler() as crawler:\n    # Assuming urls is a list of URL strings\n    crawl_results = await crawler.arun_many(urls, config=config)\n\n    # Process as they…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Safe for domains with 1M+ URLs\nconfig = SeedingConfig(\n    source=\"cc+sitemap\",\n    concurrency=50,  # Queue size adapts to concurrency\n    max_urls=100000  # Process in batches if needed\n)\n\n# The…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices & Tips",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Cache Management",
        "content": "The seeder automatically caches results to speed up repeated operations:",
        "code_blocks": [
          {
            "language": "text",
            "code": "- **Common Crawl cache** : `~/.crawl4ai/seeder_cache/[index]_[domain]_[hash].jsonl`\n- **Sitemap cache** : `~/.crawl4ai/seeder_cache/sitemap_[domain]_[hash].json`\n- **HEAD data cache** :…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Smart TTL Cache for Sitemaps",
        "content": "Sitemap caches now include intelligent validation:\n\n**Cache validation priority:** \n1. `force=True` → Always refetch\n2. Cache doesn't exist → Fetch fresh\n3. `validate_sitemap_lastmod=True` and…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Default: 24-hour TTL with lastmod validation\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    cache_ttl_hours=24,              # Cache expires after 24 hours\n    validate_sitemap_lastmod=True    #…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Pattern Matching Strategies",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Be specific when possible\ngood_pattern = \"*/blog/2024/*.html\"  # Specific\nbad_pattern = \"*\"                     # Too broad\n\n# Combine patterns with metadata filtering\nconfig = SeedingConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Rate Limiting Considerations",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Be respectful of servers\nconfig = SeedingConfig(\n    hits_per_sec=10,      # Max 10 requests per second\n    concurrency=20        # But use 20 workers\n)\n\n# For your own servers\nconfig =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Quick Reference",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Common Patterns",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Blog post discovery\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    pattern=\"*/blog/*\",\n    extract_head=True,\n    query=\"your topic\",\n    scoring_method=\"bm25\"\n)\n\n# E-commerce product…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Troubleshooting Guide",
        "content": "| Issue | Solution |\n| --- | --- |\n| No URLs found | Try `source=\"cc+sitemap\"`, check domain spelling |\n| Slow discovery | Reduce `concurrency`, add `hits_per_sec` limit |\n| Missing metadata | Ensure…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Performance Benchmarks",
        "content": "Typical performance on a standard connection:\n- **Sitemap discovery** : 100-1,000 URLs/second\n- **Common Crawl discovery** : 50-500 URLs/second\n- **HEAD checking** : 10-50 URLs/second\n- **Head…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "URL seeding transforms web crawling from a blind expedition into a surgical strike. By discovering and analyzing URLs before crawling, you can:\n- Save hours of crawling time\n- Reduce bandwidth usage…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Smart URL Filtering",
        "content": "The seeder automatically filters out nonsense URLs that aren't useful for content crawling:\n\nTo disable filtering (not recommended):",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Enabled by default\nconfig = SeedingConfig(\n    source=\"sitemap\",\n    filter_nonsense_urls=True  # Default: True\n)\n\n# URLs that get filtered:\n# - robots.txt, sitemap.xml, ads.txt\n# - API endpoints…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "config = SeedingConfig(\n    source=\"sitemap\",\n    filter_nonsense_urls=False  # Include ALL URLs\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Key Features Summary",
        "content": "- **Parallel Sitemap Index Processing** : Automatically detects and processes sitemap indexes in parallel\n- **Memory Protection** : Bounded queues prevent RAM issues with large domains (1M+ URLs)\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Need More Coverage?",
        "content": "If you need to discover URLs across an entire domain — including subdomains, hidden services, and pages not listed in any sitemap — check out [Domain Mapping](../domain-mapping/). It combines 8…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [
      {
        "name": "source",
        "type": "str",
        "description": "URL source: \"cc\" (Common Crawl), \"sitemap\", or \"sitemap+cc\"",
        "default": "\"sitemap+cc\"",
        "required": false
      },
      {
        "name": "pattern",
        "type": "str",
        "description": "URL pattern filter (e.g., \"*/blog/*\", \"*.html\")",
        "default": "\"*\"",
        "required": false
      },
      {
        "name": "extract_head",
        "type": "bool",
        "description": "Extract metadata from page <head>",
        "default": "False",
        "required": false
      },
      {
        "name": "live_check",
        "type": "bool",
        "description": "Verify URLs are accessible",
        "default": "False",
        "required": false
      },
      {
        "name": "max_urls",
        "type": "int",
        "description": "Maximum URLs to return (-1 = unlimited)",
        "default": "-1",
        "required": false
      },
      {
        "name": "concurrency",
        "type": "int",
        "description": "Parallel workers for fetching",
        "default": "10",
        "required": false
      },
      {
        "name": "hits_per_sec",
        "type": "int",
        "description": "Rate limit for requests",
        "default": "5",
        "required": false
      },
      {
        "name": "force",
        "type": "bool",
        "description": "Bypass cache, fetch fresh data",
        "default": "False",
        "required": false
      },
      {
        "name": "verbose",
        "type": "bool",
        "description": "Show detailed progress",
        "default": "False",
        "required": false
      },
      {
        "name": "query",
        "type": "str",
        "description": "Search query for BM25 scoring",
        "default": "None",
        "required": false
      },
      {
        "name": "scoring_method",
        "type": "str",
        "description": "Scoring method (currently \"bm25\")",
        "default": "None",
        "required": false
      },
      {
        "name": "score_threshold",
        "type": "float",
        "description": "Minimum score to include URL",
        "default": "None",
        "required": false
      },
      {
        "name": "filter_nonsense_urls",
        "type": "bool",
        "description": "Filter out utility URLs (robots.txt, etc.)",
        "default": "True",
        "required": false
      },
      {
        "name": "cache_ttl_hours",
        "type": "int",
        "description": "Hours before sitemap cache expires (0 = no TTL)",
        "default": "24",
        "required": false
      },
      {
        "name": "validate_sitemap_lastmod",
        "type": "bool",
        "description": "Check sitemap's lastmod and refetch if newer",
        "default": "True",
        "required": false
      }
    ],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "URL Seeding",
      "Web Crawling",
      "Sitemap",
      "Common Crawl",
      "BM25",
      "AsyncUrlSeeder",
      "SeedingConfig"
    ],
    "prerequisites": [],
    "_content_hash": "df9e190910d1567492524d646b12f7522b5f88a49c0e1365872b307a97c5fded",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/extraction/chunking/",
    "title": "Chunking Strategies",
    "type": "guide",
    "summary": "This page explains various chunking strategies for dividing large texts into manageable parts, including regex-based, sentence-based, topic-based, fixed-length word, and sliding window chunking, as…",
    "sections": [
      {
        "heading": "Chunking Strategies",
        "content": "Chunking strategies are critical for dividing large texts into manageable parts, enabling effective content processing and extraction. These strategies are foundational in cosine similarity-based…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Why Use Chunking?",
        "content": "1. **Cosine Similarity and Query Relevance**: Prepares chunks for semantic similarity analysis.\n2. **RAG System Integration**: Seamlessly processes and stores chunks for retrieval.\n3. **Structured…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Methods of Chunking",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Regex-Based Chunking",
        "content": "Splits text based on regular expression patterns, useful for coarse segmentation.\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "class RegexChunking:\n    def __init__(self, patterns=None):\n        self.patterns = patterns or [r'\\n\\n']  # Default pattern for paragraphs\n\n    def chunk(self, text):\n        paragraphs = [text]…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Sentence-Based Chunking",
        "content": "Divides text into sentences using NLP tools, ideal for extracting meaningful statements.\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from nltk.tokenize import sent_tokenize\n\nclass NlpSentenceChunking:\n    def chunk(self, text):\n        sentences = sent_tokenize(text)\n        return [sentence.strip() for sentence in sentences]\n\n#…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Topic-Based Segmentation",
        "content": "Uses algorithms like TextTiling to create topic-coherent chunks.\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from nltk.tokenize import TextTilingTokenizer\n\nclass TopicSegmentationChunking:\n    def __init__(self):\n        self.tokenizer = TextTilingTokenizer()\n\n    def chunk(self, text):\n        return…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. Fixed-Length Word Chunking",
        "content": "Segments text into chunks of a fixed word count.\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "class FixedLengthWordChunking:\n    def __init__(self, chunk_size=100):\n        self.chunk_size = chunk_size\n\n    def chunk(self, text):\n        words = text.split()\n        return [' '.join(words[i:i…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Sliding Window Chunking",
        "content": "Generates overlapping chunks for better contextual coherence.\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "class SlidingWindowChunking:\n    def __init__(self, window_size=100, step=50):\n        self.window_size = window_size\n        self.step = step\n\n    def chunk(self, text):\n        words =…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Combining Chunking with Cosine Similarity",
        "content": "To enhance the relevance of extracted content, chunking strategies can be paired with cosine similarity techniques. Here’s an example workflow:\n\n**Code Example**:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from sklearn.feature_extraction.text import TfidfVectorizer\nfrom sklearn.metrics.pairwise import cosine_similarity\n\nclass CosineSimilarityExtractor:\n    def __init__(self, query):\n        self.query…",
            "filename": ""
          }
        ],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "chunking",
      "text segmentation",
      "regex",
      "NLP",
      "sentence tokenization",
      "TextTiling",
      "sliding window",
      "cosine similarity",
      "RAG",
      "Crawl4AI"
    ],
    "prerequisites": [],
    "_content_hash": "26e3b8e253315946559f425e3db2345c720fd92714b3691f3d782e8bcb791070",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/extraction/clustring-strategies/",
    "title": "Clustering Strategies - Crawl4AI Documentation (v0.9.x)",
    "type": "guide",
    "summary": "This page provides a comprehensive guide to using the Cosine Strategy in Crawl4AI for semantic content extraction, covering configuration options, usage examples, best practices, and error handling.",
    "sections": [
      {
        "heading": "Cosine Strategy",
        "content": "The Cosine Strategy in Crawl4AI uses similarity-based clustering to identify and extract relevant content sections from web pages. This strategy is particularly useful when you need to find and…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "How It Works",
        "content": "The Cosine Strategy:\n1. Breaks down page content into meaningful chunks\n2. Converts text into vector representations\n3. Calculates similarity between chunks\n4. Clusters similar content together\n5.…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Basic Usage",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import CosineStrategy\n\nstrategy = CosineStrategy(\n    semantic_filter=\"product reviews\",    # Target content type\n    word_count_threshold=10,             # Minimum words per cluster…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Configuration Options",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Core Parameters",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "CosineStrategy(\n    # Content Filtering\n    semantic_filter: str = None,       # Keywords/topic for content filtering\n    word_count_threshold: int = 10,    # Minimum words per cluster…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Parameter Details",
        "content": "1. **semantic_filter** \n   - Sets the target topic or content type\n   - Use keywords relevant to your desired content\n   - Example: \"technical specifications\", \"user reviews\", \"pricing…",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Strict matching\nstrategy = CosineStrategy(sim_threshold=0.8)\n\n# Loose matching\nstrategy = CosineStrategy(sim_threshold=0.3)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Only consider substantial paragraphs\nstrategy = CosineStrategy(word_count_threshold=50)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Get top 5 most relevant content clusters\nstrategy = CosineStrategy(top_k=5)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Use Cases",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Article Content Extraction",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    semantic_filter=\"main article content\",\n    word_count_threshold=100,  # Longer blocks for articles\n    top_k=1                   # Usually want single main…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Product Review Analysis",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    semantic_filter=\"customer reviews and ratings\",\n    word_count_threshold=20,   # Reviews can be shorter\n    top_k=10,                 # Get multiple reviews…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Technical Documentation",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    semantic_filter=\"technical specifications documentation\",\n    word_count_threshold=30,\n    sim_threshold=0.6,        # Stricter matching for technical content…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Advanced Features",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Custom Clustering",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    linkage_method='complete',  # Alternative clustering method\n    max_dist=0.4,              # Larger clusters…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Content Filtering Pipeline",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    semantic_filter=\"pricing plans features\",\n    word_count_threshold=15,\n    sim_threshold=0.5,\n    top_k=3\n)\n\nasync def extract_pricing_features(url: str):\n    async…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Best Practices",
        "content": "1. **Adjust Thresholds Iteratively** \n   - Start with default values\n   - Adjust based on results\n   - Monitor clustering quality\n\n2. **Choose Appropriate Word Count Thresholds** \n   - Higher for…",
        "code_blocks": [
          {
            "language": "python",
            "code": "strategy = CosineStrategy(\n    word_count_threshold=10,  # Filter early\n    top_k=5,                 # Limit results\n    verbose=True             # Monitor performance\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# For mixed content pages\nstrategy = CosineStrategy(\n    semantic_filter=\"product features\",\n    sim_threshold=0.4,      # More flexible matching\n    max_dist=0.3,          # Larger clusters…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Error Handling",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "try:\n    result = await crawler.arun(\n        url=\"https://example.com\",\n        extraction_strategy=strategy\n    )\n\n    if result.success:\n        content = json.loads(result.extracted_content)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Conclusion",
        "content": "The Cosine Strategy is particularly effective when:\n- Content structure is inconsistent\n- You need semantic understanding\n- You want to find similar content blocks\n- Structure-based extraction…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "Cosine Strategy",
      "clustering",
      "semantic extraction",
      "content extraction",
      "Python"
    ],
    "prerequisites": [],
    "_content_hash": "89ea3741cdf040bf54268545c4344c2375554b5dba89b99d625bc7ff3203b414",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/extraction/llm-strategies/",
    "title": "Extracting JSON (LLM)",
    "type": "guide",
    "summary": "A guide to using Crawl4AI's LLM-based extraction strategy to extract structured JSON from web pages using any LLM via LiteLLM, including schema definition, chunking, input formats, and practical…",
    "sections": [
      {
        "heading": "Overview",
        "content": "In some cases, you need to extract **complex or unstructured** information from a webpage that a simple CSS/XPath schema cannot easily parse. Or you want **AI**-driven insights, classification, or…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Why Use an LLM?",
        "content": "- **Complex Reasoning**: If the site’s data is unstructured, scattered, or full of natural language context.\n- **Semantic Extraction**: Summaries, knowledge graphs, or relational data that require…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. Provider-Agnostic via LiteLLM",
        "content": "You can use LLMConfig, to quickly configure multiple variations of LLMs and experiment with them to find the optimal one for your use case. You can read more about LLMConfig…",
        "code_blocks": [
          {
            "language": "python",
            "code": "llm_config = LLMConfig(provider=\"openai/gpt-4o-mini\", api_token=os.getenv(\"OPENAI_API_KEY\"))",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. How LLM Extraction Works",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.1 Flow",
        "content": "1. **Chunking** (optional): The HTML or markdown is split into smaller segments if it’s very long (based on `chunk_token_threshold`, overlap, etc.).\n2. **Prompt Construction**: For each chunk, the…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "3.2 `extraction_type`",
        "content": "- **`\"schema\"`**: The model tries to return JSON conforming to your Pydantic-based schema.\n- **`\"block\"`**: The model returns freeform text, or smaller JSON structures, which the library…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "4. Key Parameters",
        "content": "Below is an overview of important LLM extraction parameters. All are typically set inside `LLMExtractionStrategy(...)`. You then put that strategy in your `CrawlerRunConfig(...,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "extraction_strategy = LLMExtractionStrategy(\n    llm_config = LLMConfig(provider=\"openai/gpt-4\", api_token=\"YOUR_OPENAI_KEY\"),\n    schema=MyModel.model_json_schema(),\n    extraction_type=\"schema\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Putting It in `CrawlerRunConfig`",
        "content": "**Important**: In Crawl4AI, all strategy definitions should go inside the `CrawlerRunConfig`, not directly as a param in `arun()`. Here’s a full example:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import os\nimport asyncio\nimport json\nfrom pydantic import BaseModel, Field\nfrom typing import List\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode, LLMConfig\nfrom…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "6. Chunking Details",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6.1 `chunk_token_threshold`",
        "content": "If your page is large, you might exceed your LLM’s context window. **`chunk_token_threshold`** sets the approximate max tokens per chunk. The library calculates word→token ratio using…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6.2 `overlap_rate`",
        "content": "To keep context continuous across chunks, we can overlap them. E.g., `overlap_rate=0.1` means each subsequent chunk includes 10% of the previous chunk’s text. This is helpful if your needed info…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6.3 Performance & Parallelism",
        "content": "By chunking, you can potentially process multiple chunks in parallel (depending on your concurrency settings and the LLM provider). This reduces total time if the site is huge or has many sections.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "7. Input Format",
        "content": "By default, **LLMExtractionStrategy** uses `input_format=\"markdown\"`, meaning the **crawler’s final markdown** is fed to the LLM. You can change to:\n\n- **`html`**: The cleaned HTML or raw HTML…",
        "code_blocks": [
          {
            "language": "python",
            "code": "LLMExtractionStrategy(\n    # ...\n    input_format=\"html\",  # Instead of \"markdown\" or \"fit_markdown\"\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Token Usage & Show Usage",
        "content": "To keep track of tokens and cost, each chunk is processed with an LLM call. We record usage in:\n\n- **`usages`** (list): token usage per chunk or call.\n- **`total_usage`**: sum of all chunk calls.\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "llm_strategy = LLMExtractionStrategy(...)\n# ...\nllm_strategy.show_usage()\n# e.g. “Total usage: 1241 tokens across 2 chunk calls”",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "9. Example: Building a Knowledge Graph",
        "content": "Below is a snippet combining **`LLMExtractionStrategy`** with a Pydantic schema for a knowledge graph. Notice how we pass an **`instruction`** telling the model what to parse.\n\n**Key…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import os\nimport json\nimport asyncio\nfrom typing import List\nfrom pydantic import BaseModel, Field\nfrom crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode, LLMConfig\nfrom…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "10. Best Practices & Caveats",
        "content": "1. **Cost & Latency**: LLM calls can be slow or expensive. Consider chunking or smaller coverage if you only need partial data.\n2. **Model Token Limits**: If your page + instruction exceed the…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "11. Conclusion",
        "content": "**LLM-based extraction** in Crawl4AI is **provider-agnostic**, letting you choose from hundreds of models via LiteLLM. It’s perfect for **semantically complex** tasks or generating advanced…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "LLM",
      "LiteLLM",
      "extraction",
      "JSON",
      "Pydantic",
      "chunking",
      "knowledge graph"
    ],
    "prerequisites": [],
    "_content_hash": "9b1b96f58e30ca8610cb729eeffde1740c47211062d96b208e8e3cf8d661497d",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/extraction/no-llm-strategies/",
    "title": "Extracting JSON (No LLM)",
    "type": "guide",
    "summary": "This page covers Crawl4AI's LLM-free extraction strategies, including schema-based extraction with CSS/XPath selectors (JsonCssExtractionStrategy, JsonXPathExtractionStrategy) and regex-based…",
    "sections": [
      {
        "heading": "1. Intro to Schema-Based Extraction",
        "content": "A schema defines:\n\n- A **base selector** that identifies each \"container\" element on the page (e.g., a product row, a blog post card).\n- **Fields** describing which CSS/XPath selectors to use for…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "2. Simple Example: Crypto Prices",
        "content": "Let's begin with a **simple** schema-based extraction using the `JsonCssExtractionStrategy`. Below is a snippet that extracts cryptocurrency prices from a site (similar to the legacy Coinbase…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode\nfrom crawl4ai import JsonCssExtractionStrategy\n\nasync def extract_crypto_prices():\n    # 1. Define a…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai import JsonXPathExtractionStrategy\n\nasync def extract_crypto_prices_xpath():\n    # 1. Minimal dummy…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Advanced Schema & Nested Structures",
        "content": "Real sites often have **nested** or repeated data—like categories containing products, which themselves have a list of reviews or features. For that, we can define **nested** or **list** (and even…",
        "code_blocks": [
          {
            "language": "python",
            "code": "schema = {\n    \"name\": \"E-commerce Product Catalog\",\n    \"baseSelector\": \"div.category\",\n    # (1) We can define optional baseFields if we want to extract attributes \n    # from the category…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\nfrom crawl4ai import JsonCssExtractionStrategy\n\necommerce_schema = {\n    # ... the advanced schema from above…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "4. RegexExtractionStrategy - Fast Pattern-Based Extraction",
        "content": "Crawl4AI now offers a powerful new zero-LLM extraction strategy: `RegexExtractionStrategy`. This strategy provides lightning-fast extraction of common data types like emails, phone numbers, URLs,…",
        "code_blocks": [
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom crawl4ai import (\n    AsyncWebCrawler,\n    CrawlerRunConfig,\n    RegexExtractionStrategy\n)\n\nasync def extract_with_regex():\n    # Create a strategy using built-in…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Use individual patterns\nstrategy = RegexExtractionStrategy(pattern=RegexExtractionStrategy.Email)\n\n# Combine multiple patterns\nstrategy = RegexExtractionStrategy(\n    pattern = (…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom crawl4ai import (\n    AsyncWebCrawler,\n    CrawlerRunConfig,\n    RegexExtractionStrategy\n)\n\nasync def extract_prices():\n    # Define a custom pattern for US Dollar…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "import json\nimport asyncio\nfrom pathlib import Path\nfrom crawl4ai import (\n    AsyncWebCrawler,\n    CrawlerRunConfig,\n    RegexExtractionStrategy,\n    LLMConfig\n)\n\nasync def…",
            "filename": ""
          },
          {
            "language": "json",
            "code": "[\n  {\n    \"url\": \"https://example.com\",\n    \"label\": \"email\",\n    \"value\": \"contact@example.com\",\n    \"span\": [145, 163]\n  },\n  {\n    \"url\": \"https://example.com\",\n    \"label\": \"url\",\n    \"value\":…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "5. Why \"No LLM\" Is Often Better",
        "content": "- **Zero Hallucination**: Pattern-based extraction doesn't guess text. It either finds it or not.\n- **Guaranteed Structure**: The same schema or regex yields consistent JSON across many pages, so…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "6. Base Element Attributes & Additional Fields",
        "content": "It's easy to **extract attributes** (like `href`, `src`, or `data-xxx`) from your base or nested elements using:\n\n```json\n{\n  \"name\": \"href\",\n  \"type\": \"attribute\",\n  \"attribute\": \"href\",…",
        "code_blocks": [
          {
            "language": "json",
            "code": "{\n  \"name\": \"href\",\n  \"type\": \"attribute\",\n  \"attribute\": \"href\",\n  \"default\": null\n}",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "7. Putting It All Together: Larger Example",
        "content": "Consider a blog site. We have a schema that extracts the **URL** from each post card (via `baseFields` with an `\"attribute\": \"href\"`), plus the title, date, summary, and author:\n\n```json\nschema = {…",
        "code_blocks": [
          {
            "language": "json",
            "code": "schema = {\n  \"name\": \"Blog Posts\",\n  \"baseSelector\": \"a.blog-post-card\",\n  \"baseFields\": [\n    {\"name\": \"post_url\", \"type\": \"attribute\", \"attribute\": \"href\"}\n  ],\n  \"fields\": [\n    {\"name\": \"title\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "8. Extracting Sibling Data with `source`",
        "content": "Some websites split a single logical item across **sibling elements** rather than nesting everything inside one container. A classic example is Hacker News, where each submission spans two adjacent…",
        "code_blocks": [
          {
            "language": "html",
            "code": "<tr class=\"athing submission\">  <!-- rank, title, url -->\n  <td><span class=\"rank\">1.</span></td>\n  <td><span class=\"titleline\"><a href=\"https://example.com\">Example Title</a></span></td>\n</tr>\n<tr>…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "schema = {\n    \"name\": \"HN Submissions\",\n    \"baseSelector\": \"tr.athing.submission\",\n    \"fields\": [\n        {\"name\": \"rank\", \"selector\": \"span.rank\", \"type\": \"text\"},\n        {\"name\": \"title\",…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "9. Tips & Best Practices",
        "content": "- **Inspect the DOM** in Chrome DevTools or Firefox's Inspector to find stable selectors.\n- **Start Simple**: Verify you can extract a single field. Then add complexity like nested objects or…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "10. Schema Generation Utility",
        "content": "While manually crafting schemas is powerful and precise, Crawl4AI now offers a convenient utility to **automatically generate** extraction schemas using LLM. This is particularly useful when:\n\n-…",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy, JsonXPathExtractionStrategy\nfrom crawl4ai import LLMConfig\n\n# Sample HTML with product information\nhtml = \"\"\"\n<div class=\"product-card\">\n    <h2…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Default: validated (recommended)\nschema = JsonCssExtractionStrategy.generate_schema(\n    url=\"https://news.ycombinator.com\",\n    query=\"Extract each story: title, url, score, author\",\n)\n\n# Skip…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy\nfrom crawl4ai.models import TokenUsage\n\nusage = TokenUsage()\n\nschema = JsonCssExtractionStrategy.generate_schema(…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "usage = TokenUsage()\nschema1 = JsonCssExtractionStrategy.generate_schema(url=url1, query=q1, usage=usage)\nschema2 = JsonCssExtractionStrategy.generate_schema(url=url2, query=q2,…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "from crawl4ai import JsonCssExtractionStrategy, LLMConfig\n\n# Collect HTML samples from different pages\nhtml_sample_1 = \"\"\"\n<table class=\"specs\">\n  <tr><td>Brand</td><td>Apple</td></tr>…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "11. Conclusion",
        "content": "With Crawl4AI's LLM-free extraction strategies - `JsonCssExtractionStrategy`, `JsonXPathExtractionStrategy`, and now `RegexExtractionStrategy` - you can build powerful pipelines that:\n\n- Scrape any…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "JSON extraction",
      "CSS selectors",
      "XPath",
      "Regex",
      "Schema-based extraction",
      "No LLM",
      "JsonCssExtractionStrategy",
      "JsonXPathExtractionStrategy",
      "RegexExtractionStrategy",
      "Web scraping",
      "Structured data"
    ],
    "prerequisites": [],
    "_content_hash": "3c37970cb48d6a07d5da3e125a43a6b84f1240534e4e8cd9efd98a2e9cc38b28",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/migration/table_extraction_v073/",
    "title": "Migration Guide: Table Extraction v0.7.3",
    "type": "guide",
    "summary": "A migration guide for Crawl4AI v0.7.3 introducing the Table Extraction Strategy Pattern, highlighting new classes and options, full backward compatibility, migration scenarios, code organization…",
    "sections": [
      {
        "heading": "Overview",
        "content": "Version 0.7.3 introduces the **Table Extraction Strategy Pattern** , providing a more flexible and extensible approach to table extraction while maintaining full backward compatibility.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What's New",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Strategy Pattern Implementation",
        "content": "Table extraction now follows the same strategy pattern used throughout Crawl4AI:\n\n- **Consistent Architecture** : Aligns with extraction, chunking, and markdown strategies\n- **Extensibility** : Easy…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "New Classes",
        "content": "",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import (\n    TableExtractionStrategy,    # Abstract base class\n    DefaultTableExtraction,      # Current implementation (default)\n    NoTableExtraction           # Explicitly disable…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Backward Compatibility",
        "content": "**✅ All existing code continues to work without changes.**",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "No Changes Required",
        "content": "If your code looks like this, it will continue to work:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# This still works exactly the same\nconfig = CrawlerRunConfig(\n    table_score_threshold=7\n)\nresult = await crawler.arun(url, config)\ntables = result.tables  # Same structure, same data",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "What Happens Behind the Scenes",
        "content": "When you don't specify a `table_extraction` strategy:\n\n- `CrawlerRunConfig` automatically creates `DefaultTableExtraction`\n- It uses your `table_score_threshold` parameter\n- Tables are extracted…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "New Capabilities",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "1. Explicit Strategy Configuration",
        "content": "You can now explicitly configure table extraction:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# New: Explicit control\nstrategy = DefaultTableExtraction(\n    table_score_threshold=7,\n    min_rows=2,              # New: minimum row filter\n    min_cols=2,              # New: minimum column…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "2. Disable Table Extraction",
        "content": "Improve performance when tables aren't needed:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# New: Skip table extraction entirely\nconfig = CrawlerRunConfig(\n    table_extraction=NoTableExtraction()\n)\n# No CPU cycles spent on table detection/extraction",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "3. Custom Extraction Strategies",
        "content": "Create specialized extractors:",
        "code_blocks": [
          {
            "language": "python",
            "code": "class MyTableExtractor(TableExtractionStrategy):\n    def extract_tables(self, element, **kwargs):\n        # Custom extraction logic\n        return custom_tables\n\nconfig = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Migration Scenarios",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Scenario 1: Basic Usage (No Changes Needed)",
        "content": "**Before (v0.7.2):**\n\n**After (v0.7.3):**",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig()\nresult = await crawler.arun(url, config)\nfor table in result.tables:\n    print(table['headers'])",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Exactly the same - no changes required\nconfig = CrawlerRunConfig()\nresult = await crawler.arun(url, config)\nfor table in result.tables:\n    print(table['headers'])",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Scenario 2: Custom Threshold (No Changes Needed)",
        "content": "**Before (v0.7.2):**\n\n**After (v0.7.3):**",
        "code_blocks": [
          {
            "language": "python",
            "code": "config = CrawlerRunConfig(\n    table_score_threshold=5\n)",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Still works the same\nconfig = CrawlerRunConfig(\n    table_score_threshold=5\n)\n\n# Or use new explicit approach for more control\nstrategy = DefaultTableExtraction(\n    table_score_threshold=5,…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Scenario 3: Advanced Filtering (New Feature)",
        "content": "**Before (v0.7.2):**\n\n**After (v0.7.3):**",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Had to filter after extraction\nconfig = CrawlerRunConfig(\n    table_score_threshold=5\n)\nresult = await crawler.arun(url, config)\n\n# Manual filtering\nlarge_tables = [\n    t for t in result.tables…",
            "filename": ""
          },
          {
            "language": "python",
            "code": "# Filter during extraction (more efficient)\nstrategy = DefaultTableExtraction(\n    table_score_threshold=5,\n    min_rows=5,\n    min_cols=3\n)\nconfig = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Code Organization Changes",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Module Structure",
        "content": "**Before (v0.7.2):**\n\n**After (v0.7.3):**",
        "code_blocks": [
          {
            "language": "text",
            "code": "crawl4ai/\n  content_scraping_strategy.py\n    - LXMLWebScrapingStrategy\n      - is_data_table()      # Table detection\n      - extract_table_data() # Table extraction",
            "filename": ""
          },
          {
            "language": "text",
            "code": "crawl4ai/\n  content_scraping_strategy.py\n    - LXMLWebScrapingStrategy\n      # Table methods removed, uses strategy\n\n  table_extraction.py (NEW)\n    - TableExtractionStrategy    # Base class\n    -…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Import Changes",
        "content": "**New imports available (optional):**",
        "code_blocks": [
          {
            "language": "python",
            "code": "# These are now available but not required for existing code\nfrom crawl4ai import (\n    TableExtractionStrategy,\n    DefaultTableExtraction,\n    NoTableExtraction\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Implications",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "No Performance Impact",
        "content": "For existing code, performance remains identical:\n- Same extraction logic\n- Same scoring algorithm\n- Same processing time",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Performance Improvements Available",
        "content": "New options for better performance:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Skip tables entirely (faster)\nconfig = CrawlerRunConfig(\n    table_extraction=NoTableExtraction()\n)\n\n# Process only specific areas (faster)\nconfig = CrawlerRunConfig(…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Testing Your Migration",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Verification Script",
        "content": "Run this to verify your extraction still works:",
        "code_blocks": [
          {
            "language": "python",
            "code": "import asyncio\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig\n\nasync def verify_extraction():\n    url = \"your_url_here\"\n\n    async with AsyncWebCrawler() as crawler:\n        # Test 1: Old…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Deprecation Notes",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "No Deprecations",
        "content": "- All existing parameters continue to work\n- `table_score_threshold` in `CrawlerRunConfig` is still supported\n- No breaking changes",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Internal Changes (Transparent to Users)",
        "content": "- `LXMLWebScrapingStrategy.is_data_table()` - Moved to `DefaultTableExtraction`\n- `LXMLWebScrapingStrategy.extract_table_data()` - Moved to `DefaultTableExtraction`\n\nThese methods were internal and…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Benefits of Upgrading",
        "content": "While not required, using the new pattern provides:\n\n- **Better Control** : Filter tables during extraction, not after\n- **Performance Options** : Skip extraction when not needed\n- **Extensibility**…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Troubleshooting",
        "content": "",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Issue: Different Number of Tables",
        "content": "**Cause** : Threshold or filtering differences\n\n**Solution** :",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Ensure same threshold\nstrategy = DefaultTableExtraction(\n    table_score_threshold=7,  # Match your old setting\n    min_rows=0,               # No filtering (default)\n    min_cols=0…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Issue: Import Errors",
        "content": "**Cause** : Using new classes without importing\n\n**Solution** :",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Add imports if using new features\nfrom crawl4ai import (\n    DefaultTableExtraction,\n    NoTableExtraction,\n    TableExtractionStrategy\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Issue: Custom Strategy Not Working",
        "content": "**Cause** : Incorrect method signature\n\n**Solution** :",
        "code_blocks": [
          {
            "language": "python",
            "code": "class CustomExtractor(TableExtractionStrategy):\n    def extract_tables(self, element, **kwargs):  # Correct signature\n        # Not: extract_tables(self, html)\n        # Not: extract(self, element)…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Getting Help",
        "content": "If you encounter issues:\n\n- Check your `table_score_threshold` matches previous settings\n- Verify imports if using new classes\n- Enable verbose logging: `DefaultTableExtraction(verbose=True)`\n-…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Summary",
        "content": "- ✅  **Full backward compatibility**  - No code changes required\n- ✅  **Same results**  - Identical extraction behavior by default\n- ✅  **New options**  - Additional control when needed\n- ✅  **Better…",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "table extraction",
      "strategy pattern",
      "migration",
      "v0.7.3",
      "Python",
      "web scraping"
    ],
    "prerequisites": [],
    "_content_hash": "66b14db55568c3051caeaaa55dbabe18f2de5e9da52e0ade2d67424d0085fd55",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  },
  {
    "url": "https://docs.crawl4ai.com/migration/webscraping-strategy-migration/",
    "title": "WebScrapingStrategy Migration Guide",
    "type": "guide",
    "summary": "This guide explains the deprecation of BeautifulSoup-based WebScrapingStrategy in favor of LXMLWebScrapingStrategy, and confirms backward compatibility with no required changes.",
    "sections": [
      {
        "heading": "Overview",
        "content": "Crawl4AI has simplified its content scraping architecture. The BeautifulSoup-based `WebScrapingStrategy` has been deprecated in favor of the faster LXML-based implementation. However, **no action is…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "What Changed?",
        "content": "- **`WebScrapingStrategy` is now an alias** for `LXMLWebScrapingStrategy`\n- **The BeautifulSoup implementation has been removed** (~1000 lines of redundant code)\n- **`LXMLWebScrapingStrategy`…",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Backward Compatibility",
        "content": "**Your existing code continues to work without any changes:**",
        "code_blocks": [
          {
            "language": "python",
            "code": "# This still works perfectly\nfrom crawl4ai import AsyncWebCrawler, CrawlerRunConfig, WebScrapingStrategy\n\nconfig = CrawlerRunConfig(\n    scraping_strategy=WebScrapingStrategy()  # Works as before\n)",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Migration Options",
        "content": "You have three options:",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Option 1: Do Nothing (Recommended)",
        "content": "Your code will continue to work. `WebScrapingStrategy` is permanently aliased to `LXMLWebScrapingStrategy`.",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Option 2: Update Imports (Optional)",
        "content": "For clarity, you can update your imports:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Old (still works)\nfrom crawl4ai import WebScrapingStrategy\nstrategy = WebScrapingStrategy()\n\n# New (more explicit)\nfrom crawl4ai import LXMLWebScrapingStrategy\nstrategy = LXMLWebScrapingStrategy()",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Option 3: Use Default Configuration",
        "content": "Since `LXMLWebScrapingStrategy` is the default, you can omit the strategy parameter:",
        "code_blocks": [
          {
            "language": "python",
            "code": "# Simplest approach - uses LXMLWebScrapingStrategy by default\nconfig = CrawlerRunConfig()",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Type Hints",
        "content": "If you use type hints, both work:",
        "code_blocks": [
          {
            "language": "python",
            "code": "from crawl4ai import WebScrapingStrategy, LXMLWebScrapingStrategy\n\ndef process_with_strategy(strategy: WebScrapingStrategy) -> None:\n    # Works with both WebScrapingStrategy and…",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Subclassing",
        "content": "If you've subclassed `WebScrapingStrategy`, it continues to work:",
        "code_blocks": [
          {
            "language": "python",
            "code": "class MyCustomStrategy(WebScrapingStrategy):\n    def __init__(self):\n        super().__init__()\n        # Your custom code",
            "filename": ""
          }
        ],
        "images": []
      },
      {
        "heading": "Performance Benefits",
        "content": "- **10-20x faster** HTML parsing for large documents\n- **Lower memory usage**\n- **Consistent behavior** across all use cases\n- **Simplified maintenance** and bug fixes",
        "code_blocks": [],
        "images": []
      },
      {
        "heading": "Summary",
        "content": "This change simplifies Crawl4AI's internals while maintaining 100% backward compatibility. Your existing code continues to work, and you get better performance automatically.",
        "code_blocks": [],
        "images": []
      }
    ],
    "parameters": [],
    "see_also": [],
    "tags": [
      "Crawl4AI",
      "WebScrapingStrategy",
      "LXML",
      "migration",
      "backward compatibility",
      "scraping"
    ],
    "prerequisites": [],
    "_content_hash": "006a246ae90b5f8eee5416b23c1d26f7a7ad07b8a0c6934ec34276e6e3491ee0",
    "error": "",
    "finish_reason": "",
    "_canonical": true
  }
]