prowl4ai is a lightweight Go web crawler inspired by crawl4ai.
It fetches fully rendered HTML with Playwright, runs readability-style cleaning, converts content to Markdown, and returns structured crawl results.
- Playwright-backed page rendering (JavaScript-enabled sites)
- Configurable crawl timeout and headless mode
- Readability-based clean HTML extraction
- Markdown conversion from cleaned HTML
- JSON or Markdown CLI output
- Crawl metadata (title, byline, excerpt, language)
- Response metadata (status code, headers, redirected URL)
This is an early-stage project with a single CLI command: crawl.
See the roadmap for planned features and development progress.
Current CLI flags intentionally expose a minimal surface area:
--timeout(page timeout in milliseconds)--headless(run browser headless or headed)--output(jsonormarkdown)
Additional crawler options exist in internal config types and can be exposed as the CLI evolves.
- Go
1.25+ - Playwright runtime + browser binaries
- Clone and enter the repo:
git clone <your-fork-or-repo-url>
cd prowl4ai- Install Go dependencies:
go mod download- Install Playwright browser binaries (Chromium):
go run github.com/playwright-community/playwright-go/cmd/playwright@latest install chromiumRun a crawl and return JSON:
go run ./cmd/prowl4ai crawl https://example.comRun with custom timeout and headed browser:
go run ./cmd/prowl4ai crawl --timeout 90000 --headless=false https://example.comReturn Markdown only:
go run ./cmd/prowl4ai crawl --output markdown https://example.comUsage:
prowl4ai crawl [--timeout ms] [--headless bool] [--output json|markdown] <url>
Install the module:
go get github.com/techbysteve/prowl4aiThen use it directly in code:
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/techbysteve/prowl4ai"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
crawler := prowl4ai.NewCrawler()
defer func() {
if err := crawler.Close(context.Background()); err != nil {
log.Printf("close error: %v", err)
}
}()
result, err := crawler.Crawl(ctx, "https://example.com")
if err != nil {
log.Fatalf("crawl failed: %v", err)
}
fmt.Println(result.Markdown)
}Custom browser/run config:
package main
import (
"context"
"fmt"
"log"
"github.com/techbysteve/prowl4ai"
)
func main() {
browserCfg := prowl4ai.DefaultBrowserConfig()
browserCfg.Headless = true
runCfg := prowl4ai.DefaultRunConfig()
runCfg.PageTimeoutMs = 120000
runCfg.WaitUntil = "networkidle"
runCfg.WaitFor = "main article"
runCfg.WaitForTimeoutMs = 10000
crawler := prowl4ai.NewCrawlerWithConfig(browserCfg, runCfg)
defer func() {
if err := crawler.Close(context.Background()); err != nil {
log.Printf("close error: %v", err)
}
}()
result, err := crawler.Crawl(context.Background(), "https://example.com")
if err != nil {
log.Fatalf("crawl failed: %v", err)
}
fmt.Printf("status=%d redirected=%s\n", result.StatusCode, result.RedirectedURL)
}A successful crawl returns fields like:
urlhtmlcleaned_htmlmarkdownmetadatastatus_coderesponse_headersredirected_urlsuccess
On failure, the tool still returns structured JSON with:
success: falseerror_message- best-effort context fields when available
cmd/prowl4ai/main.go: CLI entrypointinternal/browser/: browser adapter abstraction + Playwright implementationinternal/prowler/: crawler service orchestrationinternal/extract/: clean HTML + Markdown pipelineinternal/config/: browser and run defaultsinternal/model/: crawl result models
- Browser backend is Playwright-based and defaults to Chromium.
- CLI currently exposes only a subset of internal crawl configuration.
- Link extraction is not yet exposed in CLI output.
This project is inspired by the ideas and workflow of crawl4ai, adapted into a focused Go implementation.