Skip to main content
8 min read

WordPress Integration

Add privacy-focused analytics to your WordPress site. Track visitors, understand behaviour, and grow your audience without compromising privacy.

Manual setup only. Zenovay does not currently provide an official WordPress plugin or WooCommerce extension. The instructions below use the standard tracking script with snippets in header.php / functions.php, which work reliably on every WordPress install. Wherever you see references to "automatic tracking" below, it means a single add_action() hook that you paste into your theme — not an installable plugin.


Quick Start

MethodBest ForSetup Time
header.php snippetCustom themes3 minutes
functions.php hookDeveloper-managed sites with admin exclusion5 minutes
wp_enqueue_scriptSites that strictly use WordPress script enqueueing5 minutes

Add to your theme's header.php before </head>:

<!-- Zenovay Analytics -->
<script defer data-tracking-code="YOUR_TRACKING_CODE" src="https://api.zenovay.com/z.js"></script>

This is the simplest install. Works on all themes that have a header.php file and the </head> tag visible in the template.


Method 2: functions.php hook

For more control (exclude admin users, conditional loading, etc.), add to your theme's functions.php:

/**
 * Add Zenovay Analytics tracking script
 */
function zenovay_tracking_script() {
    // Don't track admin users (optional)
    if (current_user_can('manage_options')) {
        return;
    }

    ?>
    <script defer data-tracking-code="YOUR_TRACKING_CODE" src="https://api.zenovay.com/z.js"></script>
    <?php
}
add_action('wp_head', 'zenovay_tracking_script');

Method 3: wp_enqueue_script

For proper script management following WordPress conventions:

/**
 * Enqueue Zenovay Analytics script
 */
function zenovay_enqueue_scripts() {
    if (current_user_can('manage_options')) {
        return;
    }

    wp_enqueue_script(
        'zenovay-analytics',
        'https://api.zenovay.com/z.js',
        array(), // No dependencies
        null,    // No version (external script)
        false    // Load in header
    );

    add_filter('script_loader_tag', function($tag, $handle) {
        if ('zenovay-analytics' === $handle) {
            return str_replace(' src', ' defer data-tracking-code="YOUR_TRACKING_CODE" src', $tag);
        }
        return $tag;
    }, 10, 2);
}
add_action('wp_enqueue_scripts', 'zenovay_enqueue_scripts');

WooCommerce Tracking

Track product views, add-to-cart, and purchases on your WooCommerce store. Add to your theme's functions.php:

/**
 * Zenovay WooCommerce Event Tracking
 */

// Track product views
function zenovay_track_product_view() {
    if (!is_product()) return;

    global $product;
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        if (window.zenovay) {
            window.zenovay('track', 'product_viewed', {
                product_id: '<?php echo esc_js($product->get_id()); ?>',
                product_name: '<?php echo esc_js($product->get_name()); ?>',
                price: <?php echo $product->get_price(); ?>,
                currency: '<?php echo get_woocommerce_currency(); ?>',
                category: '<?php echo esc_js(wc_get_product_category_list($product->get_id())); ?>'
            });
        }
    });
    </script>
    <?php
}
add_action('wp_footer', 'zenovay_track_product_view');

// Track add to cart
function zenovay_track_add_to_cart($cart_item_key, $product_id, $quantity) {
    $product = wc_get_product($product_id);
    ?>
    <script>
    if (window.zenovay) {
        window.zenovay('track', 'add_to_cart', {
            product_id: '<?php echo esc_js($product_id); ?>',
            product_name: '<?php echo esc_js($product->get_name()); ?>',
            price: <?php echo $product->get_price(); ?>,
            quantity: <?php echo $quantity; ?>,
            currency: '<?php echo get_woocommerce_currency(); ?>'
        });
    }
    </script>
    <?php
}
add_action('woocommerce_add_to_cart', 'zenovay_track_add_to_cart', 10, 3);

// Track purchases on thank you page
function zenovay_track_purchase($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    // Only track once
    if ($order->get_meta('_zenovay_tracked')) return;
    $order->update_meta_data('_zenovay_tracked', true);
    $order->save();

    $items = array();
    foreach ($order->get_items() as $item) {
        $items[] = array(
            'product_id' => $item->get_product_id(),
            'name' => $item->get_name(),
            'price' => $item->get_total(),
            'quantity' => $item->get_quantity()
        );
    }
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        if (window.zenovay) {
            window.zenovay('track', 'purchase', {
                transaction_id: '<?php echo esc_js($order->get_order_number()); ?>',
                revenue: <?php echo $order->get_total(); ?>,
                currency: '<?php echo $order->get_currency(); ?>',
                tax: <?php echo $order->get_total_tax(); ?>,
                shipping: <?php echo $order->get_shipping_total(); ?>,
                items: <?php echo json_encode($items); ?>
            });
        }
    });
    </script>
    <?php
}
add_action('woocommerce_thankyou', 'zenovay_track_purchase');

