Back to home

Tracking Documentation

Complete guide to installing and configuring the CRO9 behavioral tracker

Quick Start

Add this script tag before the closing </body> tag on any page you want to track:

<script
  src="https://www.cro9.com/cro9-tracker.js"
  data-api-key="YOUR_API_KEY"
  data-endpoint="https://www.cro9.com/api/track/collect"
  data-consent-mode="gdpr">
</script>
Get your API key from Settings → Tracking

Configuration Options

AttributeValuesDefaultDescription
data-api-keyStringRequiredYour unique CRO9 API key
data-consent-modegdpr, ccpa, essential, disabledgdprPrivacy compliance mode
data-endpointURLhttps://www.cro9.com/api/track/collectWhere events are sent. Keep the www host — beacons cannot follow a redirect.
data-auto-conversionstrue, falsetrueCount every form submit as a conversion. Set false if you call CRO9.conversion() yourself.
data-debugtrue, falsefalseEnable console logging

Next.js / React Integration

For single-page applications, use the Script component for proper loading:

import Script from 'next/script'

export default function Layout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src="https://www.cro9.com/cro9-tracker.js"
          data-api-key={process.env.NEXT_PUBLIC_CRO9_KEY}
          data-endpoint="https://www.cro9.com/api/track/collect"
          data-consent-mode="gdpr"
          strategy="afterInteractive"
        />
        {/* Route changes are tracked automatically (pushState is patched).
            Apps that switch screens by state, not URL, call CRO9.page('/screen'). */}
      </body>
    </html>
  )
}

JavaScript API

Once loaded, interact with the tracker via window.CRO9:

Track Custom Events

// Track a custom event
CRO9.track('button_click', {
  buttonId: 'pricing-cta',
  variant: 'A',
  value: 99
});

Conversions and Purchases

Form submits are counted automatically. Everything else that is worth money is a call you make on the page where it happened — first-party, from the visitor's own session.

// A goal reached — a booked call, a signup, a quote request.
// value and currency are optional; meta rides along into the event.
CRO9.conversion('booked_call', 250, 'USD', { source: 'calendly' })

// A sale, with the money on it. Deduped on transactionId, so a reloaded
// thank-you page never sells the same thing twice.
CRO9.purchase({
  transactionId: order.id,
  value: 39,
  currency: 'USD',
  plan: 'command',
  items: [{ id: 'command_monthly', name: 'Command (monthly)' }],
})

Revenue Truth (Stripe)

Connect your Stripe account on the Connections page and every settled charge, refund and dispute becomes a conversion on the session that produced it. Two metadata fields make the match exact; without them CRO9 falls back to the customer's email from identify().

// REVENUE TRUTH. Put the tracker's ids on the Stripe object you create,
// and CRO9 attributes the settled charge — and any refund — to the visitor
// who paid, once you connect Stripe on the Connections page.
const session = await stripe.checkout.sessions.create({
  // …your line items…
  metadata: {
    cro9_vid: cro9VisitorId,   // from CRO9.getVisitorId() on the page
    cro9_sid: cro9SessionId,   // from CRO9.getSessionId()
  },
})

Single-Page Apps

// URL-driven apps need nothing: pushState / popstate are patched and
// every route change is a page_view. Apps that switch screens by state
// (tabs, wizards) report the screen themselves:
CRO9.page('/today')
CRO9.page('/settings/api', { section: 'keys' })

Identify Users

// Identify a user (requires consent)
CRO9.identify('user_123', {
  email: 'user@example.com',
  name: 'John Doe',
  plan: 'pro'
});

Exit Intent Hook

// Listen for exit intent
window.addEventListener('cro9:exitIntent', () => {
  // Show your exit popup
  showExitPopup();
});

Need Help?