Reading the CrawlResult

A CrawlResult carries more than markdown. Here is how to read each field and which representation to use for which job.

html cleaned_html markdown media links metadata error_message
01/concept

Concept

CrawlResult is a Pydantic model that bundles the final URL, success flag, HTTP status, raw HTML, cleaned HTML, a markdown result object, media, links, metadata, and captured network or console data. Treat it as the single source of truth for what happened during the crawl.

The markdown field is itself a MarkdownGenerationResult. It exposes raw_markdown, markdown_with_citations, references_markdown, fit_markdown, and fit_html. The fit_* variants only appear when a content filter or extraction strategy produced them. media and links are dictionaries; use .get() with a fallback to avoid KeyError.

02/use-cases

Use cases

  • Feed cleaned markdown into an LLM pipeline without navigation chrome.
  • Extract all internal links for a site map.
  • Save page screenshots and PDFs from the same result object.
03/watch

Video walkthrough

Official Crawl4AI tutorialyoutube · loads on click
04/run

Code example

python Inspect a CrawlResult
import asyncio
import json
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig

async def main():
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://example.com",
            config=CrawlerRunConfig(),
        )

        if not result.success:
            print("Crawl failed:", result.error_message)
            return

        print("URL:", result.url)
        print("Status:", result.status_code)
        print("Title:", result.metadata.get("title"))
        print("HTML length:", len(result.html))
        print("Cleaned HTML length:", len(result.cleaned_html or ""))

        if result.markdown:
            print("Raw markdown length:", len(result.markdown.raw_markdown))
            if result.markdown.fit_markdown:
                print("Fit markdown length:", len(result.markdown.fit_markdown))

        images = result.media.get("images", [])
        print("Images found:", len(images))

        internal = result.links.get("internal", [])
        print("Internal links:", len(internal))

asyncio.run(main())
05/build

Practice lab

Lab 1.3

Practice lab

0/3

Objective: Crawl a page and print a structured summary of its CrawlResult fields.

Steps

  1. Crawl any allowed public page with a default CrawlerRunConfig.
  2. If result.success is true, print the URL, status code, and page title.
  3. Print the lengths of html, cleaned_html, and raw_markdown.
  4. Print the counts of images, internal links, and external links.

Success criteria

Expected output
A short report with URL, status, title, content lengths, image count, and link counts.
Hints
  • Use result.metadata.get('title') for the page title.
  • External links live in result.links.get('external', []).
Solution
python Complete solution
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig

async def main():
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://example.com",
            config=CrawlerRunConfig(),
        )
        if not result.success:
            print("Failed:", result.error_message)
            return

        md = result.markdown
        print(f"URL: {result.url}")
        print(f"Status: {result.status_code}")
        print(f"Title: {result.metadata.get('title')}")
        print(f"HTML: {len(result.html)} chars")
        print(f"Cleaned HTML: {len(result.cleaned_html or '')} chars")
        print(f"Raw markdown: {len(md.raw_markdown)} chars")
        print(f"Images: {len(result.media.get('images', []))}")
        print(f"Internal links: {len(result.links.get('internal', []))}")
        print(f"External links: {len(result.links.get('external', []))}")

asyncio.run(main())
06/check

Common mistakes

TRAP 01
Accessing markdown through removed top-level fields instead of result.markdown.
TRAP 02
Assuming result.markdown is a plain string; it is a result object.
TRAP 03
Accessing result.links['internal'] without a fallback, which raises KeyError if the key is absent.