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.jsreturns200and thatPOSTrequests 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_summaryruns on product pages. Guard withis_product(), then sendview_itemwithitem_id,item_name,priceandcurrencyfrom the global$product.woocommerce_before_checkout_formruns on the checkout page. Buildbegin_checkoutfromWC()->cart: loop overget_cart()for the items (each$cart_item['data']is the product,$cart_item['quantity']the quantity), withvaluefrom$cart->get_total( 'edit' )andcurrencyfromget_woocommerce_currency().
Troubleshooting
- Events fire before the tracker loads: keep the tracking snippet in
wp_headand theDOMContentLoadedwrapper in place. Deferred scripts run beforeDOMContentLoaded, sowindow.rybbitis 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_cartlistener 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
- Track custom events such as signups, purchases and button clicks.
- Identify users to connect sessions to accounts.
- Proxy the script through your own domain to bypass ad blockers.
- Script attributes let you skip or mask URLs and tag events.