Integration Guides

WooCommerce

Add Rybbit analytics to your WooCommerce store

WooCommerce runs on WordPress, so the snippet goes in the same way as on any WordPress site. What this guide adds is the WooCommerce action hooks that send purchases, add-to-carts, product views and checkouts to Rybbit as custom events.

Get your tracking snippet

In your Rybbit dashboard, open Site Settings → Tracking Script and copy your snippet. It looks like this:

<script src="https://app.rybbit.io/api/script.js?siteId=YOUR_SITE_ID" defer></script>

YOUR_SITE_ID is the numeric ID of your site. If you self-host Rybbit, app.rybbit.io is the domain of your own instance.

Add the snippet to WooCommerce

Follow the WordPress guide to add the snippet. If you plan to track the e-commerce events below, use the functions.php or mini-plugin method there: the event hooks are PHP and belong in the same file.

function rybbit_add_tracking_script() {
    ?>
    <script src="https://app.rybbit.io/api/script.js?siteId=YOUR_SITE_ID" defer></script>
    <?php
}
add_action( 'wp_head', 'rybbit_add_tracking_script' );

Verify installation

Open your live site in a new tab and click through a few pages. Within a few seconds the pageviews appear in the Rybbit dashboard.

If nothing shows up:

  • View the page source and search for script.js?siteId= to confirm the snippet is on the page.
  • Open the browser Network tab and check that script.js returns 200 and that POST requests go to /api/track.
  • Disable ad blockers, or set up a proxy so the script loads from your own domain.
  • See the script troubleshooting guide for other common causes.

Track custom events

WooCommerce fires PHP action hooks at each stage of the shopping flow. The snippets below print a small inline script from those hooks. They wait for DOMContentLoaded because the tracking script is loaded with defer, so window.rybbit does not exist while the page is still parsing.

Add these to your child theme's functions.php or a site-specific plugin, never to the parent theme.

Purchase

woocommerce_thankyou fires on the order-received page with the order ID.

add_action( 'woocommerce_thankyou', 'rybbit_track_purchase', 10, 1 );
function rybbit_track_purchase( $order_id ) {
    $order = wc_get_order( $order_id );
    if ( ! $order ) {
        return;
    }

    $items = array();
    foreach ( $order->get_items() as $item ) {
        $product = $item->get_product();
        $items[] = array(
            'item_id'   => $product && $product->get_sku() ? $product->get_sku() : $item->get_product_id(),
            'item_name' => $item->get_name(),
            'price'     => (float) $order->get_line_subtotal( $item, false, false ),
            'quantity'  => (int) $item->get_quantity(),
        );
    }

    $purchase = array(
        'transaction_id' => $order->get_order_number(),
        'value'          => (float) $order->get_total(),
        'tax'            => (float) $order->get_total_tax(),
        'shipping'       => (float) $order->get_shipping_total(),
        'currency'       => $order->get_currency(),
        'items'          => $items,
    );
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        window.rybbit.event('purchase', <?php echo wp_json_encode( $purchase ); ?>);
    });
    </script>
    <?php
}

Event properties are limited to 2048 characters of JSON, so trim items to ID, quantity and price, or drop it, for stores with large orders.

Add to cart

Two hooks cover both paths: the product-page form submit, and WooCommerce's added_to_cart jQuery event for AJAX buttons on shop and category pages.

// Single product page: track on form submit
add_action( 'woocommerce_after_add_to_cart_button', 'rybbit_track_add_to_cart' );
function rybbit_track_add_to_cart() {
    global $product;
    if ( ! $product instanceof WC_Product ) {
        return;
    }
    $data = array(
        'item_id'   => $product->get_sku() ? $product->get_sku() : $product->get_id(),
        'item_name' => $product->get_name(),
        'price'     => (float) $product->get_price(),
        'currency'  => get_woocommerce_currency(),
    );
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        var form = document.querySelector('form.cart');
        if (!form) return;
        form.addEventListener('submit', function () {
            var data = <?php echo wp_json_encode( $data ); ?>;
            var qty = form.querySelector('input.qty');
            data.quantity = qty && parseInt(qty.value, 10) > 0 ? parseInt(qty.value, 10) : 1;
            window.rybbit.event('add_to_cart', data);
        });
    });
    </script>
    <?php
}

// AJAX add-to-cart buttons on shop and category pages
add_action( 'wp_footer', 'rybbit_track_ajax_add_to_cart' );
function rybbit_track_ajax_add_to_cart() {
    if ( is_admin() ) {
        return;
    }
    ?>
    <script>
    jQuery(document.body).on('added_to_cart', function (event, fragments, cartHash, $button) {
        if (!$button || !$button.length) return;
        window.rybbit.event('add_to_cart', {
            item_id: $button.data('product_id'),
            quantity: $button.data('quantity') || 1,
            source: 'ajax_add_to_cart'
        });
    });
    </script>
    <?php
}

The AJAX handler only sees the product ID and quantity from the button's data-* attributes. Add attributes to the button in your theme if you also want name and price.

View product and begin checkout

The same pattern works for the remaining hooks:

  • woocommerce_after_single_product_summary runs on product pages. Guard with is_product(), then send view_item with item_id, item_name, price and currency from the global $product.
  • woocommerce_before_checkout_form runs on the checkout page. Build begin_checkout from WC()->cart: loop over get_cart() for the items (each $cart_item['data'] is the product, $cart_item['quantity'] the quantity), with value from $cart->get_total( 'edit' ) and currency from get_woocommerce_currency().

Troubleshooting

  • Events fire before the tracker loads: keep the tracking snippet in wp_head and the DOMContentLoaded wrapper in place. Deferred scripts run before DOMContentLoaded, so window.rybbit is ready by then; calling it from a bare inline script drops the event.
  • AJAX carts and mini-carts: themes that update the cart without a page load never hit the PHP hooks, so rely on the added_to_cart listener for those and test each add-to-cart path.
  • Other analytics plugins: plugins that also print e-commerce data layers can conflict. Test with a real order after enabling both.

Next steps

On this page