Anonymous visitors are the majority of traffic on most public sites, and by default, many of them don't need a session at all — no login, no cart, no preferences to remember. Yet certain common patterns (a stray messenger call, a form that always initializes CSRF state) can trigger a session write for every single one of them anyway, which — as you saw back in the cache-debugging lesson — silently disables page caching for exactly the visitors it matters most to cache for.
What you'll learn in this lesson
- Why an anonymous session write is worse than an authenticated one
- The common causes of accidental anonymous session starts
- How to verify no session is starting when none should
Why this matters more for anonymous visitors specifically
Common accidental triggers
// Any of these start a session, even for an anonymous visitor who
// never explicitly needed one:
\Drupal::messenger()->addMessage('Some message.'); // Sets a session flash message.
$form_state->setStorage($data); // Form API session-backed storage.
\Drupal::service('csrf_token')->get(); // Generating a CSRF token requires a session.
None of these look like "session code" at first glance — that's exactly what makes this bug so common. A form displayed to every visitor that unconditionally generates a CSRF token (rather than only when the form is actually about to be submitted) starts a session for every single page view that includes it, whether or not anyone ever interacts with the form.
Finding and confirming the problem
# Check the actual response header — Set-Cookie for a session cookie
# on a page that should be fully anonymous and cacheable is the tell.
curl -I https://example.com/some-page | grep -i set-cookie
A Set-Cookie: SESS... header on a response that should be anonymous and cacheable is definitive proof something on that page is starting a session unnecessarily — combine this with the query-log backtrace technique from the Performance Debugging section to trace exactly which code is responsible.
Quick check: a contact form block appears on every page of the site, and it always calls the CSRF token service to render its hidden token field, regardless of whether a visitor ever interacts with it. What's the site-wide consequence? If you said page caching gets disabled for every anonymous visitor on every page carrying that block, you've understood exactly how a small, innocent-looking form can have an outsized site-wide performance cost.
Key takeaways
- An anonymous session write disables page caching for that visitor — worse than an authenticated one, since anonymous traffic is what the page cache exists to serve fastest.
- Messenger calls, CSRF token generation, and Form API storage are the most common accidental session triggers.
- A
Set-Cookie: SESS...header on a page that should be cacheable is definitive proof of an unnecessary session start. - Audit widely-placed components (blocks appearing on every page) especially carefully — their session cost multiplies across your entire anonymous traffic.
Coming up next
Sessions handle per-visitor state. Next, a related but distinct cost: how permission checks themselves get cached, so authenticated visitors don't pay a full access-check cost on every single request.