Tracking Magento “add product to cart” action for analytic software purpose

add_to_cart_magento_track

Recently I have been working on a Magento extension for a 3rd party customer analytics and targeting web service, think Google Analytics alternative. One of the eCommerce tracking features that needed to be implemented was the “add product to cart” action. Since these kind of tracking services use JavaScript to trigger their tracking code, it’s up to us to see where and when will be embed certain tracking JavaScript in Magento. What’s interesting about “add product to cart” action is that it’s not your usual web page on which you land and are then in possibility to execute certain JavaScript.

In Magento, when you click any “Add to Cart” page, you usually end up on a URL like http://magentoce1800.loc/index.php/checkout/cart/add/uenc/aHR0…0bWw,/product/16/form_key/oTSbNJ4ZIUC46W0R/. Where checkout/cart/add part is the interesting one, as it points to Mage_Checkout module, its CartController and then addAction() within the CartController class. Second interesting part is the product/16 part of the URL which actually tells Magento that product with id 16 is being added to cart. Additionally, there is a lot more going on within the addAction() action method itself. What is important to know is that once the Magento code within the addAction() method adds the product to cart, it redirect you to the cart page itself. Meaning that the actual checkout/cart/add page is never rendered to the browser, so you cannot execute any JavaScript within it.

So, where am I going with all of this? Well, one of the cooler features of Magento is definetly its Event/Observer system. If you think about it, each controller action supports generic controller_action_predispatch event defined within the app/code/core/Mage/Core/Controller/Varien/Action.php around line 527 as follows Mage::dispatchEvent(‘controller_action_predispatch’, array(‘controller_action’ => $this));. Then there are more specific one event that matches its module forntend name, controller and action, which in this case, resolves to frontend event controller_action_predispatch_checkout_cart_add.

With this in mind, here is a simple idea for tracking “add product to cart” actions via JavaScript:

1. define an event observer method for controller_action_predispatch_checkout_cart_add event

2. within the event observer method, make a “record” of the product that was just added to the cart, for example something like Mage::getModel(‘core/session’)->setProductToShoppingCart(…) will do.

3. make a layout update for checkout_cart_index handle, that loads a custom .phtml template file, you can use core/template or your own block class for block type definition

4. within the custom .phtml template file generate your “add product to cart” tracking point by using the Mage::getModel(‘core/session’)->getProductToShoppingCart() to fetch the info for the product just added to cart, then when you are done, simply unset the session by doing something like Mage::getModel(‘core/session’)->unsProductToShoppingCart()

Below is a code example for just described workflow.

As described in step #1 above: app/code/community/Inchoo/Test/etc/config.xml

<?xml version="1.0"?>
 
<config>
    <modules>
        <Inchoo_Test>
            <version>1.0.0.0</version>
        </Inchoo_Test>
    </modules>
    <global>
        <models>
            <inchoo_test>
                <class>Inchoo_Test_Model</class>
            </inchoo_test>
        </models>
    </global>
    <frontend>
        <layout>
            <updates>
                <inchoo_test>
                    <file>inchoo_test.xml</file>
                </inchoo_test>
            </updates>
        </layout>
        <events>
            <controller_action_predispatch_checkout_cart_add>
                <observers>
                    <inchoo_test_log_cart_add>
                        <class>inchoo_test/observer</class>
                        <method>logCartAdd</method>
                    </inchoo_test_log_cart_add>
                </observers>
            </controller_action_predispatch_checkout_cart_add>
        </events>
    </frontend>
</config>

As described in step #2 above: app/code/community/Inchoo/Test/Model/Observer.php

<?php
 
class Inchoo_Test_Model_Observer
{
    public function logCartAdd() {
 
        $product = Mage::getModel('catalog/product')
                        ->load(Mage::app()->getRequest()->getParam('product', 0));
 
        if (!$product->getId()) {
            return;
        }
 
        $categories = $product->getCategoryIds();
 
        Mage::getModel('core/session')->setProductToShoppingCart(
            new Varien_Object(array(
                'id' => $product->getId(),
                'qty' => Mage::app()->getRequest()->getParam('qty', 1),
                'name' => $product->getName(),
                'price' => $product->getPrice(),
                'category_name' => Mage::getModel('catalog/category')->load($categories[0])->getName(),
            ))
        );
    }
}

Obviously the code above is very basic. It does not cover various Magento product type combinations as it pulls the price directly from product model. So in cases where you have configurable, bundle or grouped products you would need a little extra to get to it. You could however start from product id, then do a look-up on the quote items table in order to find child products, etc.

As described in step #3 above: app/design/frontend/default/default/layout/inchoo_test.xml

<?xml version="1.0"?>
 
<layout version="0.1.0">
    <checkout_cart_index>
        <reference name="before_body_end">
            <block type="inchoo_test/event_checkout_cart_index" name="inchoo_test_event_checkout_cart_index" template="inchoo/test/event/checkout/cart/index.phtml" />
        </reference>
    </checkout_cart_index>
</layout>

As described in step #4 above: app/design/frontend/default/default/ template/inchoo/test/event/checkout/cart/index.phtml

<?php $_product = Mage::getModel('core/session')->getProductToShoppingCart() ?>
<?php if ($_product && $_product->getId()): ?>
    <script type="text/javascript">
        //Some 3rd party JS tracking code
    </script>
    <?php Mage::getModel('core/session')->unsProductToShoppingCart(); ?>
<?php endif; ?>

That’s about it, one simple way to track “add product to cart” action for your analytics service.

The good thing about it is that you do not have to edit any existing .phtml template files adding JS onclick events or something like that.

Hope this helps someone.


11 comments

  1. hi. can anyone please tell me wat this means. thanks

    uenc/aHR0cHM6Ly93d3cubmlrZXN0b3JlLmNvbS5hdS93aXNobGlzdC8_X19fU0lEPVM/product/

  2. Not so much useful (but thanks for article it helped me 🙂 ) if add to card functionality is realized via ajax post and code after adding should be generated directly in the page without reload. For example for GTM purposes this data should be generated on current page and not in next one, as it will works with this solution.

  3. Really helpful to do certain dynamic stuff based on controller and action , Awesome work
    just curious to ask what if there is any exception and product is not added to cart ?
    If we use more specific event just for this case sales_quote_product_add_after , we wont have to load the model again.

  4. Trivial stuff but for the sake of purity

    $observer->getData('controller_action')->getRequest();

    can be used instead of

    Mage::app()->getRequest();
  5. i have a product page in which i have set the related products can’t set the link for add to cart in it..??

  6. Can someone please tell me how we can track the pages visited by an user?which event is responsible for rendering of pages?
    Its a bit urgent
    Thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.