<p>In Craft Commerce, I am using the Blitz Cache plugin. My &quot;add to cart&quot;-button uses ajax to add the product to the cart.</p>
<p>This is the twig-code for the form:</p>
<pre class="lang-html prettyprint-override"><code>&lt;form method=&quot;post&quot; class=&quot;product-form&quot;&gt;
  {{ csrfInput() }}
  {{ actionInput('commerce/cart/update-cart') }}
  {{ successMessageInput('{product} added to cart.'|t({
    product: product.title
  })) }}
  &lt;section class=&quot;actions&quot;&gt;
        &lt;input type=&quot;hidden&quot; name=&quot;purchasableId&quot; value=&quot;{{ defaultVariant.id }}&quot; /&gt;
        &lt;input type=&quot;number&quot; value=&quot;1&quot; name=&quot;qty&quot; class=&quot;form-control&quot; /&gt;
        &lt;button type=&quot;button&quot; class=&quot;btn btn-primary btn-add-to-basket&quot;&gt;&lt;i class=&quot;icon icon-cart-plus icon-lg&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;Add to basket&lt;/button&gt;
  &lt;/section&gt;
&lt;/form&gt;
</code></pre>
<p>This is the javascript that takes over the click event for the add-to-basket  button and posts via ajax:</p>
<pre class="lang-js prettyprint-override"><code>$(&quot;.btn-add-to-basket&quot;).on(&quot;click&quot;, function(e){
    $form = $(e.target).closest(&quot;.product-form&quot;);

    // refresh csrf token
    fetch('/api/cart/csrf')
        .then(response =&gt; response.json())
        .then(data =&gt; {
          $form.find('input[name=&quot;' + data.csrfTokenName + '&quot;]').val(data.csrfTokenValue);

          window.csrfTokenName = data.csrfTokenName;
          window.csrfTokenValue = data.csrfTokenValue;
          
          var form_data = $form.serializeArray()

          // form_data.push({
          //     name: window.csrfTokenName,
          //     value: window.csrfTokenValue
          // })
    
          $.ajax({
            type: 'post',
            url: &quot;/commerce/cart/updateCart&quot;,
            dataType: &quot;json&quot;,
            data: form_data,
    
            success: function (response, textStatus, jqXHR) {      
                // console.info(jqXHR);            
                if (jqXHR.status === 200){
                  updateCart(); // get new cart count and update UI
                }
            },
            error: function(request, status, error) {
                // Handle failure
                console.error(&quot;failed&quot; + error);
            }
          });         

        }).catch(error =&gt; console.error('Error fetching CSRF token:', error));

  });
</code></pre>
<p>This is the action code for the /api/cart/csrf:</p>
<pre class="lang-php prettyprint-override"><code>public function actionCsrf(): Response
{
    return $this-&gt;asJson([
        'csrfTokenName' =&gt; Craft::$app-&gt;getConfig()-&gt;getGeneral()-&gt;csrfTokenName,
        'csrfTokenValue' =&gt; Craft::$app-&gt;getRequest()-&gt;getCsrfToken(),
    ]);
}
</code></pre>
<p>My problem is that sometimes the call to <code>/commerce/cart/updateCart</code> will return &quot;invalid csrf&quot; and I experience a lot of times that the cart simply becomes abandoned and a new cart is created instead.</p>

CC BY-SA 4.0
2024-04-11T10:26:51.877Z
Just a couple of comments: 1) Forms can be submitted without necessarily clicking a submit button (e.g. by pressing enter while inside a field) - so you should never attach important behaviour to the click event - use the form's submit event instead. 2) Using static caching on an eCommerce site seems pretty dangerous to me (i.e., ensuring that no customer sees another customer's personal details or order history or cart contents), but if you know what you're doing then fair enough!! I've always been tempted to do static caching and create "dynamic islands" for eCommerce but not tried it yet!
James Smith
CC BY-SA 4.0
2024-04-11T11:34:24.530Z
Thanks James. Good point about attaching to the form's onSubmit event instead. I am not too spooked about using caching on an e-commerce site. The Blitz cache plugin allows you to blacklist URL patterns to exclude them from caching, which I've done to exclude everything that happens during /shop/checkout
nitech
<plugin-craftcommerce><ajax><csrf><plugin-blitz>
Add to cart via Ajax (sometimes) results in abandoned carts and invalid CSRF
# Add to cart via Ajax (sometimes) results in abandoned carts and invalid CSRF

(Asked by: username_0 on 2024-04-11)

In Craft Commerce, I am using the Blitz Cache plugin. My "add to cart"-button uses ajax to add the product to the cart.
This is the twig-code for the form:

  {{ csrfInput() }}
  {{ actionInput('commerce/cart/update-cart') }}
  {{ successMessageInput('{product} added to cart.'|t({
    product: product.title
  })) }}
  
        
        
        Add to basket
  


This is the javascript that takes over the click event for the add-to-basket  button and posts via ajax:
$(".btn-add-to-basket").on("click", function(e){
    $form = $(e.target).closest(".product-form");

    // refresh csrf token
    fetch('/api/cart/csrf')
        .then(response => response.json())
        .then(data => {
          $form.find('input[name="' + data.csrfTokenName + '"]').val(data.csrfTokenValue);

          window.csrfTokenName = data.csrfTokenName;
          window.csrfTokenValue = data.csrfTokenValue;
          
          var form_data = $form.serializeArray()

          // form_data.push({
          //     name: window.csrfTokenName,
          //     value: window.csrfTokenValue
          // })
    
          $.ajax({
            type: 'post',
            url: "/commerce/cart/updateCart",
            dataType: "json",
            data: form_data,
    
            success: function (response, textStatus, jqXHR) {      
                // console.info(jqXHR);            
                if (jqXHR.status === 200){
                  updateCart(); // get new cart count and update UI
                }
            },
            error: function(request, status, error) {
                // Handle failure
                console.error("failed" + error);
            }
          });         

        }).catch(error => console.error('Error fetching CSRF token:', error));

  });

This is the action code for the /api/cart/csrf:
public function actionCsrf(): Response
{
    return $this->asJson([
        'csrfTokenName' => Craft::$app->getConfig()->getGeneral()->csrfTokenName,
        'csrfTokenValue' => Craft::$app->getRequest()->getCsrfToken(),
    ]);
}

My problem is that sometimes the call to /commerce/cart/updateCart will return "invalid csrf" and I experience a lot of times that the cart simply becomes abandoned and a new cart is created instead.

**Tags:** plugin-craftcommerce, ajax, csrf, plugin-blitz

> **Comments:**
> **username_1**: Just a couple of comments: 1) Forms can be submitted without necessarily clicking a submit button (e.g. by pressing enter while inside a field) - so you should never attach important behaviour to the click event - use the form's submit event instead. 2) Using static caching on an eCommerce site seems pretty dangerous to me (i.e., ensuring that no customer sees another customer's personal details or order history or cart contents), but if you know what you're doing then fair enough!! I've always been tempted to do static caching and create "dynamic islands" for eCommerce but not tried it yet!  
> **username_0**: Thanks James. Good point about attaching to the form's onSubmit event instead. I am not too spooked about using caching on an e-commerce site. The Blitz cache plugin allows you to blacklist URL patterns to exclude them from caching, which I've done to exclude everything that happens during /shop/checkout  

---

## 0 answers