Contact Form Tracking

Contact Form 7

function zenovay_track_cf7_submission($contact_form, $result) {
    if ($result['status'] !== 'mail_sent') return;
    ?>
    <script>
    if (window.zenovay) {
        window.zenovay('track', 'form_submitted', {
            form_id: '<?php echo esc_js($contact_form->id()); ?>',
            form_name: '<?php echo esc_js($contact_form->title()); ?>'
        });
    }
    </script>
    <?php
}
add_action('wpcf7_mail_sent', 'zenovay_track_cf7_submission', 10, 2);

Or use the JavaScript event:

document.addEventListener('wpcf7mailsent', function(event) {
    if (window.zenovay) {
        window.zenovay('track', 'form_submitted', {
            form_id: event.detail.contactFormId,
        });
    }
});

Gravity Forms

function zenovay_track_gf_submission($entry, $form) {
    ?>
    <script>
    if (window.zenovay) {
        window.zenovay('track', 'form_submitted', {
            form_id: '<?php echo esc_js($form['id']); ?>',
            form_name: '<?php echo esc_js($form['title']); ?>'
        });
    }
    </script>
    <?php
}
add_action('gform_after_submission', 'zenovay_track_gf_submission', 10, 2);

WPForms

function zenovay_track_wpforms_submission($fields, $entry, $form_data) {
    ?>
    <script>
    if (window.zenovay) {
        window.zenovay('track', 'form_submitted', {
            form_id: '<?php echo esc_js($form_data['id']); ?>',
            form_name: '<?php echo esc_js($form_data['settings']['form_title']); ?>'
        });
    }
    </script>
    <?php
}
add_action('wpforms_process_complete', 'zenovay_track_wpforms_submission', 10, 3);

Identify logged-in users

Identify WordPress users for cross-session tracking:

function zenovay_identify_user() {
    if (!is_user_logged_in()) return;

    $user = wp_get_current_user();
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        if (window.zenovay) {
            window.zenovay('identify', {
                userId: '<?php echo esc_js($user->ID); ?>',
                email: '<?php echo esc_js($user->user_email); ?>',
                name: '<?php echo esc_js($user->display_name); ?>'
            });
        }
    });
    </script>
    <?php
}
add_action('wp_footer', 'zenovay_identify_user');

First-Party Tracking Setup

Bypass ad blockers by proxying through your domain. See the First-Party Tracking Guide for the cross-platform setup. WordPress-specific rewrite rules:

/**
 * Add rewrite rules for Zenovay first-party proxy
 */
function zenovay_add_rewrite_rules() {
    add_rewrite_rule('^_z/script\.js$', 'index.php?zenovay_proxy=script', 'top');
    add_rewrite_rule('^_z/event$', 'index.php?zenovay_proxy=event', 'top');
}
add_action('init', 'zenovay_add_rewrite_rules');

function zenovay_query_vars($vars) {
    $vars[] = 'zenovay_proxy';
    return $vars;
}
add_filter('query_vars', 'zenovay_query_vars');

function zenovay_proxy_handler() {
    $proxy = get_query_var('zenovay_proxy');
    if (!$proxy) return;

    if ($proxy === 'script') {
        header('Content-Type: application/javascript');
        echo file_get_contents('https://api.zenovay.com/z.js');
        exit;
    }

    if ($proxy === 'event') {
        $response = wp_remote_post('https://api.zenovay.com/e/' . $_GET['tracking_code'], [
            'body' => file_get_contents('php://input'),
            'headers' => ['Content-Type' => 'application/json']
        ]);

        header('Content-Type: application/json');
        echo wp_remote_retrieve_body($response);
        exit;
    }
}
add_action('template_redirect', 'zenovay_proxy_handler');

Then update your tracking script to use the proxy:

<script defer
    data-tracking-code="YOUR_TRACKING_CODE"
    data-api-url="/_z/"
    src="/_z/script.js">
</script>

After adding the rewrite rules, go to Settings → Permalinks and click Save Changes to flush the rewrite cache.


Cache Plugin Compatibility

