WebTracker docs

WebTracker tracks three things: web traffic, downloads and sales. Traffic and downloads come from a tiny script in your pages; sales come from your server as events. Everything lands in the same event stream, so revenue, campaigns and downloads can be compared side by side.

1. Add the tracking snippet

Paste this into your site's <head>. Replace wbf_xxx with the tracking ID shown for your site in Sites.

<script async src="https://webtracker.app/w.js" data-site="wbf_xxx"></script>

The script is cookie-free: it uses a first-party anonymous ID and a session ID, records pageviews (including single-page-app route changes), referrers, device, OS and country, and stores UTM parameters for the whole session so campaign attribution survives redirects.

2. Track custom events

Call webtracker from anywhere on the page. Any properties you pass are stored with the event and become selectable columns in the Events panel.

window.webtracker('track', 'Signup', { plan: 'pro' });
window.webtracker('track', 'Trial started', { product: 'iCash' });

3. Download tracking

Downloads are first-class in WebTracker. The script automatically sends a Download event when a visitor clicks a link to a downloadable file (.dmg, .exe, .zip, .pkg, .msi, and similar). The Downloads panel then shows totals for today, this week, this month and all time — each compared with the previous period — plus top files, operating systems and countries.

To record a download from your own code (for example a server-side download script or a button that streams a file), send the event yourself:

window.webtracker('track', 'Download', {
  file: 'MaxBulkMailer.dmg',
  product_name: 'MaxBulk Mailer',
  version: '8.7.2',
  os: 'macOS'
});

Country is filled in automatically from the request when you don't provide one.

4. Sales: server-side events

Sales are tracked with a Sale event sent from your server — your order script, your payment callback, or your IPN handler. Server-side means no ad blocker and no browser required, and it works with any payment provider (Stripe, PayPal, FastSpring, CoinPayments, bank transfer, manual orders…).

EndpointPOST https://webtracker.app/api/public/collect/event with a JSON body:

{
  "tid": "wbf_xxx",
  "name": "Sale",
  "path": "/checkout/complete",
  "props": {
    "transaction_id": "9GH12345XY",
    "sku": "MBM-PRO",
    "quantity": 1,
    "product_name": "MaxBulk Mailer Pro",
    "customer_name": "Jane Doe",
    "customer_email": "jane@example.com",
    "invoice_number": "INV-10231",
    "store_name": "PayPal",
    "country_code": "US",
    "os": "macOS",
    "amount_cents": 8900,
    "currency": "USD",
    "profit_cents": 7600
  }
}

amount_cents and profit_cents are integers in the smallest unit of currency. Non-USD amounts are converted to USD for reporting.transaction_id is what makes an order unique, so retries and imports never create duplicates.

Example in PHP:

$payload = json_encode([
  'tid'  => 'wbf_xxx',
  'name' => 'Sale',
  'props' => [
    'transaction_id' => $txn,
    'sku'            => $sku,
    'quantity'       => (int) $qty,
    'product_name'   => $product,
    'customer_email' => $email,
    'store_name'     => 'PayPal',
    'country_code'   => $country,
    'amount_cents'   => (int) round($amount * 100),
    'currency'       => $currency,
    'profit_cents'   => (int) round($profit * 100),
  ],
]);

$ch = curl_init('https://webtracker.app/api/public/collect/event');
curl_setopt_array($ch, [
  CURLOPT_POST           => true,
  CURLOPT_POSTFIELDS     => $payload,
  CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT        => 30,
]);
$res  = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 200 = stored. Anything else: queue the payload and retry later.

The endpoint only answers 200 when the event is stored. Treat any other status as "not recorded yet" and retry — the recommended pattern is to append the JSON payload to a local queue_events/ folder and flush it from a cron job, so a slow network never loses a sale. The Integrations panel in the app has ready-made cURL, PHP, Python and Node.js snippets with your real tracking ID.

5. Refunds

Send a Refund event with the same transaction_id as the original sale. The order is marked refunded and refunded amounts are excluded from net revenue while remaining visible in the refund totals.

{ "tid": "wbf_xxx", "name": "Refund", "props": { "transaction_id": "9GH12345XY", "amount_cents": 8900, "currency": "USD" } }

6. Import historical sales

Have years of orders in a spreadsheet or a database export? Use Sales → Import to upload a CSV and map the columns. Common export headers are detected automatically, foreign currencies are converted to USD, and rows whose transaction ID already exists are skipped. The same importer handles refund files.

7. Reading the panels

  • Dashboard — live visitors, pageviews, top pages, referrers, countries, devices and 30-day revenue.
  • Sales — revenue and orders for today, this week, this month and all time, each compared with the previous period, plus an order list with the columns you choose. Analytics adds trends by product, store, country and currency.
  • Downloads — download volume over time with top files, OS and country breakdowns.
  • Campaigns — UTM source, medium and campaign performance with attached revenue.
  • Events — the raw stream: filter by event type and pick which properties to show as columns.
  • Sites — tracking IDs, plus health, status and domain checks per site.

8. Settings that affect every number

In Settings you choose your timezone and whether the week starts on Monday or Sunday. Every "today", "this week" and "this month" figure across Sales, Downloads and Dashboard is calculated with those settings, so your reports match your own calendar.