Browse the docs

Tracking & attribution

Measurement for an always-on performance stack: one first-party script ties site visits, conversions, and revenue back to your campaigns, with no per-channel pixels to configure.

Installing the tag

The Tracking page in the app gives you a personalized snippet with your site token. It goes in your site’s <head>:

<script async src="https://waverunner.adwave.com/t/YOUR_SITE_TOKEN"></script>
  • One tag per website: each business in your account has its own snippet, conversion rules, webhook, and settings. Run more than one site? Use the switcher on the Tracking page to pick the right one.
  • The tag is SPA-aware: it tracks route changes in single-page apps automatically.
  • Recommended settings (per website, on by default): automatic capture of clicks and form submits, Form conversions (success-gated signup/lead/subscribe), and origin enforcement. Turning any of these off asks you to confirm the impact on Autopilot and tracking. You can restore all recommended settings in one click.

Step-by-step install guides, written for non-technical readers:

Defining conversions

The easiest way to set up conversions: on the Tracking page, describe what counts as a win in plain language (“a purchase: people land on an order confirmation page”). Waverunner analyzes your site’s recent traffic and proposes evidence-backed rules you approve with one click. It also watches for conversion-looking pages on its own and asks whether to track them. Nothing is ever tracked without your say-so.

Under the hood, conversions come from four places:

  • Conversion rules: match a URL (or a phone-number tap) and Waverunner records the conversion, no code needed. Approving a suggestion creates one of these; you can also add them manually. Each rule has a trigger so a bare page visit is never mixed up with completing something:
    • Page reach: someone lands on a confirmation page (classic thank-you URL).
    • Form then page: someone submits a form and lands on the page within a minute (needs Autocapture on).
    • Checkout return: someone comes back from a hosted checkout (Stripe, PayPal, and similar). Same-domain checkouts (for example many Shopify stores) still use a thank-you page rule or the purchase webhook.
    • Phone tap: someone taps a tel: link. That counts call intent, not a completed call.
    Rules are per website: a rule you add for one site never fires on another. Prefer confirmation pages over form-entry URLs like /signup. For purchases, a server-side webhook remains the most reliable path when you can wire it.
  • Form conversions: with autocapture + Form conversions enabled, a successful marketing form submit (HTTP 2xx with success UI, or a thank-you navigation) records signup, lead, or subscribe, not every bare submit or form-page visit. No thank-you URL required.
  • The tag API: fire a conversion event from your frontend with a value, currency, and order ID (order IDs de-duplicate automatically).
  • Server-side webhooks: a per-website webhook URL accepts conversions from your backend, with ready-made recipes for Shopify, Stripe, WooCommerce, and Zapier.

What a win is worth

Cost per conversion works as soon as conversions count. Return on ad spend (ROAS) needs a dollar value on those wins. We never invent a platform default: until you set a value, ROAS shows an honest dash, and Autopilot still optimizes for cost per conversion.

  • Purchases: pass the real order amount in a track call, or connect Shopify / WooCommerce / Stripe so the webhook carries exact totals.
  • Leads and signups: on Tracking, use Set what a win is worth on each goal (or on Form conversions: lead, signup, subscribe). Not selling directly? Estimate from close rate: if about one in ten signups becomes a $500 customer, a signup is worth roughly $50. Reports label that revenue as estimated. You can change or clear an estimate anytime.
  • Real amounts win: if the same conversion name arrives with a value from track, a webhook, or an order-grade page total, that number is used and the Tracking estimate is ignored for that event. Estimates only fill in when the event carries no value. Different names stay independent (purchase does not use a signup estimate).
Values apply to new conversions only. Changing an estimate does not rewrite history.

The tag API

Once the snippet is installed, every page has a global waverunner() function with three commands:

// Record a conversion. Value is in dollars; the optional orderId
// makes the same purchase count once even if it is reported twice
// (for example by this call and your store's webhook).
waverunner("track", "purchase", { value: 129.99, orderId: "1001" });

// Tell us who the visitor is when you learn it (sign-in, checkout).
// This links the browser to that email, so conversions your backend
// sends later still connect to the ad that brought them, even from
// another device. Emails are stored only as salted one-way hashes.
waverunner("identify", "customer@example.com");

// Wire in your cookie banner: declined visitors get the same
// do-not-share treatment as Global Privacy Control.
waverunner("consent", { adSharing: userAcceptedAdCookies });
  • track accepts any conversion name you choose, plus optional value, currency, and orderId.
  • identify takes an email string, or an object with email, phone, firstName, and lastName. It is the glue between browser visits and server-side webhook conversions: without it, a backend-reported sale can only match through the same browser.
  • consent stores the visitor's choice for a year. Measurement for your own reports continues either way; declining stops all sharing with ad platforms.

How attribution works

  • Last-touch: a conversion is credited to the most recent qualifying touch. That stamp drives billed results, wallet charges, and ROAS. All touches are still stored.
  • Clicks beat views: ad clicks carry a first-party click ID (30-day window) and always win over view-through exposure.
  • View-through: TV and web display impressions are recorded by a first-party pixel; the view-through window is configurable at 7, 14, or 30 days.
  • Comparison models on Tracking: when someone sees more than one of your ads before converting, Tracking shows how first touch, last touch, linear, time decay, position, and data-driven models would split the same dollars. Those columns are for learning only. Money and ROAS stay on last touch.
  • Assisted conversions: on a campaign's Performance tab, assists show when another channel touched someone earlier (click, household view, or person-resolved view) before a different channel got last-touch credit. Assists are reporting-only and never change wallet charges or ROAS. Details: Assisted conversions and Lift.
  • Closed loop: attributed conversions are forwarded to Meta (Conversions API) and Google (offline click-conversion uploads). For Google, those offline uploads are the primary signal used for bidding. When Google Ads is connected, the tag also loads a sitewide Google tag (AW config) and may fire observation-only website conversion events that share the same transaction id — they do not double-count against the offline primary. Install our first-party tag; you do not need a separate Google conversion snippet on the page.

Cookies the tag sets

All cookies are first-party, set on your own domain:

CookiePurposeLifetime
_wr_vidVisitor ID: recognizes a returning browser365 days
_wr_sidSession ID: groups a visit30 minutes, sliding
_wr_cidClick ID: links a visit to the ad click that caused it30 days
_wr_aidAd ID: which specific ad drove the click30 days
_wr_utmSession UTM parameters (source, medium, campaign, term, content). Last campaign-tagged landing in the session wins.Session

When Waverunner adds UTM parameters on an ad click-through (for your own analytics tools), utm_campaign is a readable slug from the campaign name plus a short id (for example summer-sale-3f2a), not the raw campaign UUID. Existing UTM parameters already on your landing URL are never overwritten. Money attribution still uses the first-party click id, not UTMs.

Emails and IP addresses are hashed with a salt before storage; Waverunner never stores raw personal identifiers from your visitors. See the privacy policy for the full data-handling picture.