Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Markdown Response Laravel Package

spatie/laravel-markdown-response

Serve markdown versions of your Laravel HTML pages for AI agents and bots. Detect markdown requests via Accept: text/markdown, known user agents, or .md URLs. Driver-based conversion (local PHP or Cloudflare Workers AI), with caching and HTML preprocessing.

View on GitHub
Deep Wiki
Context7

title: CDN and cache layers weight: 6

When you serve both HTML and markdown from the same URL, external cache layers can cause problems. The package includes a Vary: Accept header on markdown responses, but not all CDNs respect it.

Cloudflare

Cloudflare's Free and Pro plans do not respect the Vary: Accept header for non-image content types. This means the first response (HTML or markdown) gets cached and served to all subsequent requests — regardless of their Accept header.

If you use the .md suffix detection method, this is not an issue: /about and /about.md are different URLs with separate cache entries.

If you rely on Accept header or user agent detection, you need to configure Cloudflare to bypass its cache for markdown requests. Create a Cache Rule with this expression:

any(http.request.headers["accept"][*] contains "text/markdown")

Set the action to Bypass Cache.

For user agent-based detection, add expressions for the bots you want to handle:

any(http.request.headers["accept"][*] contains "text/markdown") or
http.request.headers["user-agent"] contains "GPTBot" or
http.request.headers["user-agent"] contains "ClaudeBot" or
http.request.headers["user-agent"] contains "ChatGPT-User"

Other CDNs

CDNs like Fastly, Varnish, and Nginx generally respect the Vary: Accept header. Since the package sets this header on markdown responses, these CDNs will store separate cache entries for different Accept header values without additional configuration.

spatie/laravel-responsecache

If you use spatie/laravel-responsecache, cached HTML responses may be served before this package's middleware runs. The response cache stores the first response it sees (HTML) and replays it for all subsequent requests — including those that should receive markdown.

To fix this, override useCacheNameSuffix() in your CacheProfile to create separate cache entries:

use Illuminate\Http\Request;
use Spatie\ResponseCache\CacheProfiles\CacheAllSuccessfulGetRequests;

class CacheProfile extends CacheAllSuccessfulGetRequests
{
    public function useCacheNameSuffix(Request $request): string
    {
        $suffix = parent::useCacheNameSuffix($request);

        if ($request->attributes->get('markdown-response.suffix')
            || str_contains($request->header('Accept', ''), 'text/markdown')
        ) {
            return $suffix . '-markdown';
        }

        return $suffix;
    }
}

Then register it in config/responsecache.php:

'cache_profile' => App\CacheProfiles\CacheProfile::class,

General advice

Caching failures are silent — a cached HTML response served to an AI bot is still a valid HTTP response, so no errors are logged. Test your setup end-to-end in production-like environments where all cache layers are active.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport