Browse help topics

Tracking & results

Tracking & attribution

Connect site visits, conversions, and revenue to your campaigns with one Adwave tracking snippet per business.

From an ad to a measured result
  1. 01Ad exposure

    A person sees or clicks an ad.

  2. 02Website visit

    Your business’s tag records a visit.

  3. 03Conversion

    A configured action records a result.

  4. 04Reporting

    Credit and assists appear separately.

A reported conversion is not proof of an incremental sale. Lift experiments answer a different question.

On this page

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. If you 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:

Checking that the code is live

The Tracking page has a health card that answers one question: is the code working? It shows the last visit, the last win, how many posts were turned away because they came from a different address than your website, and what reached each ad platform in the last 30 days. Under it is the one thing to do next, in plain words.

  1. Click Send a test ping. This creates a one-time code that is good for ten minutes.
  2. Click Open your site with the test link. Your site opens in a new tab with the code attached to the address. The tag on that page sends the code back, and nothing else.
  3. Return to the Tracking page. The card reads Receiving within about ten seconds of the page loading. No reload needed.

If the link expires before your site reaches us, the most common causes are the code not being on the page you opened, a theme or plugin update that removed it, or the site running on a different address than the one in your business profile. That last case shows up in the Turned away count, together with the address the posts came from.

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”). Adwave 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. Suggested rules take effect only after you approve them. The recommended automatic visit and form tracking settings are on by default.

Under the hood, conversions come from four places:

  • Conversion rules: match a URL (or a phone-number tap) and Adwave 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 WooCommerce, Zapier, WhatConverts, and Gravity Forms. Connect Stripe on Tracking to import customers; that connection does not record purchases.

Refunds and value changes

When an order is refunded, cancelled, or its amount changes, send the same webhook with the order id and the name refund or adjust. We never record a second conversion: the original is marked and supported ad platforms receive a correction. A refund without an amount reverses the whole order; a refund with an amount lowers the recorded value; adjust sets a new value.

// Full refund of order 1001 (the conversion stops counting).
{ "name": "refund", "orderId": "1001" }

// Partial refund: 20.00 back on a 50.00 order (now worth 30.00).
{ "name": "refund", "orderId": "1001", "value": 20 }

// The order was edited to 75.00.
{ "name": "adjust", "orderId": "1001", "value": 75 }

Include vendorEventId when your platform can send the same refund twice; a repeat with the same id is ignored. An order id we have never seen answers 202 with unmatched_adjustment. Supported store integrations send these updates automatically. Check the integration's setup for the events it supports.

Calls

Phone calls count as conversions when your pages show a tracking number. Every campaign gets its own number, forwarded to yours, so a completed call of at least the minimum length is recorded as a completed call for that campaign and lands in your leads inbox.

Visitors who arrive from an ad also get a number of their own for the length of their visit: the tag swaps the number on the page from a small pool we keep for your website, and a call to that number is tied to the exact visit, click, and ad that brought the caller. The pool grows and shrinks with your traffic (four to twenty numbers) and is released after two months without ad visits. When every pool number is in use, the page shows the campaign number.

Ad platforms only ever receive the caller's own click. A call we can match to a visit or to a known contact carries that click; a call we can only place on a campaign is credited to the campaign and sent without a click id.

WhatConverts

Paste your per-website WhatConverts URL from Tracking (Install → Connect your store → WhatConverts) into WhatConverts at Tracking → Integrations → Automations → Webhooks. Turn on New and Update. Choose completed lead types (Phone Call, Web Form, Chat, Custom Event, and the rest). Do not turn on In Progress.

We record the lead and send it to Google or Meta only when it is not spam, not a duplicate, and not marked not quotable. Turn off WhatConverts' own Google Ads upload so the same lead is not sent twice. Leave Meta CAPI on. We send the same event_id the browser pixel uses so Meta dedupes the pair. Leave WhatConverts Facebook on for phone and chat. Turn WhatConverts Facebook off for website forms only if Events Manager shows two Leads for the same form. If a lead is marked spam after we already sent it to Google, Google keeps that retraction. We still correct our own numbers.

