How to correctly use cookies? (Twig and cache context) In my current project I need to alter node templates depending on previously visited landing page. My idea is that, when a visitor visits one of these landing pages, a cookie will be set, and subsequent node templates will be altered depending on that cookie.

I've got three view pages serving as entry points for my visitors:
myproject.com/tv
myproject.com/mobile
myproject.com/infopoint  

In theme preprocess I'm checking/setting a cookie and assigning a template variable. The Twig templates do minor modifications depending on that variable:

function MYTHEME_preprocess(array &amp;$variables, $hook) {
  $router = \Drupal::routeMatch();

  if ($route = $router-&gt;getRouteObject()) {
    $view_id = $route-&gt;getDefault('view_id');
    $display_id = $route-&gt;getDefault('display_id');
    $view_display_plugin = $route-&gt;getOption('_view_display_plugin_id');

    if ($view_id &amp;&amp; $view_display_plugin === 'page') {
      if ($view_id == 'slide') {
        user_cookie_save(['device' =&gt; 'tv']);
        $variables['MYTHEME']['device'] = 'tv';
      }
      elseif ($view_id == 'tile' &amp;&amp; $display_id == 'mobile') {
        user_cookie_save(['device' =&gt; 'mobile']);
        $variables['MYTHEME']['device'] = 'mobile';
      }
      elseif ($view_id == 'tile' &amp;&amp; $display_id == 'infopoint') {
        user_cookie_save(['device' =&gt; 'infopoint']);
        $variables['MYTHEME']['device'] = 'infopoint';
      }
    }
  }

  // user_cookie_save prefixes all cookie names with 'Drupal.visitor.'
  if (isset($_COOKIE['Drupal.visitor.device']) &amp;&amp; 
    in_array($_COOKIE['Drupal.visitor.device'], ['tv', 'mobile', 'infopoint'])) {
         // I'm doing design modifications in my Twig templates depending on this variable
        $variables['MYTHEME']['device'] = $_COOKIE['Drupal.visitor.device'];
    }
  }
}


In services.yml I've activated the cookies cache context

parameters:
  renderer.config:
    required_cache_contexts: ['languages:language_interface', 'theme', 'user.permissions', 'url.site', 'cookies:Drupal.visitor.device']


In my Twig templates I've got multiple code pieces like this:

{% if MYTHEME.device == 'tv' %}
   &lt;!-- code here --&gt;
{% else %}
   &lt;!-- other design here --&gt;
{% endif %}


Sadly the code doesn't really work. On the entry pages, the device theme variable is always correct, but the cookie is not updated (seems as if only first uncached hit sets the cookie. I even have the weird situation that cookie and twig variable aren't equal.). On node templates the theme variable isn't set correctly at all.

Any ideas how to get the code above working?

PS: Due slow views with geo-distance calculations disabling cache is not an option, I need to provide cached pages also for anonymous users.
I've updated the code in the question, the code is now working. It was almost complete, I had made some simple mistakes though:


Even when providing a proper cache context, you still need to disable the Internal page cache module. Only Internal dynamic page cache module is allowed.
user_cookie_save() prefixes the cookie name with Drupal.visitor. This is  the real name you'll also see in your browser's dev console. But when checking for cookie names in PHP, dots and spaces are converted to underscores. That means using user_cookie_save(['mycookie' =&gt; 'some_value']); creates a cookie with a "real" name of Drupal.visitor.mycookie, but in PHP


your template/module code needs to check
if ($_COOKIE['Drupal_visitor_mycookie'])
and you also have to use the underscore name in services.yml
required_cache_contexts: ['cookies:Drupal_visitor_device', '...other_stuff...']

Don't set the cookie value and check that updated cookie value in the same request:
user_cookie_save(['mycookie' =&gt; 'new_value'])
will immediatly update the cookie in the client browser, but PHP code in the same request like
if ($_COOKIE['Drupal_visitor_mycookie'])
will still return the original value from the previous request.