# EngageTrack Documentation
> EngageTrack is a privacy-first web analytics platform with revenue attribution, funnels, goals, and a full REST API.
---
URL: https://engagetrack.net/docs/getting-started.md
---
title: Getting Started
description: Set up EngageTrack analytics on your website in minutes. Here's how to get started in 4 steps.
order: 1
---
# Grow your business with EngageTrack in 4 steps
Set up EngageTrack analytics on your website in minutes to find your best marketing channels and grow your business. Here's how to get started in 4 steps:
## 1/ Install tracking script
Create a new website and add the tracking script to the `
` section of your website:
```html
```
Need to customize the script? Check the [script configuration
reference](/docs/advanced/script-configuration) for all available options like
localhost tracking, cross-domain setup, custom API endpoints, and more.
### Installation tutorials
## 2/ Connect a payment provider
Link your Stripe, LemonSqueezy, Paddle, or Polar account to automatically track revenue and attribute it to your marketing channels.
→ [Connect payment providers](/docs/revenue-attribution/overview)
## 3/ Set up custom events
Track conversions, button clicks, and form submissions with custom goals:
```html
```
```js
// Track a custom goal via HTML attribute
//
// Or track programmatically
window.engagetrack("signup_click", { method: "google" });
// Track revenue
window.engagetrack.trackPurchase("order_123", 29.99, "USD");
```
→ [Track custom goals](/docs/tracking/goals)
→ [Track custom events](/docs/tracking/custom-events)
## 4/ Invite your team
Collaborate with your team by inviting members to your organization dashboard.
→ [Invite team members](/docs/team/invitations)
## Next steps
- [Filter your data](/docs/analytics/filtering) to segment visitors
- [Set up conversion funnels](/docs/tracking/funnels)
- [Configure revenue tracking](/docs/tracking/revenue)
- [Explore the API](/docs/api/authentication)
---
URL: https://engagetrack.net/docs/custom-domain.md
---
title: Custom Domain
description: Proxy the EngageTrack script through your own domain to bypass ad blockers and maximize tracking accuracy.
order: 2
---
# Custom Domain
Some ad blockers block third-party analytics scripts by matching known CDN hostnames like `cdn.engagetrack.net`. Proxying the EngageTrack script through your own domain makes it a first-party resource — ad blockers typically allow first-party traffic.
Custom domain proxying is available on the **Agency plan** only. Upgrade at
**Settings → Billing** to access this feature.
Proxying through a custom domain can improve data accuracy by 10–20% depending
on your audience's ad blocker usage rate.
## How It Works
Without a proxy, your visitors load the script directly from EngageTrack's CDN:
```
https://cdn.engagetrack.net/sdk.js
```
With a custom domain proxy, the script loads from your own subdomain:
```
https://analytics.yourdomain.com/js/sdk.js
```
Your server or CDN forwards those requests to EngageTrack's origin. From the browser's perspective, all traffic stays on your domain — so ad blockers have no hostname to block.
## Setup Options
Choose the approach that matches your infrastructure.
### Nginx Reverse Proxy
Add a `location` block to your Nginx configuration:
```nginx
location /js/ {
proxy_pass https://cdn.engagetrack.net/;
proxy_set_header Host cdn.engagetrack.net;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
}
location /api/event {
proxy_pass https://api.engagetrack.net/event;
proxy_set_header Host api.engagetrack.net;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
```
Reload Nginx after saving: `nginx -s reload`.
### Cloudflare Workers
Deploy a Worker that forwards requests to EngageTrack's origin:
```js
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname.startsWith("/js/")) {
const origin = "https://cdn.engagetrack.net" + url.pathname.replace("/js", "");
return fetch(origin, request);
}
if (url.pathname === "/api/event") {
return fetch("https://api.engagetrack.net/event", request);
}
return new Response("Not found", { status: 404 });
}
```
Deploy via the Cloudflare dashboard or `wrangler publish`.
### Vercel Rewrites
Add a `rewrites` entry to your `vercel.json`:
```json
{
"rewrites": [
{
"source": "/proxy/sdk.js",
"destination": "https://cdn.engagetrack.net/sdk.js"
},
{
"source": "/proxy/event",
"destination": "https://api.engagetrack.net/event"
}
]
}
```
### Netlify Redirects
Add proxy rules to your `_redirects` file:
```
/proxy/sdk.js https://cdn.engagetrack.net/sdk.js 200!
/proxy/event https://api.engagetrack.net/event 200!
```
The `200!` status tells Netlify to proxy the request rather than issue a redirect.
## Update Your Tracking Script
Once your proxy is live, point the tracking script at your custom domain using the `data-api` attribute:
```html
```
Replace `YOUR_SITE_PUBLIC_ID` with your actual site ID from the EngageTrack
dashboard, and replace `analytics.yourdomain.com` with your actual proxy
subdomain.
## Verify It Works
1. Open your browser's DevTools and switch to the **Network** tab.
2. Reload the page.
3. Confirm that `sdk.js` is loaded from your custom domain — not from `cdn.engagetrack.net`.
4. Perform an action that triggers an event (e.g., navigate to another page) and confirm the event request goes to `analytics.yourdomain.com/api/event`.
Add `data-debug="true"` to the script tag to enable console logging. This
shows you exactly which endpoint each event is sent to, which is useful for
verifying your proxy setup.
## Trade-offs
Proxying adds a network hop between your server and EngageTrack's API. For most setups this is negligible, but keep in mind:
- **Latency:** Requests pass through your infrastructure before reaching EngageTrack. Use a geographically distributed edge (Cloudflare Workers, Vercel Edge) to minimise added latency.
- **Bandwidth:** Your proxy handles script and event traffic. At high volumes this may count against your hosting bandwidth quota.
- **Maintenance:** If EngageTrack changes its CDN or API endpoints, you will need to update your proxy configuration.
## Next Steps
- Return to [Getting Started](/docs/getting-started) for the full list of `data-*` configuration attributes including `data-api`.
- See the Configuration Options table in Getting Started for all supported script attributes.
---
URL: https://engagetrack.net/docs/installation/overview.md
---
title: Installation Guides
description: Add EngageTrack analytics to any website or app in under 2 minutes with our lightweight tracking script.
order: 1
---
# Installation Guides
EngageTrack ships as a single **~3 KB** JavaScript snippet that tracks pageviews, outbound links, file downloads, form submissions, scroll depth, and more — with zero device storage by default. No cookies, no `localStorage`, no consent banner needed. Fully GDPR and ePrivacy compliant out of the box.
## Quick Install
Add the script to the `` of any HTML page:
```html
```
That's it. Pageviews are tracked automatically as soon as the script loads.
Find your **Site ID** in the EngageTrack dashboard under **Site Settings → General**.
## Framework Guides
Choose your stack for a step-by-step walkthrough:
| Framework | Guide |
| --------- | ----- |
| **Next.js** | [Install in Next.js (App Router)](/docs/installation/nextjs) |
| **React** | [Install in React (Vite, CRA, etc.)](/docs/installation/react) |
| **Vue.js** | [Install in Vue.js](/docs/installation/vuejs) |
| **Astro** | [Install in Astro](/docs/installation/astro) |
| **WordPress** | [Install on WordPress](/docs/installation/wordpress) |
| **Google Tag Manager** | [Install via GTM](/docs/installation/google-tag-manager) |
## What Gets Tracked Automatically
Once installed, the SDK automatically captures:
- **Pageviews** — every page load and client-side navigation
- **Outbound links** — clicks to external domains
- **File downloads** — common file extensions (pdf, zip, dmg, etc.)
- **Form submissions** — all `
);
}
```
## 5. Astro with SSR
If you're running Astro in SSR mode (with an adapter like `@astrojs/node` or `@astrojs/vercel`), the script tag in your layout works the same way. The `is:inline` directive ensures it renders as plain HTML regardless of rendering mode.
For server-side event tracking, you can read the visitor cookies in your API routes:
```ts
// src/pages/api/convert.ts
import type { APIRoute } from "astro";
export const POST: APIRoute = async ({ cookies }) => {
const visitorId = cookies.get("engagetrack_visitor_id")?.value;
const sessionId = cookies.get("engagetrack_session_id")?.value;
await fetch("https://api.engagetrack.net/api/v1/event", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
site_id: import.meta.env.PUBLIC_ENGAGETRACK_SITE_ID,
name: "server-conversion",
visitor_id: visitorId,
session_id: sessionId,
}),
});
return new Response(JSON.stringify({ ok: true }), { status: 200 });
};
```
## Verify Installation
1. Run `npm run dev` to start the Astro dev server.
2. Open your site and navigate between a few pages.
3. In the EngageTrack dashboard, go to the **Realtime** tab — your visits should appear within seconds.
If you see your pageviews in Realtime, you're all set. If not, add
`data-debug="true"` to the script tag and check the browser console for
diagnostic messages.
---
URL: https://engagetrack.net/docs/installation/wordpress.md
---
title: WordPress
description: Install EngageTrack on your WordPress website.
order: 6
---
# WordPress
Add EngageTrack analytics to your WordPress site. No plugin required — just a single script tag added to your site's header.
## Option A: Insert Headers and Footers Plugin (Easiest)
If you're not comfortable editing theme files, use a plugin to inject the script.
1. Install and activate the **WPCode** plugin (formerly Insert Headers and Footers) from the WordPress plugin directory.
2. Go to **Code Snippets → Header & Footer** in the WordPress admin.
3. Paste the following into the **Header** section:
```html
```
4. Click **Save Changes**.
Replace `YOUR_SITE_ID` with the Site ID from your EngageTrack dashboard (**Site Settings → General**).
## Option B: Edit header.php
If you prefer not to install a plugin, add the script directly to your theme's header file.
1. In the WordPress admin, go to **Appearance → Theme File Editor**.
2. Select your active theme and open `header.php`.
3. Find the closing `` tag and add the script just above it:
```php
```
4. Click **Update File**.
Editing `header.php` directly means your changes will be lost when the theme
updates. To avoid this, use a **child theme** or use the plugin approach
(Option A) instead.
## Option C: wp_enqueue_script in functions.php
For developers who prefer the WordPress way, add the script via `functions.php`:
```php
// functions.php (in your child theme)
function engagetrack_enqueue_script() {
wp_enqueue_script(
'engagetrack',
'https://cdn.engagetrack.net/sdk.js',
array(),
null,
false // Load in header
);
// Add the data-site-id attribute
wp_script_add_data('engagetrack', 'data-site-id', 'YOUR_SITE_ID');
}
add_action('wp_enqueue_scripts', 'engagetrack_enqueue_script');
// Add defer and data attributes to the script tag
function engagetrack_script_attributes($tag, $handle) {
if ('engagetrack' !== $handle) {
return $tag;
}
return str_replace(
' src=',
' defer data-site-id="YOUR_SITE_ID" src=',
$tag
);
}
add_filter('script_loader_tag', 'engagetrack_script_attributes', 10, 2);
```
## Track Goals with HTML Attributes
You can track button clicks and link interactions across your WordPress site using `data-goal` attributes. This works in the WordPress block editor, page builders, and raw HTML:
```html
View Pricing
```
Most page builders (Elementor, Divi, Beaver Builder) let you add custom HTML
attributes to elements. Look for an "Advanced" or "Attributes" section in the
element settings.
## WooCommerce Revenue Tracking
For WooCommerce stores, add a conversion tracking snippet to the order confirmation page. Add this to your child theme's `functions.php`:
```php
function engagetrack_woocommerce_tracking($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
?>
If you see your pageviews in Realtime, you're all set. If not, add
`data-debug="true"` to the script tag and check the browser console for
diagnostic messages.
---
URL: https://engagetrack.net/docs/installation/google-tag-manager.md
---
title: Google Tag Manager
description: Install EngageTrack via Google Tag Manager.
order: 7
---
# Google Tag Manager
If your site already uses Google Tag Manager (GTM), you can deploy EngageTrack without touching your site's source code.
## 1. Create a Custom HTML Tag
1. Open your GTM container and go to **Tags → New**.
2. Name the tag **EngageTrack Analytics**.
3. Click **Tag Configuration** and select **Custom HTML**.
4. Paste the following code:
```html
```
Replace `YOUR_SITE_ID` with the Site ID from your EngageTrack dashboard (**Site Settings → General**).
We create the script dynamically instead of using a static `<script>`
tag because GTM injects Custom HTML tags into the body. The dynamic approach
ensures the script loads with the correct attributes and avoids duplicate
loading.
## 2. Set the Trigger
1. Click **Triggering** and select **All Pages**.
2. This fires the tag on every page load, including both the initial load and subsequent navigations.
## 3. Save and Publish
1. Click **Save** on the tag.
2. Use GTM's **Preview** mode to verify the tag fires correctly.
3. Once verified, click **Submit** to publish the container.
## Goal Tracking via GTM DataLayer
You can fire EngageTrack goals based on GTM dataLayer events. For example, if your site pushes events to the dataLayer:
```javascript
// Your application code
dataLayer.push({
event: "form_submitted",
formName: "contact",
});
```
Create a second Custom HTML tag in GTM to forward these events to EngageTrack:
### Step 1: Create a DataLayer Variable
1. Go to **Variables → User-Defined Variables → New**.
2. Choose **Data Layer Variable**.
3. Set the variable name to `formName`.
4. Name it **DLV - formName** and save.
### Step 2: Create the Forwarding Tag
1. Create a new **Custom HTML** tag named **EngageTrack - Form Goal**.
2. Paste:
```html
```
3. Set the trigger to a **Custom Event** with event name `form_submitted`.
4. Save and publish.
## Track Revenue via DataLayer
If your e-commerce platform pushes purchase data to the dataLayer:
```javascript
dataLayer.push({
event: "purchase",
transactionTotal: 99.99,
transactionCurrency: "USD",
});
```
Create a Custom HTML tag to forward revenue:
```html
```
Set the trigger to a **Custom Event** with event name `purchase`.
Create DataLayer Variables for `transactionTotal` and `transactionCurrency`
the same way as described in Step 1 above.
## Verify Installation
1. Open GTM **Preview** mode and load your website.
2. Confirm the **EngageTrack Analytics** tag fires on "Container Loaded".
3. Navigate between a few pages.
4. In the EngageTrack dashboard, go to the **Realtime** tab — your visits should appear within seconds.
If you see your pageviews in Realtime, you're all set. If not, add
`s.dataset.debug = "true"` to the script creation code (before
`document.head.appendChild`) and check the browser console.
---
URL: https://engagetrack.net/docs/tracking/goals.md
---
title: Goal Tracking
description: Track custom conversions and events with EngageTrack's goal system.
order: 1
---
# Goal Tracking
Goals let you track specific user actions — signups, purchases, button clicks, or any custom event that matters to your business.
## HTML Data Attributes
The simplest way to track goals is with `data-goal` attributes on any HTML element:
```html
View Pricing
```
When a user clicks the element, EngageTrack automatically fires a goal event.
## JavaScript API
### Plain JavaScript
Call `window.engagetrack()` directly or use the `.track()` alias:
```javascript
// Simple goal
window.engagetrack("newsletter-subscribe");
// Goal with custom properties
window.engagetrack("purchase", {
plan: "startup",
interval: "yearly",
amount: "29.99",
});
// Alternative .track() alias
window.engagetrack.track("newsletter-subscribe");
```
### TypeScript / Next.js
Because the SDK is loaded via a `
```
Or if you prefer a single link with manual construction:
```javascript
const visitorId = window.engagetrack?.getVisitorId() || "";
const sessionId = window.engagetrack?.getSessionId() || "";
const paymentLink = `https://buy.stripe.com/aBC123dEfGhI?client_reference_id=${visitorId}&engagetrack_session_id=${sessionId}`;
window.location.href = paymentLink;
```
Although `client_reference_id` is passed through to the checkout session by
Stripe, EngageTrack does **not** currently read this field for attribution.
The snippet below is provided for reference, but it will not result in
attributed revenue. Use the [Stripe Checkout
API](/docs/revenue-attribution/stripe-checkout) for full attribution.
## Step 3: Set Up the Webhook
Follow the same webhook setup as [Stripe Checkout](/docs/revenue-attribution/stripe-checkout#step-2-set-up-the-webhook-in-stripe):
1. Go to [Stripe Dashboard → Developers → Webhooks](https://dashboard.stripe.com/webhooks)
2. Click **Add endpoint**
3. Enter the webhook URL:
```
https://api.engagetrack.net/api/v1/webhooks/revenue/stripe/{YOUR_SITE_PUBLIC_ID}
```
4. Select `checkout.session.completed` and `charge.refunded` events
5. Click **Add endpoint**
## Limitations
Payment Links have some limitations compared to the [Checkout Sessions API](/docs/revenue-attribution/stripe-checkout):
| Feature | Checkout API | Payment Links |
| --- | --- | --- |
| Custom metadata | Full support (key/value pairs) | Limited to `client_reference_id` |
| Subscription metadata | Supported via `subscription_data` | Not supported |
| Session ID tracking | Direct metadata field | URL parameter (less reliable) |
| Server-side control | Full | None |
For subscriptions, Payment Links do not carry metadata forward to future
invoices. Only the initial payment will have attribution data. If you need
subscription revenue tracking, use the [Checkout Sessions
API](/docs/revenue-attribution/stripe-checkout#subscriptions) instead.
## Verify
1. Open your site and inspect a Stripe Payment Link — the URL should include `client_reference_id` and `engagetrack_session_id` parameters
2. Click the link and complete a test purchase using card `4242 4242 4242 4242`
3. Check your EngageTrack dashboard → **Revenue** tab for the payment
4. Verify the payment is attributed to the correct traffic source
If the payment appears but without source attribution, the visitor ID was not passed correctly. Check that:
- The EngageTrack SDK is loaded before the snippet runs
- `window.engagetrack.getVisitorId()` returns a non-empty string
- The URL parameters are present when clicking the link
---
URL: https://engagetrack.net/docs/revenue-attribution/stripe-payment-intent.md
---
title: Stripe PaymentIntent
description: Set up revenue attribution with Stripe PaymentIntent for custom checkout flows.
order: 4
---
# Stripe PaymentIntent
If you are building a custom checkout form with Stripe Elements, you create PaymentIntents on the server. This guide shows how to attach EngageTrack metadata to the PaymentIntent so revenue is attributed correctly.
## How It Works
1. Your client-side code reads `engagetrack_visitor_id` and `engagetrack_session_id` from the SDK and sends them to your server
2. Your server creates a PaymentIntent with these values in the `metadata` field
3. After payment, Stripe sends a `payment_intent.succeeded` webhook to EngageTrack
4. EngageTrack reads the metadata and attributes the revenue
## Step 1: Send IDs from the Client
When your checkout form loads, read the EngageTrack IDs and include them in the request to your server:
```javascript
const visitorId = window.engagetrack?.getVisitorId() || "";
const sessionId = window.engagetrack?.getSessionId() || "";
const response = await fetch("/api/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
amount: 2999, // $29.99 in cents
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
}),
});
const { clientSecret } = await response.json();
// Use clientSecret with Stripe Elements to confirm payment
```
## Step 2: Create the PaymentIntent with Metadata
### Node.js / Express
```javascript
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post("/api/create-payment-intent", async (req, res) => {
const { amount, engagetrack_visitor_id, engagetrack_session_id } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
metadata: {
engagetrack_visitor_id: engagetrack_visitor_id || "",
engagetrack_session_id: engagetrack_session_id || "",
},
});
res.json({ clientSecret: paymentIntent.client_secret });
});
```
### Next.js App Router (Route Handler)
```typescript
import { NextRequest, NextResponse } from "next/server";
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: NextRequest) {
const { amount, engagetrack_visitor_id, engagetrack_session_id } =
await request.json();
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
metadata: {
engagetrack_visitor_id: engagetrack_visitor_id ?? "",
engagetrack_session_id: engagetrack_session_id ?? "",
},
});
return NextResponse.json({ clientSecret: paymentIntent.client_secret });
}
```
The SDK stores IDs in browser storage (not cookies), so the client-to-server
approach shown above is the recommended pattern. Read the IDs with
`window.engagetrack.getVisitorId()` and `window.engagetrack.getSessionId()`,
then send them to your server in the request body.
## Step 3: Set Up the Webhook
Add the EngageTrack webhook endpoint in your Stripe dashboard:
1. Go to [Stripe Dashboard → Developers → Webhooks](https://dashboard.stripe.com/webhooks)
2. Click **Add endpoint**
3. Enter the webhook URL:
```
https://api.engagetrack.net/api/v1/webhooks/revenue/stripe/{YOUR_SITE_PUBLIC_ID}
```
4. Under **Events to send**, select:
- `payment_intent.succeeded`
- `charge.refunded`
5. Click **Add endpoint**
## Stripe Elements Example
Here is a complete client-side example using Stripe Elements with React:
```tsx
import { useState, useEffect } from "react";
import { loadStripe } from "@stripe/stripe-js";
import {
Elements,
PaymentElement,
useStripe,
useElements,
} from "@stripe/react-stripe-js";
const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
);
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!stripe || !elements) return;
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "https://yoursite.com/success",
},
});
if (error) {
console.error(error.message);
}
setLoading(false);
}
return (
);
}
export default function CheckoutPage() {
const [clientSecret, setClientSecret] = useState("");
useEffect(() => {
const visitorId = window.engagetrack?.getVisitorId() || "";
const sessionId = window.engagetrack?.getSessionId() || "";
fetch("/api/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
amount: 2999,
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
}),
})
.then((res) => res.json())
.then(({ clientSecret }) => setClientSecret(clientSecret));
}, []);
if (!clientSecret) return
Loading checkout...
;
return (
);
}
```
## Verify
1. Open your site and navigate to the custom checkout page
2. Open DevTools → Console and run `window.engagetrack.getVisitorId()` to confirm the SDK is loaded and returning an ID
3. Complete a test payment using card `4242 4242 4242 4242`
4. Check your EngageTrack dashboard → **Revenue** tab
5. Confirm the payment appears and is attributed to your traffic source
If the payment is not attributed:
- Verify that the PaymentIntent metadata contains the correct keys (check in Stripe Dashboard → Payments → select payment → Metadata section)
- Ensure the webhook endpoint is receiving events (Stripe Dashboard → Webhooks → recent deliveries)
- Confirm you selected `payment_intent.succeeded` when adding the webhook endpoint
---
URL: https://engagetrack.net/docs/revenue-attribution/lemonsqueezy.md
---
title: LemonSqueezy
description: Set up revenue attribution with LemonSqueezy.
order: 5
---
# LemonSqueezy
LemonSqueezy is a merchant of record that handles payments, taxes, and subscriptions. This guide shows how to pass EngageTrack visitor and session IDs through LemonSqueezy's `custom_data` field for revenue attribution.
## How It Works
1. The EngageTrack SDK generates a visitor ID and session ID (stored in browser storage, accessible via the SDK's JavaScript API)
2. When creating a checkout, you pass these values in the `custom_data` field
3. After payment, LemonSqueezy sends a webhook to EngageTrack with the custom data
4. EngageTrack reads the visitor ID and attributes the revenue to the traffic source
## Checkout API
### Node.js / Express
```javascript
import { lemonSqueezySetup, createCheckout } from "@lemonsqueezy/lemonsqueezy.js";
lemonSqueezySetup({ apiKey: process.env.LEMONSQUEEZY_API_KEY });
app.post("/create-checkout", async (req, res) => {
// Receive visitor/session IDs from the client request body
const { engagetrack_visitor_id: visitorId, engagetrack_session_id: sessionId } = req.body;
const { data } = await createCheckout(process.env.LEMONSQUEEZY_STORE_ID, {
productOptions: {
redirectUrl: "https://yoursite.com/success",
},
checkoutData: {
custom: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
},
});
res.json({ url: data.data.attributes.url });
});
```
### Next.js App Router (Route Handler)
```typescript
import { NextRequest, NextResponse } from "next/server";
import { lemonSqueezySetup, createCheckout } from "@lemonsqueezy/lemonsqueezy.js";
lemonSqueezySetup({ apiKey: process.env.LEMONSQUEEZY_API_KEY! });
export async function POST(request: NextRequest) {
// Receive visitor/session IDs from the client request body
const { variant_id, engagetrack_visitor_id, engagetrack_session_id } =
await request.json();
const visitorId = engagetrack_visitor_id ?? "";
const sessionId = engagetrack_session_id ?? "";
const { data } = await createCheckout(process.env.LEMONSQUEEZY_STORE_ID!, {
productOptions: {
redirectUrl: "https://yoursite.com/success",
},
checkoutData: {
variantId: Number(variant_id),
custom: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
},
});
return NextResponse.json({ url: data!.data.attributes.url });
}
```
LemonSqueezy uses `custom_data` (accessed via the `custom` field in the SDK)
to pass arbitrary data through the checkout. EngageTrack expects the keys
`engagetrack_visitor_id` and `engagetrack_session_id` inside this object.
## Checkout Links
If you use LemonSqueezy Checkout Links (no server code), append the custom data as URL parameters:
```html
Buy Now
```
The URL parameter syntax for LemonSqueezy checkout links uses bracket
notation: `checkout[custom][engagetrack_visitor_id]`. This is how
LemonSqueezy maps URL parameters to the `custom_data` field.
## Set Up the Webhook
1. Go to [LemonSqueezy Dashboard → Settings → Webhooks](https://app.lemonsqueezy.com/settings/webhooks)
2. Click **Add endpoint**
3. Enter the webhook URL:
```
https://api.engagetrack.net/api/v1/webhooks/revenue/lemonsqueezy/{YOUR_SITE_PUBLIC_ID}
```
4. Under **Events**, select:
- `order_created`
- `subscription_payment_success`
- `order_refunded`
5. Enter a signing secret and save it — you will need this when connecting LemonSqueezy in EngageTrack
6. Click **Save**
If you connected LemonSqueezy via the EngageTrack dashboard (Site Settings
→ Revenue), the webhook is registered automatically and you can skip
this step.
## Verify
1. Open your site and confirm the SDK is loaded by running `window.engagetrack.getVisitorId()` in the browser console
2. Complete a test purchase using LemonSqueezy's [test mode](https://docs.lemonsqueezy.com/guides/developer-guide/testing)
3. Go to your EngageTrack dashboard → **Revenue** tab
4. The test payment should appear within a few seconds, attributed to your traffic source
If the payment appears without attribution:
- Check the LemonSqueezy webhook logs for delivery errors (LemonSqueezy Dashboard → Webhooks → select endpoint)
- Verify the `custom_data` field in the webhook payload contains `engagetrack_visitor_id`
- Ensure the cookie values are non-empty when creating the checkout
---
URL: https://engagetrack.net/docs/revenue-attribution/paddle.md
---
title: Paddle
description: Set up revenue attribution with Paddle.
order: 6
---
# Paddle
Paddle is a merchant of record that handles payments, taxes, and subscriptions globally. This guide shows how to pass EngageTrack visitor and session IDs through Paddle's `custom_data` field for revenue attribution.
## How It Works
1. The EngageTrack SDK generates a visitor ID and session ID (stored in browser storage, accessible via the SDK's JavaScript API)
2. When opening a Paddle checkout, you pass these values in the `custom_data` field
3. After payment, Paddle sends a webhook to EngageTrack with the custom data
4. EngageTrack reads the visitor ID and attributes the revenue to the traffic source
## Overlay Checkout (Paddle.js)
The most common Paddle integration uses the overlay checkout via Paddle.js. Pass the EngageTrack IDs in the `customData` option:
```html
```
### React / Next.js
```tsx
"use client";
import { initializePaddle, type Paddle } from "@paddle/paddle-js";
import { useEffect, useState } from "react";
export default function CheckoutButton({ priceId }: { priceId: string }) {
const [paddle, setPaddle] = useState(null);
useEffect(() => {
initializePaddle({
token: process.env.NEXT_PUBLIC_PADDLE_CLIENT_TOKEN!,
}).then(setPaddle);
}, []);
function handleCheckout() {
if (!paddle) return;
const visitorId = window.engagetrack?.getVisitorId() || "";
const sessionId = window.engagetrack?.getSessionId() || "";
paddle.Checkout.open({
items: [{ priceId, quantity: 1 }],
customData: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
settings: {
successUrl: "https://yoursite.com/success",
},
});
}
return ;
}
```
Paddle uses `custom_data` to pass arbitrary data through the checkout.
EngageTrack expects the keys `engagetrack_visitor_id` and
`engagetrack_session_id` inside this object.
## Checkout API (Server-Side)
If you create transactions server-side using the Paddle API, attach the custom data there:
```javascript
import { Paddle } from "@paddle/paddle-node-sdk";
const paddle = new Paddle(process.env.PADDLE_API_KEY);
app.post("/create-checkout", async (req, res) => {
// Receive visitor/session IDs from the client request body
const { engagetrack_visitor_id: visitorId, engagetrack_session_id: sessionId } = req.body;
const transaction = await paddle.transactions.create({
items: [
{
priceId: "pri_xxxxxxxxxxxxx",
quantity: 1,
},
],
customData: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
});
res.json({ transactionId: transaction.id });
});
```
## Set Up the Webhook
1. Go to [Paddle Dashboard → Developer Tools → Notifications](https://vendors.paddle.com/notifications)
2. Click **New destination**
3. Select **Webhook** as the type
4. Enter the webhook URL:
```
https://api.engagetrack.net/api/v1/webhooks/revenue/paddle/{YOUR_SITE_PUBLIC_ID}
```
5. Under **Events**, select:
- `transaction.completed` (handles both one-time payments and subscription renewals — renewals are detected when `origin` is `subscription_recurring`)
- `adjustment.created` (for refunds)
6. Click **Save**
If you connected Paddle via the EngageTrack dashboard (Site Settings →
Revenue), the webhook is registered automatically and you can skip this
step.
## Verify
1. Open your site and confirm the SDK is loaded by running `window.engagetrack.getVisitorId()` in the browser console
2. Complete a test purchase using Paddle's [sandbox environment](https://developer.paddle.com/concepts/platform/environments)
3. Go to your EngageTrack dashboard → **Revenue** tab
4. The test payment should appear within a few seconds, attributed to your traffic source
If the payment appears without attribution:
- Open the Paddle transaction in your Paddle dashboard and check the `custom_data` field contains `engagetrack_visitor_id`
- Verify webhook delivery in Paddle Dashboard → Developer Tools → Notifications → select destination → Event logs
- Ensure the EngageTrack SDK is loaded before `Paddle.Checkout.open()` is called
---
URL: https://engagetrack.net/docs/revenue-attribution/polar.md
---
title: Polar
description: Set up revenue attribution with Polar.
order: 7
---
# Polar
Polar is a payment platform for developers and open-source projects. This guide shows how to pass EngageTrack visitor and session IDs through Polar's `metadata` field for revenue attribution.
## How It Works
1. The EngageTrack SDK generates a visitor ID and session ID (stored in browser storage, accessible via the SDK's JavaScript API)
2. When creating a Polar checkout, you pass these values in the `metadata` field
3. After payment, Polar sends a webhook to EngageTrack with the metadata
4. EngageTrack reads the visitor ID and attributes the revenue to the traffic source
## Checkout API
### Node.js / Express
```javascript
import { Polar } from "@polar-sh/sdk";
const polar = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN });
app.post("/create-checkout", async (req, res) => {
// Receive visitor/session IDs from the client request body
const { engagetrack_visitor_id: visitorId, engagetrack_session_id: sessionId } = req.body;
const checkout = await polar.checkouts.create({
productPriceId: "price_xxxxxxxxxxxxx",
successUrl: "https://yoursite.com/success",
metadata: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
});
res.json({ url: checkout.url });
});
```
### Next.js App Router (Route Handler)
```typescript
import { NextRequest, NextResponse } from "next/server";
import { Polar } from "@polar-sh/sdk";
const polar = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN! });
export async function POST(request: NextRequest) {
// Receive visitor/session IDs from the client request body
const { price_id, engagetrack_visitor_id, engagetrack_session_id } =
await request.json();
const visitorId = engagetrack_visitor_id ?? "";
const sessionId = engagetrack_session_id ?? "";
const checkout = await polar.checkouts.create({
productPriceId: price_id,
successUrl: "https://yoursite.com/success",
metadata: {
engagetrack_visitor_id: visitorId,
engagetrack_session_id: sessionId,
},
});
return NextResponse.json({ url: checkout.url });
}
```
Polar uses a `metadata` field (not `custom_data`) to pass arbitrary
key-value pairs through the checkout. EngageTrack expects the keys
`engagetrack_visitor_id` and `engagetrack_session_id`.
## Checkout Links
If you use Polar Checkout Links, append the metadata as URL parameters:
```html
Buy Now
```
## Set Up the Webhook
1. Go to [Polar Dashboard → Settings → Webhooks](https://polar.sh/settings/webhooks)
2. Click **Add endpoint**
3. Enter the webhook URL:
```
https://api.engagetrack.net/api/v1/webhooks/revenue/polar/{YOUR_SITE_PUBLIC_ID}
```
4. Under **Events**, select:
- `order.created`
- `subscription.updated`
- `refund.created`
5. Click **Save**
If you connected Polar via the EngageTrack dashboard (Site Settings →
Revenue), the webhook is registered automatically and you can skip this
step.
## Verify
1. Open your site and confirm the SDK is loaded by running `window.engagetrack.getVisitorId()` in the browser console
2. Complete a test purchase using Polar's [sandbox mode](https://docs.polar.sh/developers/sandbox)
3. Go to your EngageTrack dashboard → **Revenue** tab
4. The test payment should appear within a few seconds, attributed to your traffic source
If the payment appears without attribution:
- Check the Polar webhook logs for delivery errors (Polar Dashboard → Settings → Webhooks → select endpoint)
- Verify the `metadata` field in the webhook payload contains `engagetrack_visitor_id`
- Ensure the EngageTrack SDK is loaded and the cookie values are non-empty when creating the checkout
---
URL: https://engagetrack.net/docs/analytics/dashboard-overview.md
---
title: Dashboard Overview
description: Understand the metrics, charts, and breakdowns available in your EngageTrack analytics dashboard.
order: 1
---
# Dashboard Overview
The EngageTrack dashboard gives you a real-time, centralized view of your website's traffic and performance. All data is scoped to a single site within your organization.
## Key Metrics
The top bar displays five headline KPIs, each with a comparison percentage to the previous period:
| Metric | Description |
| ----------------- | ------------------------------------------ |
| **Visitors** | Unique visitors |
| **Pageviews** | Total page loads across all visitors |
| **Bounce Rate** | Percentage of single-page sessions |
| **Visit Duration**| Average time spent per session |
| **Views/Visit** | Average number of pages viewed per session |
Comparisons are always against the immediately preceding period of equal
length. For example, selecting "Last 7 days" compares to the 7 days before
that.
## Time-Series Chart
Below the KPIs, a line chart shows visitors, pageviews, or sessions over time. The granularity adjusts automatically based on the selected period. A faded overlay shows the previous period for at-a-glance comparison.
## Breakdown Cards
### Sources
Traffic is grouped into semantic **channels** (Organic Search, Paid, Social, Direct, Email, Referral) and further broken down by:
- **Referrers** — individual domains sending traffic
- **Campaigns** — UTM campaigns (`utm_campaign` parameter)
- **Channels** — enriched channel view with top sub-sources and revenue per channel
### Pages
- **Top Pages** — most visited page paths
- **Entry Pages** — where visitors land first
- **Exit Pages** — where visitors leave
### Locations
Geographic distribution at three levels:
- **Country**
- **Region** — state or province
- **City**
A 3D globe visualization shows real-time visitor locations.
### Devices
- **Device** — Desktop, Mobile, or Tablet
- **Browser** — Chrome, Firefox, Safari, etc.
- **OS** — Windows, macOS, Android, iOS, etc.
## Realtime
The realtime widget shows the number of visitors currently active on your site. A live globe displays active visitor coordinates in real-time.
## Date Picker
All dashboard data can be filtered by period:
- **Today** — current day so far
- **Yesterday** — the previous full day
- **7d** — last 7 days
- **30d** — last 30 days
- **90d** — last 90 days
- **12mo** — last 12 months
- **Custom** — pick a specific start and end date
---
URL: https://engagetrack.net/docs/analytics/filtering.md
---
title: Filtering & Segmentation
description: Filter your analytics data by country, page, source, device, browser, OS, and more.
order: 2
---
# Filtering & Segmentation
EngageTrack supports powerful filtering across all analytics views. Filters let you drill down into specific segments — for example, "visitors from Germany using Chrome on mobile."
## Available Filter Dimensions
| Dimension | Example Values |
| -------------- | ------------------------------------------------- |
| Country | `US`, `DE`, `RO` |
| Region | `California`, `Bavaria` |
| City | `San Francisco`, `Bucharest` |
| Page | `/pricing`, `/blog/my-post` |
| Entry Page | `/`, `/landing` |
| Source | `google`, `twitter` |
| UTM Source | `newsletter`, `google` |
| UTM Medium | `cpc`, `email`, `social` |
| UTM Campaign | `spring-sale`, `launch` |
| Referrer | `github.com`, `reddit.com` |
| Browser | `Chrome`, `Firefox`, `Safari` |
| OS | `Windows`, `macOS`, `Android` |
| Device | `Desktop`, `Mobile`, `Tablet` |
| Event Name | `signup`, `purchase` |
## How to Apply Filters
1. Click **+ Add filter** above the chart
2. Select a dimension (e.g., Country)
3. Start typing to search for values — the dashboard suggests matching values as you type
4. Select one or more values
5. The entire dashboard updates to reflect only matching traffic
Multiple filters are combined with **AND** logic — all conditions must match.
Filters persist across all tabs (Sources, Pages, Locations, Devices) so you
can explore different breakdowns for the same segment.
---
URL: https://engagetrack.net/docs/advanced/script-configuration.md
---
title: Script Configuration
description: Complete reference for all tracking script configuration options.
order: 1
---
# Script Configuration
The EngageTrack tracking script is configured entirely through HTML `data-*` attributes on the `
```
## Script Attributes Reference
| Attribute | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
| `data-site-id` | string | — | **Required.** Your site ID from the EngageTrack dashboard. Also accepts `data-site` as an alias. |
| `data-api` | string | `https://api.engagetrack.net/api/v1/event` | Custom event endpoint URL. Use this when [proxying](/docs/proxy/overview) the SDK through your own domain. |
| `data-outbound` | `"true"` / `"false"` | `"true"` | Track clicks on links to external domains. |
| `data-downloads` | `"true"` / `"false"` | `"true"` | Track file download clicks (pdf, doc, zip, exe, etc.). |
| `data-forms` | `"true"` / `"false"` | `"true"` | Track form submissions. Auth-related forms are automatically excluded. |
| `data-phone` | `"true"` / `"false"` | `"true"` | Track clicks on `tel:` phone links. |
| `data-hash` | `"true"` / `"false"` | `"false"` | Enable hash-based routing mode. When `"true"`, the full URL including `#hash` is tracked as the page path. |
| `data-persistence` | `"memory"` / `"storage"` | `"memory"` | Tracking persistence mode. **`"memory"`** (default): zero device storage — session ID lives in a JS variable, lost on tab close. No consent banner needed. **`"storage"`**: persistent visitor ID in `localStorage`, session in `sessionStorage`. Enables multi-day visitor tracking but requires a consent banner in the EU. |
| `data-debug` | `"true"` / `"false"` | `"false"` | Log all tracking events to the browser console. |
| `data-allowed-hostnames` | string | `""` | Comma-separated list of hostnames for [cross-domain tracking](/docs/advanced/cross-domain). Requires `data-persistence="storage"`. |
| `data-exclude` | string | `""` | Comma-separated list of path patterns to exclude from pageview tracking (e.g., `/dashboard/*,/admin/*`). Supports `*` wildcards. Custom events and purchases are never excluded. |
The `data-site-id` attribute is required. Without it, the script will not
initialize and will log a warning to the console.
## HTML Element Attributes
These attributes can be added to any HTML element to trigger tracking behavior.
### Goal Tracking
| Attribute | Description |
| --------- | ----------- |
| `data-goal` | Fires a custom goal event when the element is clicked. Value is the goal name (lowercase, numbers, hyphens, underscores, max 64 chars). |
| `data-goal-*` | Attach custom properties to the goal. The suffix becomes the property name (kebab-case is converted to snake_case). Max 10 properties per goal. |
```html
```
Goal names must match the pattern `[a-z0-9_-]` and be at most 64
characters. Property values are truncated to 255 characters.
### Scroll Tracking
| Attribute | Description |
| --------- | ----------- |
| `data-scroll` | Fires a custom event when the element scrolls into view (50% visibility threshold). Value is the goal name. Each goal fires only once per page load. |
```html
Pricing
```
Scroll tracking uses the `IntersectionObserver` API. Goals reset on SPA
navigation, so they can fire again on the next page.
## Configuration Examples
### Development Setup
Track localhost traffic with debug logging enabled:
```html
```
Open your browser console to see all events being sent in real time.
### Production with Proxy
Serve the SDK through your own domain to bypass ad blockers:
```html
```
> See the [Proxy Setup guide](/docs/proxy/overview) for full instructions.
### Persistent Tracking (Storage Mode)
Enable multi-day visitor tracking. Requires a consent banner in the EU:
```html
```
Storage mode writes a visitor ID to `localStorage` and session data to
`sessionStorage`. Under the ePrivacy Directive, this requires informed
consent before the script loads for EU visitors.
### Cross-Domain Tracking
Track visitors across multiple domains as a single session. Requires `data-persistence="storage"`:
```html
```
> See the [Cross-Domain Tracking guide](/docs/advanced/cross-domain) for setup details.
### Hash-Based Navigation
For apps using hash-based routing (e.g., `/#/dashboard`, `/#/settings`):
```html
```
### Minimal Tracking
Disable all automatic tracking except pageviews:
```html
```
---
URL: https://engagetrack.net/docs/advanced/cross-domain.md
---
title: Cross-Domain Tracking
description: Track visitors across multiple domains with seamless session stitching.
order: 2
---
# Cross-Domain Tracking
By default, EngageTrack treats each domain as a separate context. Cross-domain tracking lets you follow a single visitor across multiple domains (e.g., `www.example.com` to `checkout.example.com`) as one continuous session.
Cross-domain tracking requires **storage mode** (`data-persistence="storage"`)
on both domains. In the default memory mode, there is no persistent visitor
ID to pass between domains. Storage mode requires a consent banner in the EU.
## How It Works
1. You list the destination domains in the `data-allowed-hostnames` attribute on the **source** domain
2. When a visitor clicks a link to an allowed hostname, the SDK appends `_et_vid` (visitor ID) and `_et_sid` (session ID) as URL parameters
3. On the **destination** domain, the SDK reads those parameters, hydrates the visitor and session IDs into `localStorage`/`sessionStorage`, and removes the parameters from the URL
The result is a seamless session that spans both domains.
## Setup
### Step 1: Configure the Source Domain
On every domain that links to another domain you own, add the destination hostnames to `data-allowed-hostnames`:
```html
```
List only the exact hostnames (no protocol, no paths). Separate multiple
hostnames with commas. Both `data-persistence="storage"` and `data-allowed-hostnames`
are required on the source domain.
### Step 2: Install the SDK on the Destination Domain
The destination domain must also have the EngageTrack script installed with the **same site ID**:
```html
```
The SDK automatically detects `_et_vid` and `_et_sid` in the URL, hydrates the visitor identity into `localStorage`/`sessionStorage`, and cleans the URL.
### Step 3: Use Regular Links
No special link markup is needed. The SDK intercepts clicks on outbound links and decorates them automatically:
```html
Complete Purchase
```
Cross-domain links opened via `window.open()` or programmatic navigation
are not automatically decorated. For those cases, build the URL manually
using `window.engagetrack.getVisitorId()` and
`window.engagetrack.getSessionId()`.
### Programmatic Navigation
If you navigate to a cross-domain URL with JavaScript:
```javascript
const vid = window.engagetrack.getVisitorId();
const sid = window.engagetrack.getSessionId();
const url = new URL("https://checkout.example.com/buy");
url.searchParams.set("_et_vid", vid);
url.searchParams.set("_et_sid", sid);
window.location.href = url.toString();
```
## Bidirectional Tracking
If visitors can navigate in both directions (e.g., `www` to `checkout` and back), add `data-allowed-hostnames` on **both** domains:
```html
```
## Verify It's Working
1. Enable debug mode on both domains by adding `data-debug="true"` to the script tag
2. Open the browser console on the source domain
3. Click a link to the destination domain
4. Look for `[EngageTrack] Cross-domain link decorated:` in the console — this confirms the URL parameters were appended
5. On the destination domain, check for `[EngageTrack] Cross-domain: hydrated visitor` and `hydrated session` messages
6. Verify both domains report the same visitor ID by calling `window.engagetrack.getVisitorId()` in the console on each domain
---
URL: https://engagetrack.net/docs/advanced/subdomain-tracking.md
---
title: Subdomain Tracking
description: Track visitors across subdomains of the same root domain.
order: 3
---
# Subdomain Tracking
EngageTrack handles subdomain tracking automatically in most cases. This guide covers how to configure tracking for different subdomain setups.
## Default Behavior
In the default **memory mode**, the SDK uses no device storage at all — visitor identification is handled server-side via a daily-rotating hash. This means all subdomains are treated equally: visitors are identified by the same hash within a single day, regardless of which subdomain they visit.
In **storage mode** (`data-persistence="storage"`), the SDK stores the visitor ID in `localStorage`. Since `localStorage` is scoped to the exact origin, different subdomains maintain separate storage:
- **Same-origin pages** (e.g., `www.example.com/blog` and `www.example.com/app`) share identity automatically
- **Different subdomains** (e.g., `www.example.com` and `app.example.com`) do **not** share `localStorage` by default — each subdomain will generate its own visitor ID
The SDK also filters out self-referrals between subdomains. If a visitor
navigates from `blog.example.com` to `app.example.com`, the referrer is
treated as direct — not as an external source.
## Setup for Separate Tracking
If you want to track each subdomain as an independent site with its own dashboard, create a separate site in EngageTrack for each subdomain and use different site IDs:
```html
```
Each site will have its own analytics, visitors, and revenue data.
## Setup for Unified Tracking
To track all subdomains under a single site in EngageTrack, use the **same site ID** on every subdomain:
```html
```
All pageviews and events from every subdomain will appear in the same dashboard. You can filter by hostname in the **Pages** report to isolate traffic from a specific subdomain.
In storage mode, `localStorage` is scoped to the exact origin, so visitor
IDs will differ between subdomains. To stitch visitor sessions across
subdomains, use [cross-domain tracking](/docs/advanced/cross-domain)
with `data-persistence="storage"` and `data-allowed-hostnames`. In the
default memory mode, the server-side hash naturally handles same-day
visitor identification across subdomains.
## Filtering by Subdomain
When using unified tracking, you can segment data by subdomain in the dashboard:
1. Go to the **Pages** report
2. Use the hostname filter to select a specific subdomain
3. All metrics (visitors, pageviews, bounce rate) will be scoped to that subdomain
You can also create [goals](/docs/tracking/goals) that target specific subdomains by filtering on the page URL.
---
URL: https://engagetrack.net/docs/advanced/user-identification.md
---
title: User Identification
description: Connect anonymous visitors to known user profiles for enhanced analytics.
order: 4
---
# User Identification
EngageTrack tracks visitors anonymously by default. The Identify API lets you connect an anonymous visitor to a known user profile after they log in or sign up, enriching your analytics with user-level data.
## The Identify API
```javascript
window.engagetrack.identify(userId, {
name: "Jane Smith",
email: "jane@example.com",
avatar: "https://example.com/avatars/jane.jpg",
custom: {
plan: "pro",
company: "Acme Inc",
},
});
```
### Parameters
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `userId` | string | Yes | A unique, stable identifier for the user (e.g., database ID, auth provider ID). |
| `traits.name` | string | No | Display name. |
| `traits.email` | string | No | Email address. Used for [email-based revenue attribution](/docs/tracking/revenue#attribution-models). |
| `traits.avatar` | string | No | URL to the user's avatar image. Displayed in the visitor timeline. |
| `traits.custom` | object | No | Key-value pairs of custom properties (e.g., plan, company, role). |
## When to Call Identify
Call `identify()` after the user's identity is confirmed — typically right after login or signup:
```javascript
// After successful login
async function onLogin(credentials) {
const user = await api.login(credentials);
// Identify the visitor with EngageTrack
window.engagetrack.identify(user.id, {
name: user.name,
email: user.email,
});
}
```
```javascript
// After successful signup
async function onSignup(formData) {
const user = await api.register(formData);
window.engagetrack.identify(user.id, {
name: user.name,
email: user.email,
custom: {
signup_source: "landing-page",
},
});
}
```
You only need to call `identify()` once per session. The SDK links the
current anonymous visitor ID to the user profile on the server.
### React / Next.js Example
```tsx
"use client";
import { useEffect } from "react";
import { useAuth } from "@/hooks/useAuth";
export function IdentifyUser() {
const { user } = useAuth();
useEffect(() => {
if (user && typeof window !== "undefined" && window.engagetrack) {
window.engagetrack.identify(user.id, {
name: user.name,
email: user.email,
avatar: user.avatar,
});
}
}, [user]);
return null;
}
```
Place this component inside your authenticated layout so it runs whenever a logged-in user loads the page.
## How It Works
When you call `identify()`, the SDK sends a POST request to the `/api/v1/identify` endpoint with:
- The current anonymous `visitor_uid` (from `localStorage` — requires storage mode)
- The `user_id` you provided
- Any traits (name, email, avatar, custom)
The server links the anonymous visitor record to the user profile. All past and future events for that visitor are associated with the identified user.
`identify()` requires **storage mode** (`data-persistence="storage"`) because
it needs a persistent visitor ID to link across sessions. In the default
memory mode, calling `identify()` will log a warning and return without
effect.
## Visitor Timeline Enrichment
Once a visitor is identified, their profile in the **Visitors** dashboard shows:
- **Name and avatar** instead of an anonymous ID
- **Email address** for quick reference
- **Custom properties** as metadata tags
- **Full event timeline** including pre-identification pageviews
## Revenue Attribution
Identified users unlock email-based revenue attribution. When a payment webhook arrives with an email address, EngageTrack can match it to an identified visitor — even if the `engagetrack_visitor_id` metadata was not included in the payment.
> See [Revenue Attribution](/docs/tracking/revenue#attribution-models) for the full attribution priority chain.
---
URL: https://engagetrack.net/docs/advanced/exclude-visits.md
---
title: Exclude Visits
description: Filter out internal traffic, bots, and test environments from your analytics.
order: 5
---
# Exclude Visits
Keep your analytics clean by excluding internal team visits, development traffic, and bots from your data.
## Self-Exclusion (Browser)
The simplest way to exclude yourself is from the browser console on your tracked site.
### Using the SDK Method
```javascript
// Disable tracking for this browser
window.engagetrack.ignore();
// Re-enable tracking
window.engagetrack.unignore();
```
Both methods require a page reload to take effect.
### Using localStorage Directly
```javascript
// Disable tracking
localStorage.setItem("engagetrack_ignore", "true");
// Re-enable tracking
localStorage.removeItem("engagetrack_ignore");
```
The exclusion flag is stored in `localStorage`, so it persists across
sessions but is specific to that browser. You need to set it on each
browser and device you use.
### Bookmark Shortcut
Create a browser bookmark with this URL to toggle exclusion with one click:
```
javascript:void(localStorage.getItem('engagetrack_ignore')==='true'?(localStorage.removeItem('engagetrack_ignore'),alert('EngageTrack: Tracking enabled. Reload the page.')):(localStorage.setItem('engagetrack_ignore','true'),alert('EngageTrack: Tracking disabled. Reload the page.')))
```
## IP Exclusion
Exclude traffic from specific IP addresses or ranges in the dashboard:
1. Go to **Site Settings -> Tracking**
2. Under **Excluded IPs**, add IP addresses or CIDR ranges
3. Traffic from those IPs will be silently dropped
Common use cases:
- Office IP addresses
- VPN exit nodes used by your team
- CI/CD server IPs
IP exclusion is applied server-side, so excluded traffic never appears in
your analytics data at all.
## Path Exclusion
Exclude specific pages or URL patterns from being tracked:
1. Go to **Site Settings -> Tracking**
2. Under **Excluded Paths**, add URL patterns
Patterns support wildcards:
| Pattern | Matches |
| ------- | ------- |
| `/admin/*` | All pages under `/admin/` |
| `/internal` | Exact match for `/internal` |
| `/staging/*` | All staging pages |
## Hostname Exclusion
If you have the script installed on staging or development environments and want to exclude that traffic:
1. Go to **Site Settings -> Tracking**
2. Under **Allowed Hostnames**, list only the production hostnames
Any traffic from hostnames not in the list will be ignored.
If you leave the allowed hostnames list empty, traffic from all hostnames
is accepted. Add at least your production domain to enable hostname
filtering.
## Verify Exclusion
To confirm your visits are being excluded:
1. Add `data-debug="true"` to the script tag (or use a development environment)
2. Open the browser console
3. If you have `engagetrack_ignore` set, you will see: `[EngageTrack] Tracking disabled via engagetrack_ignore flag`
4. Check the **Real-time** dashboard view — your visits should not appear
---
URL: https://engagetrack.net/docs/advanced/data-export.md
---
title: Data Export
description: Export your analytics data for custom analysis and reporting.
order: 6
---
# Data Export
EngageTrack gives you full access to your analytics data. Export it as CSV from the dashboard or use the API for programmatic access.
## CSV Export from Dashboard
Every report in the EngageTrack dashboard has a **Download CSV** button:
1. Navigate to the report you want to export (Pages, Sources, Countries, etc.)
2. Apply any filters or date range you need
3. Click the **Download CSV** button in the top-right corner
The exported CSV includes all rows matching your current filters, not just the visible page.
## API-Based Export
Use the analytics export endpoint to fetch data programmatically:
```bash
curl -X GET "https://api.engagetrack.net/api/v1/analytics/export?site_id=YOUR_SITE_ID&period=30d&metric=pageviews" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: text/csv"
```
### Query Parameters
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `site_id` | string | Your site ID |
| `period` | string | Time range: `7d`, `30d`, `90d`, `12mo`, or custom `2024-01-01,2024-01-31` |
| `metric` | string | Export type: `pageviews`, `sources`, `countries`, `devices`, `events` |
The response is a CSV file with appropriate `Content-Disposition` headers for download.
API exports respect the same permissions as the dashboard. You need a valid
API key with read access to the site. Generate one in **Site Settings ->
API Keys**.
## Full Site Export
Request a complete export of all raw event data for a site:
```bash
curl -X POST "https://api.engagetrack.net/api/v1/exports/full" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"site_id": "YOUR_SITE_ID",
"start_date": "2024-01-01",
"end_date": "2024-12-31"
}'
```
### Response
```json
{
"export_id": "exp_abc123",
"status": "processing",
"estimated_rows": 150000,
"download_url": null
}
```
Full exports are processed asynchronously. You will receive an email with a download link when the export is ready. You can also poll the status:
```bash
curl -X GET "https://api.engagetrack.net/api/v1/exports/exp_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
```
Full exports can be large. The download link expires after 24 hours. For
ongoing data access, use the API-based export with specific date ranges
instead.
## Export Data Format
Full exports include one row per event with the following fields:
| Field | Description |
| ----- | ----------- |
| `timestamp` | ISO 8601 event time |
| `event_type` | `pageview`, `custom`, `outbound`, `download`, `form_submit`, `purchase`, etc. |
| `url` | Page URL where the event occurred |
| `referrer` | Referring URL (empty for direct traffic) |
| `visitor_uid` | Anonymous visitor identifier |
| `session_id` | Session identifier |
| `event_name` | Custom event or goal name |
| `properties` | JSON object of event properties |
| `country` | Two-letter country code |
| `device` | `desktop`, `mobile`, or `tablet` |
| `browser` | Browser name |
| `os` | Operating system |
| `revenue` | Revenue amount (for purchase events) |
| `currency` | Revenue currency code |
---
URL: https://engagetrack.net/docs/advanced/email-reports.md
---
title: Email Reports
description: Receive automated analytics reports in your inbox.
order: 7
---
# Email Reports
Get a summary of your site's performance delivered to your inbox on a regular schedule — no need to log into the dashboard.
## Setting Up a Report
1. Go to **Site Settings -> Email Reports**
2. Click **New Report**
3. Configure the report:
- **Frequency** — Daily, weekly (sent on Mondays), or monthly (sent on the 1st)
- **Metrics** — Choose which metrics to include (visitors, pageviews, bounce rate, revenue, top pages, top sources)
- **Comparison** — Include a comparison to the previous period (e.g., this week vs. last week)
4. Add recipients and click **Save**
Reports are sent at 9:00 AM in the timezone configured for your site.
Change your site timezone in **Site Settings -> General**.
## Customizing Report Content
Each report can include any combination of the following sections:
| Section | Description |
| ------- | ----------- |
| **Summary** | Total visitors, pageviews, bounce rate, and visit duration |
| **Revenue** | Total revenue, number of purchases, average order value |
| **Top Pages** | Top 10 pages by pageviews |
| **Top Sources** | Top 10 traffic sources |
| **Top Countries** | Top 10 countries by visitors |
| **Goals** | Conversion counts for your tracked goals |
Toggle sections on or off when creating or editing a report.
## Managing Recipients
Reports can be sent to any email address — recipients do not need an EngageTrack account:
- **Add recipients** when creating a report, or edit an existing report to add more
- **Remove recipients** by clicking the remove icon next to their email
- **Team members** with access to the site are suggested automatically
Only site owners and admins can create and manage email reports. Team
members with viewer access cannot modify report settings.
## Managing Reports
View and manage all scheduled reports from **Site Settings -> Email Reports**:
- **Pause** a report to temporarily stop delivery without deleting the configuration
- **Edit** a report to change the frequency, metrics, or recipients
- **Delete** a report to stop it permanently
- **Send now** to trigger an immediate delivery for testing
## Example Report
A weekly email report includes:
- **Subject:** "EngageTrack Weekly Report — example.com — Mar 10-16, 2026"
- **Summary metrics** with percentage change vs. the previous week
- **Top 10 pages and sources** in a clean table format
- **Revenue summary** if revenue tracking is enabled
- A link to view the full dashboard for the reported period
---
URL: https://engagetrack.net/docs/proxy/overview.md
---
title: Proxy Setup
description: Improve tracking accuracy by proxying the SDK through your own domain.
order: 1
---
# Proxy Setup
Proxying the EngageTrack SDK through your own domain improves tracking accuracy by preventing ad blockers from blocking the tracking script and API requests.
## Why Use a Proxy
- **Ad blocker bypass** — Ad blockers maintain lists of known analytics domains. Serving the script from your own domain avoids these lists entirely.
- **First-party context** — Requests to your own domain are treated as first-party by browsers, avoiding third-party restrictions.
- **Privacy compliance** — Data stays within your infrastructure before being forwarded, which can simplify GDPR data processing documentation.
## How It Works
A proxy setup involves two things:
1. **Serve the SDK script** from your domain instead of `cdn.engagetrack.net`
2. **Relay event data** from your domain to the EngageTrack API at `api.engagetrack.net`
The visitor's browser only ever communicates with your domain. Your server forwards the requests to EngageTrack behind the scenes.
```
Browser → yourdomain.com/js/script.js → cdn.engagetrack.net/sdk.js
Browser → yourdomain.com/api/event → api.engagetrack.net/api/v1/event
```
## Updated Script Tag
After setting up the proxy, update your script tag to use your proxy URLs:
```html
```
The `data-api` attribute tells the SDK to send events to your proxy endpoint instead of the default EngageTrack API.
Make sure your proxy forwards the original client IP address in the
`X-Forwarded-For` header. EngageTrack uses IP geolocation for country-level
analytics. Without the real IP, all visitors will appear to come from your
server's location.
## Proxy Guides
Choose the guide that matches your stack:
- [Next.js Proxy](/docs/proxy/nextjs) — Using rewrites or middleware
- [Nginx Proxy](/docs/proxy/nginx) — Reverse proxy configuration
- [Express.js Proxy](/docs/proxy/express) — Node.js middleware
The proxy approach works with any server that can forward HTTP requests.
The guides above cover the most common setups. The pattern is always the
same: proxy the script file and the event endpoint.
---
URL: https://engagetrack.net/docs/proxy/nextjs.md
---
title: Next.js Proxy
description: Set up an EngageTrack proxy with Next.js middleware or rewrites.
order: 2
---
# Next.js Proxy
There are two ways to proxy EngageTrack through a Next.js application: **rewrites** (simplest) or **middleware** (more control).
## Option 1: Rewrites (Recommended)
Add rewrites to your `next.config.js` (or `next.config.ts`):
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{
source: "/js/script.js",
destination: "https://cdn.engagetrack.net/sdk.js",
},
{
source: "/api/event",
destination: "https://api.engagetrack.net/api/v1/event",
},
];
},
};
module.exports = nextConfig;
```
Then update your script tag:
```html
```
Next.js rewrites automatically forward the client's IP address and
headers, so geolocation works out of the box.
### Next.js App Router Component
If you use the App Router, create a component to load the script:
```tsx
// components/engagetrack.tsx
export function EngageTrack() {
return (
);
}
```
Add it to your root layout:
```tsx
// app/layout.tsx
import { EngageTrack } from "@/components/engagetrack";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Option 2: Middleware
For more control (e.g., adding custom headers, rate limiting), use Next.js middleware:
```typescript
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
const url = request.nextUrl.pathname;
if (url === "/js/script.js") {
return NextResponse.rewrite(
new URL("https://cdn.engagetrack.net/sdk.js")
);
}
if (url === "/api/event") {
const destination = new URL("https://api.engagetrack.net/api/v1/event");
const response = NextResponse.rewrite(destination);
// Forward the client IP for geolocation
const ip = request.headers.get("x-forwarded-for") || request.ip;
if (ip) {
response.headers.set("X-Forwarded-For", ip);
}
return response;
}
return NextResponse.next();
}
export const config = {
matcher: ["/js/script.js", "/api/event"],
};
```
If you already have middleware in your project, merge the EngageTrack
routes into your existing middleware function rather than creating a
separate file. Next.js only supports a single `middleware.ts`.
## Verify the Proxy
1. Open your site and check that the script loads from your domain (Network tab in DevTools)
2. Add `data-debug="true"` to the script tag
3. Open the console and confirm events are being sent to `/api/event` (your proxy) instead of `api.engagetrack.net`
4. Check the EngageTrack dashboard — pageviews should appear within a few seconds
---
URL: https://engagetrack.net/docs/proxy/nginx.md
---
title: Nginx Proxy
description: Set up an EngageTrack proxy with Nginx reverse proxy.
order: 3
---
# Nginx Proxy
Nginx is ideal for proxying EngageTrack because it handles the forwarding at the web server level with minimal overhead.
## Configuration
Add the following `location` blocks to your Nginx server configuration:
```nginx
server {
listen 443 ssl;
server_name yourdomain.com;
# ... your existing SSL and site configuration ...
# Proxy the EngageTrack SDK script
location = /js/script.js {
proxy_pass https://cdn.engagetrack.net/sdk.js;
proxy_set_header Host cdn.engagetrack.net;
proxy_ssl_server_name on;
# Cache the script for 1 hour to reduce upstream requests
proxy_cache_valid 200 1h;
proxy_cache_use_stale error timeout updating;
}
# Proxy the event API endpoint
location = /api/event {
proxy_pass https://api.engagetrack.net/api/v1/event;
proxy_set_header Host api.engagetrack.net;
proxy_ssl_server_name on;
# Forward the real client IP for geolocation
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
# Pass through the request body
proxy_set_header Content-Type $content_type;
proxy_pass_request_body on;
}
}
```
## Proxy Headers
These headers are important for correct behavior:
| Header | Purpose |
| ------ | ------- |
| `Host` | Set to the upstream hostname so EngageTrack's servers route the request correctly. |
| `X-Forwarded-For` | Pass the visitor's real IP address for geolocation. |
| `X-Real-IP` | Alternative IP header, used as a fallback by some configurations. |
| `proxy_ssl_server_name on` | Enable SNI so the TLS handshake uses the correct upstream hostname. |
Without `proxy_ssl_server_name on`, Nginx may fail to connect to the
upstream HTTPS server. This is the most common misconfiguration.
## Caching the Script
The SDK script changes infrequently, so caching it reduces load on the upstream CDN. Add a caching zone if you have not already:
```nginx
# In the http block (outside server)
proxy_cache_path /var/cache/nginx/engagetrack
levels=1:2
keys_zone=engagetrack:1m
max_size=10m
inactive=2h;
# In the location block for the script
location = /js/script.js {
proxy_pass https://cdn.engagetrack.net/sdk.js;
proxy_set_header Host cdn.engagetrack.net;
proxy_ssl_server_name on;
proxy_cache engagetrack;
proxy_cache_valid 200 1h;
proxy_cache_use_stale error timeout updating;
add_header X-Cache-Status $upstream_cache_status;
}
```
Do **not** cache the event endpoint (`/api/event`). Each event POST must
be forwarded to the EngageTrack API in real time.
## Updated Script Tag
After configuring Nginx, update your tracking script:
```html
```
## Test the Configuration
1. Reload Nginx: `sudo nginx -t && sudo systemctl reload nginx`
2. Verify the script loads: `curl -I https://yourdomain.com/js/script.js`
3. Verify the event endpoint: `curl -X POST https://yourdomain.com/api/event -H "Content-Type: application/json" -d '{"test": true}'`
4. Check your site in a browser with `data-debug="true"` and confirm events are sent through the proxy
---
URL: https://engagetrack.net/docs/proxy/express.md
---
title: Express.js Proxy
description: Set up an EngageTrack proxy with Express.js middleware.
order: 4
---
# Express.js Proxy
Use `http-proxy-middleware` to proxy EngageTrack requests through your Express.js server.
## Install Dependencies
```bash
npm install http-proxy-middleware
```
## Route Configuration
```javascript
const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
const app = express();
// Proxy the SDK script
app.use(
"/js/script.js",
createProxyMiddleware({
target: "https://cdn.engagetrack.net",
changeOrigin: true,
pathRewrite: { "^/js/script.js": "/sdk.js" },
})
);
// Proxy the event API endpoint
app.use(
"/api/event",
createProxyMiddleware({
target: "https://api.engagetrack.net",
changeOrigin: true,
pathRewrite: { "^/api/event": "/api/v1/event" },
onProxyReq: (proxyReq, req) => {
// Forward the real client IP for geolocation
const clientIp =
req.headers["x-forwarded-for"] ||
req.socket.remoteAddress;
if (clientIp) {
proxyReq.setHeader("X-Forwarded-For", clientIp);
}
},
})
);
// ... your other routes ...
app.listen(3000, () => {
console.log("Server running on port 3000");
});
```
## TypeScript Version
```typescript
import express from "express";
import { createProxyMiddleware } from "http-proxy-middleware";
const app = express();
app.use(
"/js/script.js",
createProxyMiddleware({
target: "https://cdn.engagetrack.net",
changeOrigin: true,
pathRewrite: { "^/js/script.js": "/sdk.js" },
})
);
app.use(
"/api/event",
createProxyMiddleware({
target: "https://api.engagetrack.net",
changeOrigin: true,
pathRewrite: { "^/api/event": "/api/v1/event" },
onProxyReq: (proxyReq, req) => {
const clientIp =
req.headers["x-forwarded-for"] ||
req.socket.remoteAddress;
if (clientIp) {
proxyReq.setHeader("X-Forwarded-For", String(clientIp));
}
},
})
);
app.listen(3000);
```
The `changeOrigin: true` option sets the `Host` header to the target
hostname, which is required for the upstream server to route the request
correctly.
## Without http-proxy-middleware
If you prefer not to add a dependency, use Node's built-in `fetch` (Node 18+):
```javascript
const express = require("express");
const app = express();
app.use(express.raw({ type: "application/json", limit: "1mb" }));
// Proxy the SDK script
app.get("/js/script.js", async (req, res) => {
const response = await fetch("https://cdn.engagetrack.net/sdk.js");
res.set("Content-Type", "application/javascript");
res.set("Cache-Control", "public, max-age=3600");
const body = await response.text();
res.send(body);
});
// Proxy the event endpoint
app.post("/api/event", async (req, res) => {
const clientIp = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
const response = await fetch("https://api.engagetrack.net/api/v1/event", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Forwarded-For": clientIp || "",
},
body: req.body,
});
res.status(response.status).send(await response.text());
});
app.listen(3000);
```
Always forward the `X-Forwarded-For` header with the client's real IP
address. Without it, all visitors will be geolocated to your server's
location.
## Updated Script Tag
```html
```
---
URL: https://engagetrack.net/docs/integrations/github.md
---
title: GitHub Integration
description: Connect GitHub for deploy annotations on your analytics charts.
order: 1
---
# GitHub Integration
EngageTrack integrates with GitHub to annotate your analytics charts with deployment markers, so you can correlate traffic changes with code releases.
## Connecting GitHub
1. Navigate to **Site Settings → Integrations → GitHub**
2. Click **Connect GitHub**
3. Authorize EngageTrack via OAuth
4. Select a repository to link
GitHub OAuth connects your GitHub account for the integration feature. It
does not replace your regular EngageTrack login.
## How It Works
When a repository is linked, EngageTrack:
1. Listens for push events on your default branch
2. Creates an annotation for each deployment with the commit message, author, and timestamp
3. Displays deploy markers directly on the analytics time-series chart
This lets you immediately see how a deployment affected your traffic, conversions, or bounce rate.
## Importing Recent Commits
When you first link a repository, you can import recent commits to backfill deployment markers on your existing charts.
## Unlinking
To disconnect the GitHub integration, go to **Site Settings → Integrations → GitHub** and click **Disconnect**. Existing annotations remain visible after unlinking.
## Required Permissions
- **Viewing** the integration status: Viewer role or higher
- **Connecting, importing, unlinking**: Admin role or higher
---
URL: https://engagetrack.net/docs/integrations/revenue-providers.md
---
title: Revenue Providers
description: Connect Stripe, Lemon Squeezy, Paddle, or Polar for automatic revenue attribution.
order: 2
---
# Revenue Provider Integrations
EngageTrack connects to your payment provider to automatically attribute revenue to traffic sources. This powers the Revenue dashboard, showing exactly which channels drive real business results.
## Supported Providers
- **Stripe**
- **Lemon Squeezy**
- **Paddle**
- **Polar**
## Connecting a Provider
1. Navigate to **Site Settings → Revenue**
2. Select your payment provider
3. Authenticate:
- **Stripe** — click **Connect with Stripe** to complete the OAuth flow (~30 seconds; no API key needed)
- **Lemon Squeezy, Paddle, Polar** — enter your API key (and store/org ID where required)
4. Select your reporting currency
5. Click **Connect**
During connection, EngageTrack validates your credentials and automatically registers a webhook on the provider. No manual webhook setup is required.
API keys are encrypted at rest and are never displayed in the dashboard after
initial setup.
## Revenue Attribution
Once connected, here's how attribution works:
1. A visitor lands on your site → EngageTrack records their identity and traffic source
2. The visitor makes a purchase → your payment provider sends EngageTrack a webhook
3. EngageTrack matches the payment to the visitor and attributes the revenue to the original traffic source
Revenue is attributed using both **first-touch** (the source that originally brought the visitor) and **last-touch** (the most recent source before purchase) models.
### Linking Visitors to Payments
For accurate attribution, pass the EngageTrack visitor ID to your payment provider. For example, with Stripe:
```javascript
const session = await stripe.checkout.sessions.create({
metadata: {
engagetrack_visitor_id: visitorId, // from engagetrack.getVisitorId()
},
// ...other options
});
```
## Changing Currency
You can update your reporting currency at any time from **Site Settings → Revenue**. Revenue from different currencies is automatically converted to your reporting currency using daily exchange rates.
## Disconnecting
To disconnect your revenue provider, go to **Site Settings → Revenue** and click **Disconnect**. Existing revenue data is preserved.
## Required Permissions
- **Viewing** revenue data: Viewer role or higher
- **Connecting, updating, disconnecting**: Admin role or higher
---
URL: https://engagetrack.net/docs/frontend/dashboard.md
---
title: Dashboard Guide
description: Navigating the EngageTrack dashboard — sites, settings, and analytics views.
order: 1
---
# Dashboard Guide
The EngageTrack dashboard is the main interface for viewing your analytics. It's available at `/dashboard` after logging in.
## Site List
After login, you'll see all sites belonging to your current organization. Each card shows:
- **Domain** and site name
- **Status** — whether the tracking script is verified
- Quick stats (if data is available)
Click a site to open its analytics dashboard.
## Creating a Site
1. Click **Add Site** from the dashboard
2. Enter the site domain (e.g., `mysite.com`) and a display name
3. Copy the tracking snippet and add it to your website's `` tag
```html
```
Once the script is installed and a pageview is detected, the site card updates to show **Tracking verified**.
## Dashboard Tabs
The analytics dashboard for each site includes:
| Tab | Content |
| --------------- | ------------------------------------------------------ |
| **Overview** | KPI cards, time-series chart, all breakdown panels |
| **Goals** | Conversion goals with completion counts and rates |
| **Funnels** | Multi-step conversion funnel visualizations |
| **Visitors** | Individual visitor profiles and event timelines |
| **Revenue** | Revenue attribution by source with first/last-touch |
## Organization Settings
Navigate to **Settings** (from the sidebar) to manage:
- **General** — Organization name, slug
- **Branding** — White-label logo, color, and custom domain (Agency plan only)
- **Team** — Invite members, manage roles, transfer ownership
- **Billing** — Subscription plan, payment methods, invoices, usage
- **Danger Zone** — Delete the organization
## Site Settings
From any site's dashboard, click the gear icon to access:
- **General** — Site name, domain
- **Tracking** — Toggle outbound links, file downloads, phone clicks, form submissions, custom events, localhost tracking
- **Exclusions** — Exclude specific IPs and page paths from tracking
- **Timezone** — Set the reporting timezone
- **Public Dashboard** — Enable/disable the public-facing dashboard with granular control over which sections are visible
- **Integrations** — Connect GitHub for deploy annotations, connect revenue providers
- **Danger Zone** — Delete the site
---
URL: https://engagetrack.net/docs/frontend/public-dashboards.md
---
title: Public Dashboards
description: Share your analytics publicly with a customizable, read-only dashboard.
order: 2
---
# Public Dashboards
EngageTrack lets you share a read-only version of your analytics with anyone — no login required.
## Enabling
1. Go to **Site Settings → Public Dashboard**
2. Toggle **Enable public dashboard**
3. Copy the shareable URL and send it to anyone
## Visibility Controls
You have granular control over what visitors to your public dashboard can see. Each section can be independently toggled:
| Toggle | Controls |
| ------------------- | ---------------------- |
| **Visitors** | Unique visitors KPI |
| **Pageviews** | Pageviews KPI |
| **Bounce Rate** | Bounce rate KPI |
| **Session Duration**| Session duration KPI |
| **Realtime** | Online visitor count |
| **Chart** | Time-series chart |
| **Sources** | Sources breakdown |
| **Locations** | Location breakdown |
| **Pages** | Pages breakdown |
| **Devices** | Devices breakdown |
Each toggle independently controls a section. Disabled sections are
completely hidden from the public dashboard.
## Limitations
- Revenue data is never exposed on public dashboards
- Individual visitor profiles are not available publicly
- Data is capped to the last 12 months
Public dashboards are intended for transparency, not confidentiality. Anyone
with the link can view the enabled metrics. Don't enable them if your traffic
data is sensitive.
---
URL: https://engagetrack.net/docs/billing/plans.md
---
title: Plans & Pricing
description: Understand EngageTrack's subscription plans, features, and usage limits.
order: 1
---
# Plans & Pricing
EngageTrack offers three subscription plans. Each plan defines event limits, site limits, data retention, team size, and feature access.
## Plans at a Glance
| | **Maker** | **Startup** | **Agency** |
| --- | --- | --- | --- |
| **Price** | €5/mo | €20/mo | €50/mo |
| **Events / month** | 10,000 | 200,000 | 2,000,000 |
| **Sites** | 3 | 10 | Unlimited |
| **Team members** | 3 | 10 | Unlimited |
| **Data retention** | 12 months | 24 months | 36 months |
| **Email Reports** | ✓ | ✓ | ✓ |
| **CSV Export** | — | ✓ | ✓ |
| **API Access** | — | ✓ | ✓ |
| **White Label** | — | — | ✓ |
| **Custom Domain** | — | — | ✓ |
| **Priority Support** | — | — | ✓ |
Yearly billing is available on all plans at a discounted rate. Visit the [pricing page](/) for current yearly prices.
## Feature Notes
- **Events** — An event is any tracked interaction: pageview, custom event, outbound click, form submission, etc.
- **API Access** — Programmatic access to your analytics data via REST API with scoped API keys (Startup and above).
- **White Label** — Replace EngageTrack branding with your own logo and colors across the dashboard (Agency only).
- **Custom Domain** — Proxy the tracking script through your own domain to improve ad blocker bypass rates (Agency only).
## Free Trial
New organizations start with a **14-day free trial**. During the trial:
- All features are available
- No payment method is required
- You'll receive email reminders before the trial ends
Once the trial expires, you'll need to subscribe to a paid plan to continue using EngageTrack.
## Billing Cycle
Plans are available in **monthly** or **yearly** billing cycles. Yearly plans offer a discount compared to paying monthly.
---
URL: https://engagetrack.net/docs/billing/subscription-management.md
---
title: Subscription Management
description: Subscribe, upgrade, downgrade, cancel, and manage your billing.
order: 2
---
# Subscription Management
All billing actions are managed from **Organization Settings → Billing** and require the **Owner** role.
## Subscribing
After your free trial, subscribe to a plan:
1. Go to **Settings → Billing**
2. Select a plan and billing cycle (monthly or yearly)
3. Enter your payment details
4. Optionally apply a coupon code
5. Confirm your subscription
Email verification is required before subscribing. Verify your email from
**Settings → Account** if you haven't already.
## Upgrading or Downgrading
You can change your plan at any time from the Billing page. When you upgrade, you'll be charged the prorated difference immediately. When you downgrade, you receive credit toward future invoices.
Before switching, you can preview the exact amount you'll be charged or credited.
## Canceling
Cancel your subscription from the Billing page. After cancellation:
- Your subscription remains active until the end of the current billing period
- All your data is retained
- You can reactivate at any time before the period ends
## Reactivating
If you cancel but change your mind before the period ends, simply click **Reactivate** from the Billing page. Your subscription continues without interruption.
## Payment Methods
- **Update card** — Add a new card and set it as default from the Billing page
- **Remove card** — Remove an old payment method (you cannot remove your last active card on a paid plan)
## Billing Profile
Update your invoicing address and tax information (company name, address, VAT/tax ID) from **Settings → Billing → Billing Profile**. This information appears on your invoices.
## Invoices
View and download all past invoices from the Billing page. For advanced billing management, use the **Stripe Customer Portal** link to access your full invoice history.
## Usage
Track your current pageview usage and see how much of your plan limit you've consumed from the Billing page. The counter resets at the start of each billing cycle.
---
URL: https://engagetrack.net/docs/team/invitations.md
---
title: Team Invitations
description: Invite team members and manage roles with EngageTrack's RBAC system.
order: 1
---
# Team Invitations
EngageTrack supports multi-user teams with four permission tiers. Invite your colleagues and control exactly what they can see and do.
## Roles
| Role | Permissions |
| ---------- | ----------------------------------------------------- |
| **Owner** | Full access — billing, team management, site deletion |
| **Admin** | Manage team members, sites, and settings (no billing) |
| **Member** | View analytics for assigned sites, manage goals and funnels |
| **Viewer** | Read-only access to analytics dashboards |
## Sending an Invitation
1. Navigate to **Settings → Team**
2. Click **Invite Member**
3. Enter the person's email address
4. Select a role
5. Optionally restrict access to specific sites
```
POST /api/v1/organizations/:orgId/team/invites
{
"email": "teammate@company.com",
"role": "member",
"site_ids": ["site-uuid-1", "site-uuid-2"] // optional
}
```
Invitations expire after **7 days**. The invitee will receive an email with a
link to accept.
## Per-Site Access Control
For larger teams, you can restrict members to specific sites:
- **Owners** and **Admins** always have access to all sites
- **Members** and **Viewers** can be scoped to individual sites
- Access is managed in **Settings → Team → Edit Member**
## Ownership Transfer
Organization owners can transfer ownership to another admin:
1. Go to **Settings → Team**
2. Click the menu icon next to the target admin
3. Select **Transfer Ownership**
Ownership transfer is irreversible. You will be demoted to Admin role.
---
URL: https://engagetrack.net/docs/team/roles.md
---
title: Roles & Permissions
description: Understand the four permission tiers in EngageTrack's role-based access control system.
order: 2
---
# Roles & Permissions
EngageTrack uses a four-tier role system to manage what each team member can do within an organization.
## Role Hierarchy
| Role | Description |
| ---------- | ----------------------------------------------------- |
| **Owner** | Full control — billing, team management, site deletion |
| **Admin** | Manage team, sites, and settings (no billing access) |
| **Member** | View analytics and manage goals, funnels, and annotations |
| **Viewer** | Read-only access to analytics dashboards |
## Permission Matrix
| Action | Owner | Admin | Member | Viewer |
| ------------------------------- | ----- | ----- | ------ | ------ |
| View analytics | ✅ | ✅ | ✅ | ✅ |
| View goals & funnel stats | ✅ | ✅ | ✅ | ✅ |
| Edit/archive goals | ✅ | ✅ | ✅ | ❌ |
| Create/edit/delete funnels | ✅ | ✅ | ✅ | ❌ |
| Create/delete annotations | ✅ | ✅ | ✅ | ❌ |
| Create/edit/delete sites | ✅ | ✅ | ❌ | ❌ |
| Update site settings | ✅ | ✅ | ❌ | ❌ |
| Update organization settings | ✅ | ✅ | ❌ | ❌ |
| Connect integrations | ✅ | ✅ | ❌ | ❌ |
| Invite/remove team members | ✅ | ✅ | ❌ | ❌ |
| Change member roles | ✅ | ✅ | ❌ | ❌ |
| Manage site access per member | ✅ | ✅ | ❌ | ❌ |
| Manage billing & subscription | ✅ | ❌ | ❌ | ❌ |
| Transfer ownership | ✅ | ❌ | ❌ | ❌ |
| Delete organization | ✅ | ❌ | ❌ | ❌ |
## Email Verification
Certain actions require a verified email address:
- Subscribing to a paid plan
- Sending team invitations
## Changing Roles
Admins and owners can change any member's role from the **Team** settings page.
An organization must always have exactly one owner. To change the owner, use
the ownership transfer feature instead.
## Leaving an Organization
Any member (except the owner) can leave an organization from the **Team** settings page.
## Ownership Transfer
The owner can transfer ownership to any admin from **Settings → Team → Transfer Ownership**. After transfer, the original owner is demoted to the Admin role. This action is **irreversible**.
---
URL: https://engagetrack.net/docs/team/site-access.md
---
title: Site Access Control
description: Restrict team members to specific sites within your organization.
order: 3
---
# Site Access Control
For organizations with multiple sites, you can restrict which sites specific team members can access.
## How It Works
- **Owners** and **Admins** always have access to all sites — they cannot be restricted
- **Members** and **Viewers** can be scoped to specific sites
- By default, all members can see all sites (no restrictions)
- Once you assign specific sites to a member, they can only see those sites
## Managing Site Access
1. Go to **Settings → Team**
2. Click on a team member
3. Under **Site Access**, select which sites they should be able to view
4. Save the changes
To restore full access, remove all site restrictions for that member.
## Behavior
When a member has site restrictions:
- The **dashboard** only shows their assigned sites
- **Analytics data** only covers their assigned sites
- **Goals, funnels, and visitors** are scoped to accessible sites only
## Example
Imagine you have an agency with three client sites:
| Site | Marketing Team | Design Team |
| --------------- | -------------- | ----------- |
| client-a.com | ✅ | ✅ |
| client-b.com | ✅ | ❌ |
| client-c.com | ❌ | ✅ |
Each team's members would only see the sites they're assigned to.
## Permissions
Only **Admin** and **Owner** roles can view and modify site access assignments.
Site access restrictions only apply to Members and Viewers. Admins and Owners
always see all sites.
---
URL: https://engagetrack.net/docs/api/authentication.md
---
title: API Authentication
description: Authenticate with the EngageTrack API using API keys.
order: 1
---
# API Authentication
All EngageTrack API requests are authenticated using **API keys**. API keys provide scoped, long-lived access and are designed for server-side integrations, CI/CD pipelines, data warehouses, and automation workflows.
## Getting an API Key
1. Navigate to **Settings > API Keys** in your dashboard
2. Click **Create API Key**
3. Enter a descriptive name (e.g., `Data Warehouse Sync`)
4. Select the [scopes](/docs/api/api-keys#scope-reference) your integration needs
5. Optionally set an expiration date
6. Click **Create** and copy the key immediately
The full API key is shown **only once** at creation. Copy it and store it
securely — in a secrets manager or environment variable. If you lose it, you
must revoke the key and create a new one.
API keys require a **Startup plan** or higher. See [Plans &
Pricing](/docs/billing/plans) for details.
## Using an API Key
Pass the key as a Bearer token in the `Authorization` header of every request:
```bash
curl https://api.engagetrack.net/api/v1/organizations/{orgId}/sites \
-H "Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
```
## Key Format
API keys follow the format `et_live_` followed by 32 hexadecimal characters:
```
et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
```
## Scopes
API keys are granted specific scopes that control which endpoints they can access. Assign only the scopes your integration needs.
| Resource | Scope | Grants access to |
| --- | --- | --- |
| **Analytics** | `analytics:read` | Stats, charts, pages, sources, devices, locations, revenue, channels |
| **Sites** | `sites:read` | List sites and get site details |
| **Goals** | `goals:read` | List goals, goal stats, and goal completions |
| **Goals** | `goals:write` | Update and archive/unarchive goals |
| **Funnels** | `funnels:read` | List funnels and view funnel analysis |
| **Funnels** | `funnels:write` | Create, update, and delete funnels |
| **Annotations** | `annotations:read` | List annotations |
| **Annotations** | `annotations:write` | Create and delete annotations |
| **Visitors** | `visitors:read` | List visitors and view visitor timelines |
Write scopes do not imply read access. If your integration needs to both read
and write goals, assign both `goals:read` and `goals:write`.
## Limits
- Maximum **10 API keys** per organization
- API keys grant access to **data endpoints only** (analytics, goals, funnels, annotations, visitors, sites)
- API keys **cannot** access management endpoints (billing, team, integrations)
- Rate limits apply per-key — see [Rate Limiting](/docs/api-reference/overview#rate-limiting)
## Expiration
API keys can have an optional expiration date. Expired keys return `401 Unauthorized`. We recommend setting an expiration and rotating keys periodically.
## Security Best Practices
- **Use minimal scopes.** Only assign what your integration actually needs.
- **Set an expiration date.** Avoid keys that live forever. Rotate before expiry.
- **Store keys securely.** Use environment variables or a secrets manager. Never commit API keys to version control or embed them in client-side code.
- **One key per integration.** If one integration is compromised, you can revoke it without affecting others.
## Error Responses
### 401 Unauthorized
```json
{ "error": "Invalid or expired API key" }
```
The key does not exist, has been revoked, or has expired.
### 402 Payment Required
```json
{ "error": "API key access requires a Startup plan or higher" }
```
Upgrade your plan at **Settings > Billing**.
### 403 Forbidden
```json
{ "error": "API key missing required scope: analytics:read" }
```
The key lacks the scope needed for this endpoint. Create a new key with the correct scopes.
---
For full key management (creating, listing, and revoking keys) see the [API Keys guide](/docs/api/api-keys).
---
URL: https://engagetrack.net/docs/api/api-keys.md
---
title: API Keys
description: Create and manage API keys for programmatic access to your analytics data.
order: 2
---
# API Keys
API keys let you access EngageTrack data programmatically without a user session. They are ideal for server-side integrations, automated reporting, data warehouse syncs, and CI/CD pipelines.
API keys require a **Startup plan** or higher. Organizations on the Maker
plan will receive a `402` error when attempting to create a key.
## Creating an API Key
### Via the Dashboard
1. Go to **Settings > API Keys**
2. Click **Create API Key**
3. Enter a name and select scopes
4. Click **Create** and copy the key immediately
The full key is shown **only once**. Store it in a secure location such as a
secrets manager or environment variable. If you lose it, you must revoke the
key and create a new one.
### Via the API
You can also create API keys programmatically. Key management endpoints require a user session token — obtain one by logging in via the dashboard or the `/api/v1/auth/login` endpoint.
```bash
curl -X POST \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/api-keys' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"name": "Data Warehouse Sync",
"scopes": ["analytics:read", "sites:read"],
"expires_at": "2026-12-31T23:59:59Z"
}'
```
The response includes the full key in the `key` field. This is the only time the full key is returned.
## Scope Reference
Scopes control which API endpoints a key can access. Assign only the scopes your integration needs.
| Resource | Scope | Grants access to |
| --- | --- | --- |
| **Analytics** | `analytics:read` | Stats, charts, pages, sources, devices, locations, revenue, channels, and all other analytics breakdowns |
| **Sites** | `sites:read` | List sites and get site details |
| **Goals** | `goals:read` | List goals, goal stats, and goal completions |
| **Goals** | `goals:write` | Update and archive/unarchive goals |
| **Funnels** | `funnels:read` | List funnels and view funnel analysis |
| **Funnels** | `funnels:write` | Create, update, and delete funnels |
| **Annotations** | `annotations:read` | List annotations |
| **Annotations** | `annotations:write` | Create and delete annotations |
| **Visitors** | `visitors:read` | List visitors and view visitor timelines |
Write scopes do not imply read access. If your integration needs to both read
and write goals, assign both `goals:read` and `goals:write`.
## Usage Examples
All examples use the base URL `https://api.engagetrack.net/api/v1`.
### Get site analytics stats
```bash
curl -X GET \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/sites/{siteId}/analytics/stats?period=30d' \
-H 'Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'
```
**Required scope:** `analytics:read`
### List all sites
```bash
curl -X GET \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/sites' \
-H 'Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'
```
**Required scope:** `sites:read`
### Export page analytics
```bash
curl -X GET \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/sites/{siteId}/analytics/pages?period=30d&limit=100' \
-H 'Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'
```
**Required scope:** `analytics:read`
### List visitors
```bash
curl -X GET \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/sites/{siteId}/visitors?page=1&limit=50' \
-H 'Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'
```
**Required scope:** `visitors:read`
## Security Best Practices
- **Use minimal scopes.** Only assign the scopes your integration actually needs. A reporting dashboard only needs `analytics:read` and `sites:read`.
- **Set an expiration date.** Avoid creating keys that live forever. Set a reasonable expiration (e.g., 90 days) and rotate before it expires.
- **Store keys securely.** Use environment variables or a secrets manager. Never commit API keys to version control or embed them in client-side code.
- **Rotate keys regularly.** Create a new key, update your integration, then revoke the old key. This limits the impact of a leaked key.
- **Use one key per integration.** If one integration is compromised, you can revoke its key without affecting others.
- **Monitor usage.** Review your active API keys periodically in **Settings > API Keys** and revoke any that are no longer in use.
## Rate Limits
API key requests are rate-limited per key. Analytics endpoints allow up to **600 requests per minute**. If you exceed the limit, the API returns `429 Too Many Requests` with `X-RateLimit-*` headers indicating when you can retry.
| Header | Description |
| --- | --- |
| `X-RateLimit-Limit` | Maximum requests allowed in the current window |
| `X-RateLimit-Remaining` | Requests remaining in the current window |
| `X-RateLimit-Reset` | Unix timestamp when the window resets |
## Error Responses
### 401 Unauthorized — Invalid or expired key
```json
{
"error": "Invalid or expired API key"
}
```
The key does not exist, has been revoked, or has expired. Create a new key if needed.
### 402 Payment Required — Subscription required
```json
{
"error": "API key access requires a Startup plan or higher"
}
```
Your organization is on the Maker plan, which does not include API access. Upgrade to Startup or Agency at **Settings > Billing**.
### 403 Forbidden — Missing scope
```json
{
"error": "API key missing required scope: analytics:read"
}
```
The key does not have the scope needed for the requested endpoint. Create a new key with the correct scopes.
### 429 Too Many Requests — Rate limited
```json
{
"error": "Rate limit exceeded. Retry after 2026-03-14T12:01:00Z"
}
```
Back off and retry after the time indicated in the `X-RateLimit-Reset` header.
## Managing API Keys
### Listing Keys
View all active API keys in **Settings > API Keys**, or via the API (requires session token):
```bash
curl -X GET \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/api-keys' \
-H 'Authorization: Bearer '
```
The list shows each key's name, scopes, creation date, expiration, and a masked preview of the key (last 4 characters only).
### Revoking a Key
Revoke a key from the dashboard by clicking the **Revoke** button, or via the API (requires session token):
```bash
curl -X DELETE \
'https://api.engagetrack.net/api/v1/organizations/{orgId}/api-keys/{keyId}' \
-H 'Authorization: Bearer '
```
Revoked keys stop working immediately. This action cannot be undone.
---
URL: https://engagetrack.net/docs/api-reference/overview.md
---
title: API Reference
description: Complete REST API reference for EngageTrack.
order: 1
---
# API Reference
All API endpoints are served under `/api/v1` and require authentication via the `Authorization` header unless otherwise noted.
## Base URL
```
https://api.engagetrack.net/api/v1
```
## Authentication
All API requests are authenticated using **API keys**. Pass the key as a Bearer token in the `Authorization` header:
```bash
curl -H "Authorization: Bearer et_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
https://api.engagetrack.net/api/v1/organizations/{orgId}/sites
```
API keys provide scoped access to data endpoints (analytics, goals, funnels, annotations, visitors, sites). Create and manage keys in **Settings > API Keys**. See the [Authentication guide](/docs/api/authentication) for full details.
## Response Format
All successful responses are wrapped in a standard envelope:
```json
{
"success": true,
"data": { ... }
}
```
Error responses use:
```json
{
"error": "Error message"
}
```
## Common Query Parameters
Most analytics endpoints accept these filters:
| Parameter | Type | Description |
| --------- | -------- | --------------------------------------------- |
| `period` | `string` | `day`, `7d`, `30d`, `month`, `12mo`, `custom` |
| `date` | `string` | ISO date – base date for the period |
| `from` | `string` | Start date for custom range |
| `to` | `string` | End date for custom range |
| `filters` | `string` | JSON-encoded filter array |
## HTTP Status Codes
| Code | Meaning |
| ----- | --------------------- |
| `200` | Success |
| `201` | Created |
| `202` | Accepted |
| `400` | Bad Request |
| `401` | Unauthorized |
| `403` | Forbidden |
| `404` | Not Found |
| `429` | Rate Limited |
| `500` | Internal Server Error |
## Rate Limiting
Endpoints are rate-limited per IP/user. Auth endpoints have stricter limits (5-50 req/window). Analytics endpoints are more generous. Responses include `X-RateLimit-*` headers.
Browse the sidebar to explore endpoints grouped by resource.
---
URL: https://engagetrack.net/docs/api-reference/get-attribution.md
---
title: Attribution
description: Get revenue attribution data by source and model.
order: 38
method: GET
---
# Attribution
Returns revenue attribution data broken down by source, using the specified attribution model.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/attribution
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `model` | `string` | No | Attribution model: `first_touch` or `last_touch` (default: `last_touch`) |
| `groupBy` | `string` | No | Group results by: `source`, `medium`, or `campaign` (default: `source`) |
## Response fields
Returns an array of attribution entries:
| Field | Type | Description |
| ------------- | -------- | ---------------------------------------- |
| `group` | `string` | Group value (source, medium, or campaign name) |
| `conversions` | `number` | Number of conversions attributed |
| `revenue` | `number` | Attributed revenue |
---
URL: https://engagetrack.net/docs/api-reference/get-campaigns.md
---
title: Campaigns
description: Get campaign breakdown with visitor and revenue data.
order: 36
method: GET
---
# Campaigns
Returns a breakdown of traffic by UTM campaign, ranked by visitor count.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/campaigns
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `limit` | `number` | No | Maximum number of results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of campaign entries:
| Field | Type | Description |
| ---------- | -------- | ------------------------------------ |
| `campaign` | `string` | UTM campaign name |
| `visitors` | `number` | Unique visitors from this campaign |
---
URL: https://engagetrack.net/docs/api-reference/get-channels.md
---
title: Channels
description: Get enriched channel breakdown with UTM parameters for a site.
order: 35
method: GET
---
# Channels
Returns enriched channel data combining UTM parameters with referrer information, ranked by visitor count.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/channels/enriched
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `limit` | `number` | No | Maximum number of results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns a wrapped response with `channels` and `currency`:
| Field | Type | Description |
| ---------- | -------- | ---------------------------------- |
| `channels` | `array` | Array of channel entries (see below) |
| `currency` | `string` | Currency code (e.g. `USD`) |
Each channel entry:
| Field | Type | Description |
| --------------- | -------- | ------------------------------------------------------- |
| `channel` | `string` | Channel name |
| `visitors` | `number` | Unique visitors from this channel |
| `total_revenue` | `number` | Total revenue from this channel |
| `top_sources` | `array` | Top sources within the channel (see below) |
Each `top_sources` entry:
| Field | Type | Description |
| --------- | -------- | --------------------------------- |
| `source` | `string` | Source name |
| `visitors`| `number` | Unique visitors from this source |
| `percent` | `number` | Percentage of channel visitors |
## Related Endpoints
| Endpoint | Description |
| ------------------------- | --------------------------------------------- |
| `.../analytics/sources` | Traffic grouped by top-level source |
| `.../analytics/referrers` | Traffic grouped by normalized referrer domain |
| `.../analytics/campaigns` | Traffic grouped by UTM campaign |
---
URL: https://engagetrack.net/docs/api-reference/get-devices.md
---
title: Devices
description: Get device, browser, or OS breakdown for a site.
order: 34
method: GET
---
# Devices
Returns a breakdown of visitors by device type, browser, or operating system.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/devices
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `type` | `string` | No | Breakdown type: `browser`, `os`, or `device` (default: `device`) |
| `limit` | `number` | No | Maximum number of results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of device entries:
| Field | Type | Description |
| ---------- | -------- | -------------------------------------------- |
| `name` | `string` | Device, browser, or OS name |
| `count` | `number` | Unique visitors using this device/browser/OS |
---
URL: https://engagetrack.net/docs/api-reference/export-csv.md
---
title: Export CSV
description: Export analytics data as a CSV file.
order: 45
method: GET
---
# Export CSV
Exports analytics data as a downloadable CSV file.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/export
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `metric` | `string` | Yes | Export type: `pageviews`, `sources`, `pages`, `devices`, `locations`, or `goals` |
| `filters` | `string` | No | JSON-encoded filter array |
## Response
Returns a CSV file with `Content-Type: text/csv` and a `Content-Disposition` header for download. The columns vary by export type.
---
URL: https://engagetrack.net/docs/api-reference/get-chart.md
---
title: Get Chart Data
description: Retrieve time-series chart data for a site.
order: 3
method: GET
---
# Get Chart Data
Returns time-series data points for rendering analytics charts. Each point includes visitors, pageviews, sessions, revenue, and order counts.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/chart
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------------------------ |
| `period` | `string` | No | Time period |
| `date` | `string` | No | Base date (ISO 8601) |
| `from` | `string` | No | Start date for custom range |
| `to` | `string` | No | End date for custom range |
| `group` | `string` | No | Grouping: `hour` or `day` (default: `day`) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of data points, each containing:
| Field | Type | Description |
| ----------- | -------- | ------------------------- |
| `timestamp` | `string` | ISO 8601 timestamp |
| `visitors` | `number` | Unique visitors in bucket |
| `pageviews` | `number` | Total pageviews in bucket |
| `sessions` | `number` | Unique sessions in bucket |
| `revenue` | `number` | Revenue in bucket |
| `orders` | `number` | Order count in bucket |
---
URL: https://engagetrack.net/docs/api-reference/get-stats.md
---
title: Get Stats
description: Retrieve aggregate analytics statistics for a site.
order: 2
method: GET
---
# Get Stats
Returns aggregate statistics for the given time period.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/stats
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `date` | `string` | No | Base date (ISO 8601) |
| `from` | `string` | No | Start date for custom range |
| `to` | `string` | No | End date for custom range |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
| Field | Type | Description |
| ----------------- | -------- | --------------------------------- |
| `pageviews` | `number` | Total pageviews in the period |
| `unique_visitors` | `number` | Unique visitors (distinct hashes) |
| `sessions` | `number` | Unique sessions |
---
URL: https://engagetrack.net/docs/api-reference/list-annotations.md
---
title: List Annotations
description: Get all annotations for a site.
order: 42
method: GET
---
# List Annotations
Returns all annotations for a site, ordered by date. Annotations are markers on the analytics timeline (e.g. deployments, marketing launches).
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/annotations
```
## Response fields
Returns an array of annotation entries:
| Field | Type | Description |
| ------------- | -------- | ----------------------------------- |
| `id` | `string` | Annotation ID |
| `label` | `string` | Annotation label |
| `occurred_at` | `string` | Annotation date (ISO 8601) |
| `description` | `string` | Optional longer description |
| `color` | `string` | Marker color |
| `created_by` | `object` | Author object with `id`, `name`, `email` |
| `created_at` | `string` | Creation timestamp (ISO 8601) |
---
URL: https://engagetrack.net/docs/api-reference/list-funnels.md
---
title: List Funnels
description: List all funnels for a site.
order: 30
method: GET
---
# List Funnels
Returns all funnels defined for a site, including their steps.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/funnels
```
## Response fields
Each funnel object contains:
| Field | Type | Description |
| ------------- | -------- | -------------------- |
| `id` | `string` | Funnel ID |
| `site_id` | `string` | Site ID |
| `name` | `string` | Funnel name |
| `description` | `string` | Funnel description |
| `steps` | `array` | Ordered funnel steps |
Each step contains:
| Field | Type | Description |
| ------------ | -------- | ------------------------------- |
| `id` | `string` | Step ID |
| `name` | `string` | Step label |
| `order` | `number` | Step position (1-indexed) |
| `type` | `string` | `pageview` or `custom_event` |
| `pattern` | `string` | Page path or event name |
| `match_type` | `string` | `exact`, `contains`, or `regex` |
---
URL: https://engagetrack.net/docs/api-reference/list-goals.md
---
title: List Goals
description: List all goals for a site.
order: 20
method: GET
---
# List Goals
Returns all goals configured for the given site.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/goals
```
## Response fields
Each goal object contains:
| Field | Type | Description |
| ------------ | -------- | -------------------------------------- |
| `id` | `string` | Goal ID |
| `site_id` | `string` | Site ID |
| `name` | `string` | Goal display name |
| `type` | `string` | `pageview` or `custom_event` |
| `pattern` | `string` | Page path or event name to match |
| `match_type` | `string` | `exact`, `contains`, or `regex` |
| `value` | `number` | Optional monetary value per conversion |
| `currency` | `string` | Optional currency code (e.g. `USD`) |
## Goal Stats
To get conversion stats for all goals in a period:
```
GET /api/v1/organizations/:orgId/sites/:siteId/goals/stats
```
Returns an array of stats per goal:
| Field | Type | Description |
| -------------------- | -------- | ------------------------------------ |
| `goal_id` | `string` | Goal ID |
| `name` | `string` | Goal name |
| `type` | `string` | Goal type |
| `conversions` | `number` | Total conversions |
| `unique_conversions` | `number` | Unique visitor conversions |
| `revenue` | `number` | Total revenue from conversions |
| `conversion_rate` | `number` | Percentage of visitors who converted |
---
URL: https://engagetrack.net/docs/api-reference/list-sites.md
---
title: List Sites
description: List all sites in an organization.
order: 10
method: GET
---
# List Sites
Returns all sites belonging to the specified organization that the authenticated user has access to.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites
```
---
URL: https://engagetrack.net/docs/api-reference/list-visitors.md
---
title: List Visitors
description: Get a paginated list of visitors for a site.
order: 40
method: GET
---
# List Visitors
Returns a paginated list of visitors for a site, ordered by most recently seen.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/visitors
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------------------------ |
| `page` | `number` | No | Page number (default: 1) |
| `limit` | `number` | No | Results per page (default: 50, max: 100) |
| `search` | `string` | No | Search by email, name, UID, or external ID |
## Response fields
Each visitor object in the `visitors` array:
| Field | Type | Description |
| ---------------------- | -------- | ----------------------------------- |
| `id` | `string` | Visitor UUID |
| `uid` | `string` | Persistent visitor UID from tracker |
| `email` | `string` | Identified email (if set) |
| `name` | `string` | Identified name (if set) |
| `avatar_url` | `string` | Identified avatar URL (if set) |
| `external_id` | `string` | Your user ID (if identified) |
| `first_seen_at` | `string` | First visit timestamp |
| `last_seen_at` | `string` | Most recent visit timestamp |
| `total_sessions` | `number` | Lifetime session count |
| `total_pageviews` | `number` | Lifetime pageview count |
| `total_goals` | `number` | Lifetime goal completions |
| `total_revenue` | `number` | Lifetime revenue |
| `last_country` | `string` | Most recent country code |
| `last_browser` | `string` | Most recent browser |
| `last_os` | `string` | Most recent operating system |
| `last_device` | `string` | Most recent device type |
| `last_referrer_source` | `string` | Most recent traffic source |
The response also includes pagination metadata: `total`, `page`, and `limit`.
## Visitor Timeline
To get the event timeline for a specific visitor:
```
GET /api/v1/organizations/:orgId/sites/:siteId/visitors/:visitorId/timeline
```
Returns the visitor profile along with a paginated list of their events.
---
URL: https://engagetrack.net/docs/api-reference/get-locations.md
---
title: Locations
description: Get geographic breakdown of visitors for a site.
order: 33
method: GET
---
# Locations
Returns a breakdown of visitors by country, ranked by unique visitor count.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/locations
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `type` | `string` | No | Breakdown type: `country`, `region`, or `city` (default: `country`) |
| `limit` | `number` | No | Maximum number of results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of location entries:
| Field | Type | Description |
| ---------- | -------- | ------------------------------------ |
| `location` | `string` | Location name (country code, region, or city) |
| `visitors` | `number` | Unique visitors from this location |
---
URL: https://engagetrack.net/docs/api-reference/get-realtime.md
---
title: Realtime Stats
description: Get current realtime visitor count.
order: 6
method: GET
---
# Realtime Stats
Returns the number of visitors currently active on the site (within a 5-minute rolling window).
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/realtime
```
## Response fields
| Field | Type | Description |
| ----------------- | -------- | ----------------------------------- |
| `active_visitors` | `number` | Number of currently active visitors |
---
URL: https://engagetrack.net/docs/api-reference/get-referrers.md
---
title: Referrers
description: Get referrer source breakdown with visitor and revenue data.
order: 37
method: GET
---
# Referrers
Returns a breakdown of traffic by normalized referrer domain, ranked by visitor count.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/referrers
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `limit` | `number` | No | Maximum number of results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of referrer entries:
| Field | Type | Description |
| ---------- | -------- | ------------------------------------- |
| `referrer` | `string` | Normalized referrer domain |
| `visitors` | `number` | Unique visitors from this referrer |
---
URL: https://engagetrack.net/docs/api-reference/get-revenue-chart.md
---
title: Revenue Chart
description: Get time-series revenue data for charting.
order: 39
method: GET
---
# Revenue Chart
Returns time-series revenue data suitable for charting, grouped by the specified interval.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/revenue-chart
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------------------------------------------------- |
| `period` | `string` | No | Time period (`day`, `7d`, `30d`, `month`, `12mo`, `custom`) |
| `group` | `string` | No | Grouping interval: `hour` or `day` (default: `day`) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of time-series data points:
| Field | Type | Description |
| ----------- | -------- | ------------------------------- |
| `timestamp` | `string` | ISO 8601 timestamp for the bucket |
| `revenue` | `number` | Total revenue in the period |
| `orders` | `number` | Number of orders in the period |
| `customers` | `number` | Distinct paying visitors in the period |
---
URL: https://engagetrack.net/docs/api-reference/get-revenue.md
---
title: Revenue Overview
description: Get revenue attribution analytics and overview.
order: 7
method: GET
---
# Revenue Overview
Returns revenue metrics including total revenue, order count, customer count, average order value, and breakdowns by source, campaign, country, and page.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/revenue-overview
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------- |
| `period` | `string` | No | Time period |
| `date` | `string` | No | Base date |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
| Field | Type | Description |
| ----------------- | -------- | ----------------------------------- |
| `total_revenue` | `number` | Total revenue in the period |
| `order_count` | `number` | Number of purchase events |
| `customers` | `number` | Distinct paying visitors |
| `avg_order_value` | `number` | Average revenue per order |
| `by_source` | `array` | Revenue breakdown by traffic source |
| `by_campaign` | `array` | Revenue breakdown by UTM campaign |
| `by_country` | `array` | Revenue breakdown by country |
| `by_page` | `array` | Revenue breakdown by landing page |
## Revenue Chart
For time-series revenue data, use:
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/revenue-chart
```
Returns an array of `{timestamp, revenue, orders, customers}` data points.
---
URL: https://engagetrack.net/docs/api-reference/team-members.md
---
title: Team Members
description: List and manage team members in an organization.
order: 50
method: GET
---
# Team Members
Returns all members of the specified organization.
## Endpoint
```
GET /api/v1/organizations/:orgId/team/members
```
---
URL: https://engagetrack.net/docs/api-reference/get-pages.md
---
title: Top Pages
description: Get top, entry, and exit pages for a site.
order: 4
method: GET
---
# Top Pages
Returns a breakdown of page paths by pageview count and unique visitors. Supports top pages, entry pages, and exit pages.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/pages
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------------------- |
| `period` | `string` | No | Time period |
| `type` | `string` | No | `pages` (default), `entry`, or `exit` |
| `limit` | `number` | No | Max results to return (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of page entries:
| Field | Type | Description |
| ----------- | -------- | ------------------------------------ |
| `page_path` | `string` | The page URL path (e.g., `/pricing`) |
| `views` | `number` | Total pageview count |
| `visitors` | `number` | Unique visitors for this page |
---
URL: https://engagetrack.net/docs/api-reference/get-sources.md
---
title: Top Sources
description: Get traffic sources breakdown for a site.
order: 5
method: GET
---
# Top Sources
Returns the top traffic sources (referrer domains) ranked by unique visitors.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/analytics/sources
```
## Query Parameters
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------- |
| `period` | `string` | No | Time period |
| `limit` | `number` | No | Max results (default: 10) |
| `filters` | `string` | No | JSON-encoded filter array |
## Response fields
Returns an array of source entries:
| Field | Type | Description |
| ---------- | -------- | -------------------------------- |
| `source` | `string` | Referrer source name |
| `visitors` | `number` | Unique visitors from this source |
## Related Endpoints
| Endpoint | Description |
| ------------------------- | ---------------------------------------------------- |
| `.../analytics/channels` | Traffic grouped by channel (UTM > referrer > Direct) |
| `.../analytics/referrers` | Traffic grouped by normalized referrer domain |
| `.../analytics/campaigns` | Traffic grouped by UTM campaign |
---
URL: https://engagetrack.net/docs/api-reference/get-visitor-timeline.md
---
title: Visitor Timeline
description: Get the chronological event timeline for a specific visitor.
order: 41
method: GET
---
# Visitor Timeline
Returns a chronological feed of events for a specific visitor, including pageviews, goal completions, and purchases.
## Endpoint
```
GET /api/v1/organizations/:orgId/sites/:siteId/visitors/:visitorId/timeline
```
## Path Parameters
| Parameter | Type | Required | Description |
| ----------- | -------- | -------- | -------------- |
| `visitorId` | `string` | Yes | The visitor ID |
## Response fields
Returns the visitor profile and a `timeline` array. The response includes pagination fields `total`, `page`, and `limit`.
Each timeline entry:
| Field | Type | Description |
| ------------------ | -------- | -------------------------------------------------- |
| `id` | `string` | Event ID |
| `session_id` | `string` | Session ID |
| `event_type` | `string` | Event type (`pageview`, `goal`, `purchase`, `form`) |
| `timestamp` | `string` | ISO 8601 event timestamp |
| `page_url` | `string` | Page URL (for pageviews) |
| `page_title` | `string` | Page title (for pageviews) |
| `event_name` | `string` | Event/goal name (for goal events) |
| `revenue` | `number` | Revenue amount (for purchase events) |
| `currency` | `string` | Revenue currency code |
| `referrer_source` | `string` | Referrer source for this event |
| `properties` | `object` | Custom event properties |
---
URL: https://engagetrack.net/docs/api-reference/delete-goal.md
---
title: Archive Goal
description: Archive or restore a goal for a site.
order: 22
method: POST
---
# Archive Goal
Archives a goal so it no longer appears in stats. Historical conversion data is retained and the goal can be restored at any time. Requires member role or higher.
## Endpoint
```
POST /api/v1/organizations/:orgId/sites/:siteId/goals/:goalId/archive
```
# Restore Goal
Restores a previously archived goal so it appears in stats again.
## Endpoint
```
POST /api/v1/organizations/:orgId/sites/:siteId/goals/:goalId/unarchive
```
---
URL: https://engagetrack.net/docs/api-reference/create-annotation.md
---
title: Create Annotation
description: Add an annotation to a site's analytics timeline.
order: 43
method: POST
---
# Create Annotation
Creates a new annotation on the site's analytics timeline. Useful for marking deployments, campaigns, or other notable events.
## Endpoint
```
POST /api/v1/organizations/:orgId/sites/:siteId/annotations
```
## Request Body
| Field | Type | Required | Description |
| ------------- | -------- | -------- | ----------------------------- |
| `label` | `string` | Yes | Annotation label |
| `occurred_at` | `string` | Yes | Annotation date (ISO 8601) |
| `description` | `string` | No | Optional longer description |
| `color` | `string` | No | Optional color for the marker |
---
URL: https://engagetrack.net/docs/api-reference/create-funnel.md
---
title: Create Funnel
description: Create a new conversion funnel.
order: 31
method: POST
---
# Create Funnel
Creates a new multi-step conversion funnel for a site. Requires member role or higher.
## Endpoint
```
POST /api/v1/organizations/:orgId/sites/:siteId/funnels
```
## Request Body
| Field | Type | Required | Description |
| ------------- | -------- | -------- | ----------------------------- |
| `name` | `string` | Yes | Funnel name |
| `description` | `string` | No | Funnel description |
| `steps` | `array` | Yes | Array of funnel steps (min 2) |
Each step requires:
| Field | Type | Required | Description |
| ------------ | -------- | -------- | -------------------------------------- |
| `name` | `string` | Yes | Step label |
| `order` | `number` | Yes | Step position (1-indexed) |
| `type` | `string` | No | `pageview` (default) or `custom_event` |
| `pattern` | `string` | Yes | Page path or event name to match |
| `match_type` | `string` | No | `exact`, `contains` (default), `regex` |
## Analyze Funnel
Once created, analyze funnel performance:
```
GET /api/v1/organizations/:orgId/sites/:siteId/funnels/:funnelId/analyze
```
Returns per-step stats with:
| Field | Type | Description |
| ----------------- | -------- | -------------------------------------- |
| `step_id` | `string` | Step ID |
| `name` | `string` | Step name |
| `order` | `number` | Step position |
| `visitors` | `number` | Visitors who reached this step |
| `dropoff_rate` | `number` | % lost from previous step |
| `conversion_rate` | `number` | % retained from previous step |
| `revenue` | `number` | Revenue attributed to visitors at step |
| `top_sources` | `array` | Top 3 traffic sources at step |
| `top_countries` | `array` | Top 3 countries at step |
---
URL: https://engagetrack.net/docs/api-reference/create-invite.md
---
title: Create Invite
description: Invite a new team member to an organization.
order: 51
method: POST
---
# Create Invite
Sends an invitation email to add a new member to the organization. Requires admin role.
## Endpoint
```
POST /api/v1/organizations/:orgId/team/invites
```
## Request Body
| Field | Type | Required | Description |
| ------- | -------- | -------- | ------------------------------------------- |
| `email` | `string` | Yes | Email address to invite |
| `role` | `string` | Yes | Role to assign: `admin`, `member`, `viewer` |
---
URL: https://engagetrack.net/docs/api-reference/create-site.md
---
title: Create Site
description: Add a new site to an organization.
order: 11
method: POST
---
# Create Site
Creates a new site in the specified organization. Requires admin role.
## Endpoint
```
POST /api/v1/organizations/:orgId/sites
```
## Request Body
| Field | Type | Required | Description |
| ---------- | -------- | -------- | -------------------------------- |
| `domain` | `string` | Yes | Site domain (e.g. `example.com`) |
| `name` | `string` | No | Display name |
| `timezone` | `string` | No | IANA timezone (default: UTC) |
The response includes a `public_id` — this is the site key used in the tracking script.
This endpoint requires JWT authentication and is not accessible via API key.
---
URL: https://engagetrack.net/docs/api-reference/ingest-event.md
---
title: Ingest Event
description: Send a pageview or custom event from the tracking script.
order: 60
method: POST
---
# Ingest Event
The primary data ingestion endpoint used by the EngageTrack tracking script. Receives pageview and custom event payloads.
This endpoint is called automatically by the tracking script. You typically
don't need to call it directly unless building a custom integration.
## Endpoint
```
POST /api/v1/event
```
No Bearer token required — the site is identified by the `site_id` field (the site's public ID).
## Request Body
| Field | Type | Required | Description |
| -------------- | -------- | -------- | ------------------------------------------ |
| `site_id` | `string` | Yes | Site public ID (`pk_live_*`) |
| `event_type` | `string` | No | `pageview`, `click`, `form_submit`, `download`, `outbound`, `purchase`, `custom` |
| `url` | `string` | Yes | Full page URL |
| `event_name` | `string` | No | Custom event name (for custom events) |
| `referrer` | `string` | No | Referrer URL |
| `title` | `string` | No | Page title |
| `visitor_uid` | `string` | No | Persistent visitor ID from localStorage |
| `session_id` | `string` | No | Client-side session ID |
| `screen_w` | `number` | No | Screen width |
| `screen_h` | `number` | No | Screen height |
| `time_on_page` | `number` | No | Seconds spent on previous page |
| `scroll_depth` | `number` | No | Max scroll percentage (0-100) |
| `revenue` | `number` | No | Revenue amount (for purchase events) |
| `currency` | `string` | No | Currency code, e.g. `USD` |
| `order_id` | `string` | No | Order ID (for purchase events) |
| `properties` | `object` | No | Custom key-value properties |
## Response
Returns `202 Accepted` with body `ok` on success.
## Identify Endpoint
To link an anonymous visitor to a known user identity:
```
POST /api/v1/identify
```
| Field | Type | Required | Description |
| ------------- | -------- | -------- | -------------------------------- |
| `site_id` | `string` | Yes | Site public ID |
| `visitor_uid` | `string` | Yes | Visitor UID from tracker |
| `user_id` | `string` | Yes | Your application's user ID |
| `name` | `string` | No | User display name |
| `email` | `string` | No | User email |
| `avatar` | `string` | No | Avatar URL |
| `custom` | `object` | No | Custom attributes |
---
URL: https://engagetrack.net/docs/api-reference/update-goal.md
---
title: Update Goal
description: Update an existing goal.
order: 21
method: PUT
---
# Update Goal
Updates the configuration of an existing goal. Requires member role or higher.
## Endpoint
```
PUT /api/v1/organizations/:orgId/sites/:siteId/goals/:goalId
```
## Request Body
| Field | Type | Required | Description |
| --------------------- | -------- | -------- | ---------------------------------- |
| `name` | `string` | No | Goal display name |
| `pattern` | `string` | No | Page path or event name to match |
| `match_type` | `string` | No | `exact`, `contains`, or `regex` |
| `value` | `number` | No | Monetary value per conversion |
| `currency` | `string` | No | Currency code (e.g. `USD`) |
| `property_conditions` | `array` | No | Property filters for custom events |
The `type` field is immutable — goals are auto-created as `custom_event` or
`pageview` and cannot change type after creation.
---
URL: https://engagetrack.net/docs/api-reference/delete-annotation.md
---
title: Delete Annotation
description: Remove an annotation from a site.
order: 44
method: DELETE
---
# Delete Annotation
Permanently deletes an annotation from the site's analytics timeline.
## Endpoint
```
DELETE /api/v1/organizations/:orgId/sites/:siteId/annotations/:annotationId
```
This action cannot be undone. The annotation will be permanently removed.
---
URL: https://engagetrack.net/docs/api-reference/delete-funnel.md
---
title: Delete Funnel
description: Delete a funnel from a site.
order: 32
method: DELETE
---
# Delete Funnel
Permanently deletes a funnel and its step definitions. Requires member role or higher.
## Endpoint
```
DELETE /api/v1/organizations/:orgId/sites/:siteId/funnels/:funnelId
```
---
URL: https://engagetrack.net/docs/api-reference/delete-site.md
---
title: Delete Site
description: Remove a site and all its data.
order: 12
method: DELETE
---
# Delete Site
Permanently deletes a site and all associated analytics data. This action cannot be undone. Requires admin role.
## Endpoint
```
DELETE /api/v1/organizations/:orgId/sites/:siteId
```
## Request Body
| Field | Type | Required | Description |
| ---------------- | -------- | -------- | ---------------------------------------------- |
| `confirm_domain` | `string` | Yes | Must match the site's domain for confirmation |
This permanently deletes all pageviews, events, goals, funnels, and visitor
data for the site. Make sure to export any data you need before deleting.
This endpoint requires JWT authentication and is not accessible via API key.
---
URL: https://engagetrack.net/docs/troubleshooting/common-issues.md
---
title: Troubleshooting
description: Solutions to common EngageTrack issues and how to debug tracking problems.
order: 1
---
# Troubleshooting
This guide covers the most common issues and how to diagnose them.
## Enable Debug Mode
The first step for any tracking issue is to enable debug mode. Add `data-debug="true"` to your script tag:
```html
```
Open your browser's developer console (F12 or Cmd+Option+I). You will see detailed logs prefixed with `[EngageTrack]` for every action the SDK takes.
---
## Script Not Loading
**Symptoms:** No `[EngageTrack]` messages in the console. The script file returns a network error.
### Check Content Security Policy (CSP)
If your site uses a Content Security Policy, make sure it allows the EngageTrack domains:
```
Content-Security-Policy:
script-src 'self' https://cdn.engagetrack.net;
connect-src 'self' https://api.engagetrack.net;
```
Check the console for CSP violation errors (they appear as red error messages mentioning "Content Security Policy").
### Check for Ad Blockers
Ad blockers may block `cdn.engagetrack.net` or `api.engagetrack.net`. To verify:
1. Disable your ad blocker temporarily
2. Reload the page
3. If tracking works, set up a [proxy](/docs/proxy/overview) to serve the script from your own domain
### Verify the Script Tag
Make sure the script tag is correct:
- The `src` URL is `https://cdn.engagetrack.net/sdk.js`
- The `data-site-id` attribute is present and not empty
- The `defer` attribute is included (the script needs the DOM to be ready)
- The script is in the `` section
---
## No Data in Dashboard
**Symptoms:** The script loads and debug logs appear, but no data shows in the dashboard.
### Wrong Site ID
The `data-site-id` in your script tag must match the site ID in your EngageTrack dashboard. Copy it from **Site Settings -> General**.
### Domain Mismatch
If you have an allowed hostnames list configured in **Site Settings -> Tracking**, the domain your site is served from must be in that list. Check that:
- `localhost` is included if you are testing locally
- The exact hostname matches (e.g., `www.example.com` and `example.com` are different)
### Events Blocked Server-Side
Check the Network tab in your browser's developer tools:
1. Filter by `event` to find the POST request to the event endpoint
2. If the response is `403`, your IP may be excluded or the site ID is invalid
3. If the response is `429`, you have hit a rate limit
New events typically appear in the dashboard within 5-10 seconds. If you
are looking at the **Real-time** view, make sure you have selected the
correct site from the dropdown.
---
## Revenue Not Appearing
**Symptoms:** Purchases happen but no revenue data shows in the Revenue dashboard.
### Verify Webhook URL
Each payment provider requires a webhook to send purchase events to EngageTrack:
1. Go to **Site Settings -> Revenue**
2. Check that your provider is connected and the webhook URL is configured
3. For Stripe, the connection is automatic via OAuth. For other providers, verify the webhook URL is set in the provider's dashboard.
### Check Metadata (Stripe)
For Stripe integrations, the `engagetrack_visitor_id` must be included in the checkout session metadata for direct attribution:
```javascript
const session = await stripe.checkout.sessions.create({
metadata: {
engagetrack_visitor_id: visitorId,
},
// ...
});
```
Without this metadata, EngageTrack falls back to email-based or session-based attribution, which may not match all purchases.
### Provider Webhook Logs
Check your payment provider's webhook delivery logs for failed deliveries:
- **Stripe:** Dashboard -> Developers -> Webhooks -> Select endpoint -> Recent deliveries
- **Lemon Squeezy:** Settings -> Webhooks -> Click the webhook -> Delivery attempts
- **Paddle:** Developer Tools -> Notifications -> Event log
- **Polar:** Settings -> Webhooks -> Delivery history
Revenue data may take up to 60 seconds to appear after a webhook is
received, as the backend processes attribution asynchronously.
---
## Cross-Domain Tracking Not Working
**Symptoms:** Visitors get a new visitor ID when navigating between domains.
### Check Allowed Hostnames
Verify that `data-allowed-hostnames` includes the destination domain on the **source** site:
```html
```
### Check URL Parameters
When you click a link to the destination domain, the URL should include `_et_vid` and `_et_sid` parameters. If they are missing:
1. Enable debug mode on the source domain
2. Click the cross-domain link
3. Look for `[EngageTrack] Cross-domain link decorated:` in the console
4. If this log does not appear, the destination hostname is not in the allowed list
### Same Site ID
Both domains must use the same `data-site-id` for the sessions to be stitched together.
> See the full [Cross-Domain Tracking guide](/docs/advanced/cross-domain) for setup details.
---
## Real-Time Dashboard Not Updating
**Symptoms:** The real-time view shows stale data or "0 current visitors" despite active traffic.
### WebSocket Connection
The real-time dashboard uses WebSocket connections. Check for issues:
1. Open the Network tab and filter by "WS" (WebSocket)
2. You should see an active WebSocket connection to the API
3. If the connection fails, check that your network/firewall allows WebSocket connections
### Browser Tab Focus
Some browsers throttle background tabs, which can delay WebSocket messages. Make sure the dashboard tab is in the foreground.
### Proxy Configuration
If you are using a reverse proxy (Nginx, Cloudflare), ensure it supports WebSocket upgrades:
```nginx
# Nginx WebSocket support
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
```
---
## Self-Visits Inflating Data
**Symptoms:** Your own visits are being counted, inflating pageview and visitor numbers.
Exclude yourself using one of these methods:
```javascript
// Run this in the browser console on your tracked site
window.engagetrack.ignore();
// Then reload the page
```
Or exclude your IP address in **Site Settings -> Tracking -> Excluded IPs**.
> See [Exclude Visits](/docs/advanced/exclude-visits) for all exclusion options.
---
## Debugging Checklist
If you are still stuck, work through this checklist:
1. **Script loads?** Check the Network tab for the SDK request. Status should be 200.
2. **SDK initializes?** With `data-debug="true"`, look for `[EngageTrack] Initialized with site:` in the console.
3. **Events sent?** In the Network tab, filter by the event endpoint URL. Check that POST requests are being made.
4. **Events accepted?** The event endpoint should return a `200` or `202` status. Any other status indicates a problem.
5. **Correct site?** Compare the `site_id` in the request payload with the site ID in your dashboard.
6. **Not excluded?** Check that `localStorage.engagetrack_ignore` is not set to `"true"`.
7. **Dashboard filters?** Make sure no filters are active in the dashboard that would hide your data.
If none of the above resolves your issue, reach out to support with the
following details: your site ID, the debug console output, and a
screenshot of the Network tab showing the event request and response.