Gravity Forms

Tracking → Install → Gravity Forms gives you a signed form address. In Gravity Forms, Form Settings → Webhooks, POST JSON to that URL. The path token is the secret. Map {entry_id} to entryId (or send entry_id / numeric id). Include name plus email or phone. A second POST with the same entry is ignored.

Optional: send Authorization: Bearer with the same token as the URL. If the form is in an iframe, copy the page query (utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid) onto the iframe src and as hidden fields so the webhook can send them.

Hosted landing page forms

Forms on the landing pages we host for you carry a small Cloudflare Turnstile check. Most visitors never see a challenge; it runs quietly in the page and helps reduce automated spam in your leads inbox. Every submission is verified on our servers before it becomes a lead, is emailed to you, or is sent to your CRM.

Two more guards run behind the scenes: a submission has to come from the page it belongs to, and a sudden burst of submissions on one page is kept but marked suspect. Held leads appear in your inbox with a Held label and a reason; they are not counted and not sent to ad platforms.

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 a dash, and Autopilot still optimizes for cost per conversion.

  • Purchases: pass the real order amount in a track call, use the Shopify app, or install the WooCommerce paid-order recipe. Stripe payments need a server integration or Zapier mapping to the documented conversion format; native Stripe webhooks are not accepted directly.
  • Leads and signups: on Tracking, use Set what a win is worth on each goal (or on Form conversions: lead, signup, subscribe). Form conversion values also cover hosted pages, Instant Forms and completed calls. 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).

The tag API

Once the snippet is installed, every page has a global waverunner() function with four 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 });

// Confirm the install from the browser console. The Tracking page
// gives you a one-time code; the tag sends that code and nothing else.
waverunner("ping", "CODE_FROM_THE_TRACKING_PAGE");
  • 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 connects browser visits with 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.
  • ping is the manual form of the test link described under checking that the code is live. Each code works once and expires after ten minutes.

How attribution works

  • Last-touch: a conversion is credited to the most recent qualifying touch. That stamp determines attributed results and ROAS. Wallet charges follow your prepaid daily budget and delivery reconciliation. 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. Reported conversion revenue 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 Adwave tracking snippet; you do not need a separate Google conversion snippet on the page. Our house tag already writes utm_source=adwave-meta on Meta clicks. Google Analytics will not file that source as Paid Social on its own. Add a custom GA4 channel for adwave-meta if you want that label in your property.

The click id on landing links

Every ad we run sends people to your site through a short redirect that appends a first-party click id to the landing link. The tag reads it on the first page, so the visit, and any win that follows, can be credited to the exact ad. Tracking's Signal tab shows Landing links are missing the click id when ad clicks arrive but no visit carries one: a redirect on your side (a www to non-www hop, a trailing-slash rule, a consent page that reloads without the query string) is stripping it. Keep the query string through every redirect, or land the ads on the final address so no redirect runs.

Cookies the tag sets

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

Cookie Purpose Lifetime
_wr_vid Visitor ID: recognizes a returning browser 365 days
_wr_sid Session ID: groups a visit 30 minutes, sliding
_wr_cid Click ID: links a visit to the ad click that caused it 30 days
_wr_aid Ad ID: which specific ad drove the click 30 days
_wr_li Line ID: which audience line of the campaign the click came from 30 days
_wr_camp Campaign ID: which campaign the click came from 30 days
_wr_utm Session UTM parameters (source, medium, campaign, term, content). Last campaign-tagged landing in the session wins. 30 minutes, sliding
wr_consent Set only when your site calls the tag's consent API; records whether the visitor declined ad-platform sharing 365 days

When Adwave 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. Conversion attribution still uses the first-party click id, not UTMs.