We are building LLMRank, a Shopify app available on the App Store that makes store catalogs discoverable by ChatGPT, Perplexity, Google AI Overviews, and every other system that reads the web through an LLM lens. It scores AI readiness, generates structured data as versioned metafields, provides llm.txt and /llm-index.json endpoints, simulates LLM queries against your catalog, and at the center of it all, serves clean Markdown snapshots of products and collections for AI crawlers to consume.
That Markdown layer needs to convert HTML reliably, at scale, across different source types. Cloudflare just shipped three services for this: Markdown for Agents (edge-level content negotiation), Workers AI toMarkdown (binary file conversion via REST), and Browser Rendering /markdown (headless Chromium for JS-heavy pages). Three services, three REST endpoints, three auth patterns. Wiring them into LLMRank's Laravel backend individually meant duplicating HTTP client setup, error handling, response parsing, and caching across each integration. So we built a unified adapter, extracted it, and open sourced it.
Why Markdown matters now
AI is at the core of how we work, and when AI systems start changing how they consume the web, we pay attention. Crawlers, coding agents, and LLM-powered search now tokenize everything they receive. Raw HTML is expensive: Cloudflare measured a single blog post at 16,180 tokens in HTML versus 3,150 in Markdown, an 80% reduction. At scale, the savings in context window budget and inference cost are substantial.
Cloudflare's three services each target a different conversion scenario. Markdown for Agents operates at the CDN edge via Accept: text/markdown content negotiation, returning Markdown with x-markdown-tokens and Content-Signal headers. No auth required. Workers AI toMarkdown accepts binary uploads (PDF, DOCX, XLSX, images, CSV, and more) through a multipart REST endpoint with batch support. Browser Rendering /markdown spins up Chromium, waits for a configurable load state, and converts the rendered DOM. Supports waitForSelector, request rejection, cookie injection, basic auth, and custom user agents.
One API for everything
Markdown for Agents for Laravel wraps all three services behind a single fluent interface with a driver-based architecture. Each Cloudflare service maps to a driver (agents, workers_ai, browser), and the package handles HTTP client setup, authentication, response normalization, caching, and error recovery.
composer require moneo/markdown-for-agents
php artisan vendor:publish --tag=markdown-for-agents-config
CF_ACCOUNT_ID=your-account-id
CF_API_TOKEN=your-api-token
The agents driver requires no credentials since it relies on content negotiation, not authenticated API calls.
Convert a URL
use Moneo\MarkdownForAgents\Facades\MarkdownForAgents;
$result = MarkdownForAgents::url('https://example.com')->convert();
$result->markdown; // string: the converted content
$result->tokens; // int: estimated token count
$result->contentSignals; // ?array: ['ai-train' => 'yes', ...]
$result->driver; // string: which driver handled it
$result->fromCache; // bool: served from cache?
Convert a file
$result = MarkdownForAgents::file('/path/to/document.pdf')->convert();
// Or from a Laravel upload
$result = MarkdownForAgents::file($request->file('document'))->convert();
Batch conversion
$results = MarkdownForAgents::files([$pdf, $image, $spreadsheet])->convert();
foreach ($results as $result) {
echo "{$result->name}: {$result->tokens} tokens\n";
}
Switch drivers
// Default: agents driver (fastest, free)
$result = MarkdownForAgents::url($url)->convert();
// Browser driver for JavaScript-heavy pages
$result = MarkdownForAgents::driver('browser')
->url('https://spa-app.com')
->waitUntil('networkidle0')
->convert();
// Convert raw HTML through browser rendering
$result = MarkdownForAgents::driver('browser')
->html('<div><h1>Hello</h1><p>World</p></div>')
->convert();
The driver is selected automatically based on input type, or explicitly via driver(). The same ConversionResult DTO is returned regardless of which backend handled the request.
Automatic fallback
If the primary driver throws (zone does not support Markdown for Agents, network timeout, unexpected response), the package can retry with a different driver:
$result = MarkdownForAgents::url('https://example.com')
->withFallback('browser')
->convert();
This is particularly useful when targeting URLs where you cannot guarantee Cloudflare zone configuration. The agents driver fails fast with a non-Markdown Content-Type, and the browser driver picks up transparently.
Middleware: serve Markdown from your own routes
The package includes a middleware that implements Cloudflare's content negotiation pattern on your own Laravel routes. No Cloudflare zone required. No external API calls. The conversion runs locally using league/html-to-markdown.
Route::get('/blog/{slug}', [BlogController::class, 'show'])
->middleware('markdown-for-agents');
When an incoming request includes Accept: text/markdown, the middleware intercepts the HTML response after it is rendered, converts it, and returns it with the following headers:
Content-Type: text/markdown; charset=utf-8Vary: acceptx-markdown-tokens: {count}Content-Signal: ai-train=yes, search=yes, ai-input=yes
Regular browser requests pass through untouched. The middleware only activates on content negotiation.
This is already a live pattern. Claude Code, OpenCode, and several OpenAI crawlers send Accept: text/markdown in their request headers today. If your application can respond to that, you deliver structured content directly to the agent's context window instead of forcing it to parse your HTML and burn tokens on layout noise.
Everything else
Caching. URL and HTML conversions are cached by default, keyed by source hash and driver name. TTL is configurable globally or per request via ->cache(7200). Bypass with ->noCache(). Invalidate with MarkdownForAgents::clearCache($url) or flushCache().
Browser driver options. The browser driver exposes waitUntil (maps to Puppeteer's goto options), rejectPatterns (blocks matching requests before render), userAgent, cookies, and authenticate for pages behind auth walls.
Events. MarkdownConverted and ConversionFailed events are dispatched on every conversion. Wire them to your logging, monitoring, or alerting stack.
Artisan commands. php artisan markdown:convert converts URLs or files from the CLI with --driver and --save options. markdown:formats lists supported file types. markdown:cache:clear manages the cache.
Extensibility. Every driver implements MarkdownConverterInterface with a single method: convert(PendingConversion): ConversionResult. Register custom drivers via MarkdownForAgents::extend() and the rest of the package (caching, events, fallback) works with them out of the box.
Driver selection guide:
| Scenario | Recommended Driver |
|---|---|
| Cloudflare-enabled site | agents (fastest, free) |
| PDF, DOCX, XLSX, images | workers_ai (only option) |
| SPA or JavaScript-heavy page | browser (full render) |
| Non-Cloudflare site | browser |
| Raw HTML string | browser |
| Making your app agent ready | Middleware (local, no API) |
Why we open sourced it
This package was extracted from LLMRank. The conversion logic is entirely generic, and any Laravel team integrating with Cloudflare's Markdown services will face the same wiring problem. The middleware came from the same GEO work: making brands visible in AI-generated answers requires both consuming structured content and serving it. When an internal abstraction is clean enough to stand on its own, we extract and open source it, just like we did with Laravel Usage Limiter.
Give it a try
Markdown for Agents for Laravel is on Packagist. PHP 8.2+, Laravel 11 or 12. Tests run via orchestra/testbench with mocked HTTP, no real API calls.
Source, issues, and PRs on GitHub. If you need help building AI-powered Laravel applications or making your infrastructure agent-ready, reach out.
Links:
Moneo as Your Enterprise Partner
We collaborate closely with enterprise teams to design, deliver, and operate systems built for the long run.
Start PartnershipHow We Can Help
GEO & AI Search Optimization
Make your brand visible in AI-generated answers. Optimize for ChatGPT, Perplexity, Gemini and other AI search engines.
Learn moreShopify
Future-ready Shopify solutions for growing brands.
Learn moreSoftware Consulting
We help you make the right technical decisions, improve processes, and build smarter with advice from engineers who have seen it all.
Learn more
GEO & AI Search Optimization for Shopify
LLMRank is a Shopify app that makes product catalogs discoverable by ChatGPT, Perplexity, Google AI Overviews, and every AI system that reads the web through a language model. Here is how it works.
Quiet Failures in Usage Metering
Usage metering rarely crashes loudly. It drifts silently. We built Laravel Usage Limiter to make metering atomic, idempotent, and auditable under real production pressure.
Meet Markdown++: Open Source Markdown Editor
Markdown++ is an open source browser based editor built by Moneo for static site creators. It blends the simplicity of Markdown with AI powered writing and seamless Git integration.