{"id":51222513,"url":"https://github.com/georgemandis/tezcatl","last_synced_at":"2026-06-28T08:30:55.500Z","repository":{"id":361044531,"uuid":"1252844889","full_name":"georgemandis/tezcatl","owner":"georgemandis","description":"curl for rendered DOMs on macOS. Headless web rendering CLI powered by native macOS WebKit. Render JS-heavy pages, extract DOM, evaluate JavaScript, all from the command line.","archived":false,"fork":false,"pushed_at":"2026-06-06T20:10:23.000Z","size":14,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T12:33:32.010Z","etag":null,"topics":["cli","command-line-tool","headless-browser","macos","web-scraping","webkit","zig"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/georgemandis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-28T23:42:04.000Z","updated_at":"2026-06-06T20:10:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/georgemandis/tezcatl","commit_stats":null,"previous_names":["georgemandis/tezcatl"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/georgemandis/tezcatl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/georgemandis%2Ftezcatl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/georgemandis%2Ftezcatl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/georgemandis%2Ftezcatl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/georgemandis%2Ftezcatl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/georgemandis","download_url":"https://codeload.github.com/georgemandis/tezcatl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/georgemandis%2Ftezcatl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34882751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line-tool","headless-browser","macos","web-scraping","webkit","zig"],"created_at":"2026-06-28T08:30:54.353Z","updated_at":"2026-06-28T08:30:55.489Z","avatar_url":"https://github.com/georgemandis.png","language":"Zig","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tezcatl\n\nA lightweight CLI for rendering web pages and scraping content using native macOS WebKit.\n\ntezcatl loads URLs through the system WKWebView, waits for JavaScript to render, and returns the fully rendered DOM or the result of custom JS evaluation. No headless Chrome, no Puppeteer, no heavy dependencies — just the WebKit engine already on your Mac.\n\nThis isn't meant for production scraping pipelines or large-scale crawling. It's a good fit for small tasks, personal projects, experiments, and testing or evaluation workflows where you're already working in the macOS ecosystem and want something simple that just works.\n\nWritten in Zig. Uses Apple's WKWebView via Objective-C runtime bindings.\n\n## Install\n\n### Homebrew\n\n```bash\nbrew install georgemandis/tap/tezcatl\n```\n\n### From source\n\nRequires [Zig 0.16+](https://ziglang.org/download/) and macOS.\n\n```bash\ngit clone https://github.com/georgemandis/tezcatl.git\ncd tezcatl\nzig build -Doptimize=ReleaseFast\n```\n\n## Usage\n\n### Render a page\n\n```bash\n$ tezcatl https://example.com\n\u003chtml lang=\"en\"\u003e\u003chead\u003e\u003ctitle\u003eExample Domain\u003c/title\u003e...\n\n$ tezcatl https://spa-site.com --wait=2000\n# waits 2s after load for JS frameworks to render\n```\n\n### Evaluate JavaScript\n\n```bash\n$ tezcatl https://example.com --eval=\"document.title\"\nExample Domain\n\n$ tezcatl https://example.com --eval=\"document.querySelectorAll('a').length\"\n1\n\n$ tezcatl https://example.com --eval=\"document.title\" --json\n{\"result\":\"Example Domain\"}\n```\n\n### JSON output\n\n```bash\n$ tezcatl https://example.com --json | jq '.html' | head -c 100\n\"\u003chtml lang=\\\"en\\\"\u003e\u003chead\u003e\u003ctitle\u003eExample Domain\u003c/title\u003e...\n```\n\n### Save a web archive\n\n```bash\n$ tezcatl https://example.com --archive\n# writes example.com.webarchive (a self-contained Safari archive)\n\n$ tezcatl https://example.com --archive=page.webarchive\n# writes to an explicit path\n\n$ tezcatl https://spa-site.com --wait=2000 --archive=app.webarchive\n# wait for JS to render, then archive\n```\n\nThe `.webarchive` format is a binary property list that bundles the page and its\nsubresources, openable in Safari. Requires macOS 11.0+.\n\n### Save a PDF\n\n```bash\n$ tezcatl https://example.com --pdf\n# writes example.com.pdf\n\n$ tezcatl https://example.com --pdf=page.pdf\n# writes to an explicit path\n\n$ tezcatl https://spa-site.com --wait=2000 --pdf=app.pdf\n# wait for JS to render, then export PDF\n```\n\nRenders the whole page to a PDF via WebKit. Requires macOS 11.0+.\n\n## Composability\n\ntezcatl reads URLs as arguments and writes to stdout, so it pipes naturally with other tools:\n\n```bash\n# Get the rendered DOM and detect its language\ntezcatl https://example.com | lingua detect\n\n# Extract all links from a JS-rendered page\ntezcatl https://spa-site.com --wait=2000 --eval=\"JSON.stringify([...document.querySelectorAll('a')].map(a =\u003e a.href))\"\n\n# Scrape a page title for use in a script\nTITLE=$(tezcatl https://example.com --eval=\"document.title\")\n\n# Get rendered HTML and extract phone numbers\ntezcatl https://business-site.com --wait=1000 | lingua entities --type=phone\n```\n\n## Options\n\n```\ntezcatl \u003curl\u003e [options]\n\n  --eval=JS            Evaluate custom JavaScript instead of returning DOM\n  --eval-file=FILE     Evaluate JavaScript from a file\n  --screenshot[=FILE]  Take a PNG screenshot (default: stdout)\n  --archive[=FILE]     Save the page as a self-contained Safari .webarchive\n  --pdf[=FILE]         Save the page as a PDF\n  --width=PX           Viewport width in pixels (default: 1280)\n  --height=PX          Viewport height in pixels (default: 720)\n  --wait=MS            Wait N ms after page load for JS to settle (default: 0)\n  --timeout=MS         Navigation timeout in ms (default: 30000)\n  --json               Wrap output in JSON\n  --help, -h           Show this help message\n  --version, -v        Show version\n```\n\n## Requirements\n\n- macOS 11.0+ (Big Sur or later)\n- Zig 0.16+\n\n## How It Works\n\ntezcatl creates an offscreen WKWebView, loads the URL, waits for the navigation delegate to fire `didFinishNavigation:`, optionally waits for additional JS settling time, then evaluates `document.documentElement.outerHTML` (or custom JS via `--eval`) through `evaluateJavaScript:completionHandler:`.\n\nThe Dock icon is suppressed via `NSApplicationActivationPolicyAccessory`. All WebKit rendering happens in-process using the system engine — the same one Safari uses.\n\nKey bridging patterns:\n- **Navigation delegate:** Runtime class creation (`objc_allocateClassPair`) with `WKNavigationDelegate` callbacks\n- **JS completion handler:** ObjC block ABI (`_NSConcreteStackBlock`) for async evaluation callbacks\n- **Run loop:** `CFRunLoopRunInMode` to pump the event loop while waiting for async operations\n\n## Related Projects\n\n- [lingua](https://github.com/georgemandis/lingua) — NLP CLI (NaturalLanguage framework)\n- [loupe](https://github.com/georgemandis/loupe) — Computer vision CLI (Vision framework)\n- [whereami](https://github.com/georgemandis/whereami) — Location CLI (CoreLocation)\n- [nearme](https://github.com/georgemandis/nearme) — Local search CLI (MapKit)\n\n## Credits\n\nCreated by [George Mandis](https://george.mand.is) during [Recurse Center](https://www.recurse.com/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeorgemandis%2Ftezcatl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeorgemandis%2Ftezcatl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeorgemandis%2Ftezcatl/lists"}