Exclude the Zenovay first-party routes from your cache plugin so events post through correctly.

WP Super Cache

Add to wp-content/wp-cache-config.php:

$cache_rejected_uri = array(
    '/_z/',
);

W3 Total Cache

Go to Performance → Page Cache and add /_z/ to Never cache the following pages.

LiteSpeed Cache

LiteSpeed Cache → Cache → Excludes → Do Not Cache URIs:

/_z/

WP Rocket

Settings → WP Rocket → Advanced Rules → Never Cache URL(s):

/_z/(.*)

WP Fastest Cache

WP Fastest Cache → Exclude → Exclude Pages — add /_z/.


Multisite Configuration

For WordPress Multisite networks, the tracking script lives in your theme's header.php or functions.php and works per-site as configured. To use a single tracking code across the whole network:

/**
 * Use a single tracking code across the multisite network
 */
function zenovay_network_tracking_code() {
    return 'YOUR_NETWORK_TRACKING_CODE';
}
add_filter('zenovay_tracking_code', 'zenovay_network_tracking_code');

Otherwise, configure a different tracking code per site by hardcoding it in each site's theme.


Performance Notes

The Zenovay tracker is:

  • Deferred — doesn't block page rendering
  • Lightweight — < 23 KB gzipped
  • CDN-delivered — globally cached at the edge

Conditional Loading

Skip tracking on specific pages:

function zenovay_conditional_loading() {
    if (is_admin()) return;
    if (is_page(array('privacy-policy', 'terms'))) return;
    ?>
    <script defer data-tracking-code="YOUR_TRACKING_CODE" src="https://api.zenovay.com/z.js"></script>
    <?php
}
add_action('wp_head', 'zenovay_conditional_loading');

Troubleshooting

Script not loading

  1. View the page source (Cmd/Ctrl+U) and look for <script defer data-tracking-code=...> between <head> and </head>
  2. Verify your tracking code matches the value in the Zenovay dashboard
  3. Open the browser console and check for JavaScript errors
  4. Temporarily disable caching to test
  5. Check whether a security plugin (Wordfence, iThemes Security, etc.) is blocking external scripts to api.zenovay.com

Duplicate page views

  • Make sure you added the snippet only once (don't paste in both header.php AND a functions.php hook)
  • Check for AJAX-loaded content re-triggering tracking
  • Review caching plugin configuration

WooCommerce purchases missing

  • Verify the snippet loads on the thank-you page
  • Check the WooCommerce checkout flow (multi-page vs single-page) — some checkouts skip the standard woocommerce_thankyou hook
  • Make sure jQuery compatibility mode isn't interfering

Caching issues

  • Exclude /_z/ routes from page cache (see Cache Plugin Compatibility above)
  • Clear all caches after configuration changes
  • Test in incognito/private browsing mode

Security Considerations

Content Security Policy

If your site uses a CSP header, allow Zenovay:

script-src 'self' https://api.zenovay.com;
connect-src 'self' https://api.zenovay.com;

With first-party proxy, only 'self' is needed.

Excluding Sensitive Pages

function zenovay_should_track() {
    if (is_admin()) return false;
    if (is_page(array('my-account', 'checkout'))) return false;
    if (current_user_can('manage_options')) return false;
    return true;
}

Privacy Compliance

For cookieless tracking, add data-cookieless="true":

<script defer
    data-tracking-code="YOUR_TRACKING_CODE"
    data-cookieless="true"
    src="https://api.zenovay.com/z.js"></script>

In this mode no cookies or local storage entries are set — visitor IDs live only for the current tab. See the Privacy Compliance Guide for full detail.

With popular consent plugins:

// CookieYes — load tracking after consent
document.addEventListener('cookieyes_consent_update', function(e) {
    if (e.detail.accepted.includes('analytics')) {
        var s = document.createElement('script');
        s.defer = true;
        s.src = 'https://api.zenovay.com/z.js';
        s.dataset.trackingCode = 'YOUR_TRACKING_CODE';
        document.head.appendChild(s);
    }
});

// Complianz — same pattern
document.addEventListener('cmplz_fire_statistics', function() {
    var s = document.createElement('script');
    s.defer = true;
    s.src = 'https://api.zenovay.com/z.js';
    s.dataset.trackingCode = 'YOUR_TRACKING_CODE';
    document.head.appendChild(s);
});

See GDPR Compliance Guide for detailed setup.



Need help? Contact [email protected] or visit our Help Center.

Was this page helpful?