Docs/WooCommerce

WooCommerce

The script on the storefront, and the order recorded from PHP — so a sale counts even when the customer never comes back to the thank-you page.

1. The tracking script

WooCommerce runs on WordPress, so the install is the WordPress one: a must-use plugin, which survives a theme change. See the WordPress guide, or paste this file directly.

wp-content/mu-plugins/kipstats.php
<?php
/**
 * Plugin Name: Kipstats
 * Description: Cookie-free analytics. Survives theme changes.
 */
add_action('wp_head', function () {
    echo '<script defer src="https://kipstats.com/tracker.js" data-site="kp_xxxxxxxx"></script>';
}, 1);

2. The ingest key, out of the repository

Recording an order is a write, so it needs the site's ingest key (kpi_…), found in Dashboard → your site → Settings. Put it in wp-config.php, never in a theme file and never in Git:

wp-config.php
define('KIPSTATS_INGEST_KEY', 'kpi_your_ingest_key');

3. The order, from PHP

woocommerce_payment_complete fires when the payment is confirmed — including when the gateway confirms it minutes later, with nobody's browser involved. That is exactly the case the browser cannot cover.

wp-content/mu-plugins/kipstats-orders.php
<?php
/**
 * Plugin Name: Kipstats orders
 * Description: Records a paid WooCommerce order as a Kipstats purchase.
 */
add_action('woocommerce_payment_complete', function ($order_id) {
    if (!defined('KIPSTATS_INGEST_KEY')) {
        return;
    }
    $order = wc_get_order($order_id);
    if (!$order) {
        return;
    }
    $paid_at = $order->get_date_paid();

    wp_remote_post('https://kipstats.com/api/collect/server', [
        'timeout'  => 5,
        'blocking' => false,
        'headers'  => [
            'Authorization' => 'Bearer ' . KIPSTATS_INGEST_KEY,
            'Content-Type'  => 'application/json',
        ],
        'body' => wp_json_encode([
            'name'       => 'purchase',
            'ref'        => 'wc_' . $order->get_id(),
            'occurredAt' => $paid_at ? $paid_at->format('c') : null,
            'data'       => [
                'amount'   => (int) round($order->get_total() * 100),
                'currency' => $order->get_currency(),
                'items'    => $order->get_item_count(),
            ],
        ]),
    ]);
});
  • ref is the order ID, so a gateway that retries does not create a second sale.
  • 'blocking' => false keeps checkout fast: WordPress does not wait for our answer. The trade-off is that a failure is silent — check one real order after installing.
  • Amounts are sent in the smallest unit. The × 100 above is right for euros, dollars and pounds, wrong for zero-decimal currencies such as JPY — adjust if you sell in one.

4. Optional: the steps before payment

The order tells you what was bought, not where people gave up. Two events on the storefront are enough to see the drop:

Anywhere in your theme
<script>
  function kp(n, d) {
    try { if (window.kipstats && window.kipstats.event) window.kipstats.event(n, d || {}) } catch (e) {}
  }
  // on the cart page, when the customer heads to checkout
  kp('checkout_started', { price: <?= (int) round(WC()->cart->get_total('edit') * 100) ?>, currency: '<?= get_woocommerce_currency() ?>' })
</script>

Rage clicks, dead clicks and abandoned fields on your checkout form are captured without any code — they are usually where the answer is. See what is captured automatically.

5. Check it once, for real

  1. Place one real order (or one in your gateway's live test mode, if it marks it as such — never emit a sale for a test payment).
  2. Open Events in your dashboard: a purchase should be there, with the right amount and currency.
  3. Refund or cancel your test order in WooCommerce. ⚠️ The refund is not deducted from Kipstats revenue today — see tracking revenue.