# TrackAny.Click — Documentation

Last reviewed: 9 September 2026

[HTML](https://docs.trackany.click/)

Clear attribution from first touch to qualified lead.

## Getting started

1. Create and verify one Cloud account. 2. Select or create the organization that owns the integration. 3. Create a project for the website, shop or brand whose data must stay together. 4. Open the product workspace and confirm that it is enabled before copying credentials or sending production traffic.

That is the complete account setup. The remaining sections are implementation guides. Credentials are always project-scoped; server secrets must never be placed in browser code, public repositories or client-side environment variables.

## Before you integrate

TrackAny.Click collection is activated per customer project. Start production traffic only when the project workspace displays a public key, the installation snippet and an active collector URL. Prepared URLs or a script copied from another project do not activate collection.

## Public and secret project keys

The public pub_tac_ key belongs in the browser and is restricted to the active domains of its project. The sec_tac_ key is shown once when the project is created and belongs only in a server-side secret manager. It authenticates server events and identify calls.

If the secret key was not stored, do not substitute the public key or expose a server key in the browser. Request a controlled replacement before integrating server events; self-service secret-key rotation is not currently available.

## Install the browser tracker

Copy the project-specific snippet from TrackAny.Click → Installation. The example loads the tracker from connect.trackany.click, sends to the same collector and starts with consent denied. Use the exact script URL, endpoint and public key shown for your project, including a verified custom tracking domain when available.

The tracker also captures future Meta Pixel and Google dataLayer/gtag events on the page after analytics consent by default; the existing tags continue to run. Set data-provider-events=false to turn off this bridge, or data-google-layer for a custom data layer name. data-spa=true adds initial and History API page views. Events fired before the tracker loads cannot be recovered. data-track-outbound=true adds clicks on external HTTP(S) links.

```html
<script>
  window.trackany = window.trackany || function () {
    (window.trackany.q = window.trackany.q || []).push(arguments);
  };
</script>
<script async
  src="https://connect.trackany.click/v1/t.js"
  data-project="PUBLIC_PROJECT_KEY"
  data-endpoint="https://connect.trackany.click"
  data-consent="denied"
  data-spa="true"
  data-web-vitals="true"
  data-provider-events="true"
  data-track-outbound="true">
</script>
```

## Connect consent correctly

Before consent the tracker creates no identifiers, touches no persistent storage and sends no events. Call consent=granted only after the site's consent manager authorizes analytics. Call consent=denied on withdrawal; this clears TrackAny.Click's local state and stops new events, but it is not a server-side deletion request.

Avoid personal information in URLs, UTM values and custom properties. Page queries and fragments are removed, referrers are reduced, and the SDK does not fingerprint users.

## Track page views, leads and conversions

Use lowercase snake_case event names. Mark real goals with conversion=true and pass value and a three-letter currency together when the event has a monetary value. Browser calls automatically carry the consent-bound visitor, session and attribution context.

Use one event for one business fact. Do not report the same purchase from browser and server unless both events intentionally represent different facts.

```javascript
window.trackany("consent", "granted");
window.trackany("pageview");
window.trackany(
  "event",
  "form_submit",
  { form: "demo_request" },
  { conversion: true }
);
```

## Browser event examples

The tracker emits page_view for automatic SPA views when data-spa=true. A manual pageview call emits the same event. With data-track-outbound=true, clicks on external HTTP(S) links emit outbound_click with destination_origin only. It creates sessions automatically but does not emit session_start by itself. The consent command changes local tracking permission; it is not an event.

The other names below are suggested conventions, not a fixed event whitelist: view_product, add_to_cart, begin_checkout, form_started and form_submit. Each window.trackany call sends one event after analytics consent. Use properties for non-sensitive IDs or counts; conversion is an event option.

```javascript
window.trackany("pageview");

window.trackany("event", "view_product", { product_id: "sku_123" });
window.trackany("event", "add_to_cart", { product_id: "sku_123", quantity: 1 });
window.trackany("event", "begin_checkout", { cart_id: "cart_123" });
window.trackany("event", "form_started", { form_id: "demo" });
window.trackany("event", "form_submit", { form_id: "demo" }, { conversion: true });
window.trackany("event", "session_start");
```

## Server event examples

Send confirmed business facts from your backend with a secret key: lead_created, lead_qualified, appointment_created, appointment_completed, order_created, purchase, refund, subscription_started, subscription_cancelled, deal_won and deal_lost. These are suggested names; the API also accepts your own lowercase snake_case names up to 100 characters.

The Node.js example uses the ulid package to create a valid eventId. Install that package in your server project. Keep the exact eventId and JSON body for retries. Monetary value must be non-negative and accompanied by a three-letter currency; send a refund as its own event rather than a negative purchase. Only mark genuine goals as conversions.

```javascript
import { ulid } from "ulid";

const endpoint = "https://connect.trackany.click/v1/events";
const secretKey = process.env.TRACKANY_SECRET_KEY;

async function sendEvent(event, properties = {}, fields = {}) {
  const body = {
    eventId: `evt_${ulid()}`,
    event,
    timestamp: new Date().toISOString(),
    properties,
    ...fields,
  };
  const response = await fetch(endpoint, {
    method: "POST",
    headers: {
      authorization: `Bearer ${secretKey}`,
      "content-type": "application/json",
    },
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(`TrackAny event rejected: ${response.status}`);
  return response.json();
}

await sendEvent("lead_created", { lead_id: "lead_123" }, { contactId: "crm_123" });
await sendEvent("lead_qualified", { lead_id: "lead_123" }, { contactId: "crm_123" });
await sendEvent("appointment_created", { appointment_id: "appt_123" });
await sendEvent("appointment_completed", { appointment_id: "appt_123" });
await sendEvent("order_created", { order_id: "ord_123" });
await sendEvent("purchase", { order_id: "ord_123" },
  { value: 49.90, currency: "USD", conversion: true });
await sendEvent("refund", { order_id: "ord_123" },
  { value: 49.90, currency: "USD" });
await sendEvent("subscription_started", { subscription_id: "sub_123" });
await sendEvent("subscription_cancelled", { subscription_id: "sub_123" });
await sendEvent("deal_won", { deal_id: "deal_123" }, { conversion: true });
await sendEvent("deal_lost", { deal_id: "deal_123" });
```

## Send a trusted server event

POST JSON to /v1/events with the secret key as a Bearer token. Server events can include contactId or externalId and are reported separately from browser-trust events. Keep eventId stable when retrying the same event: identical content is deduplicated, while changed content under the same ID returns HTTP 409 event_id_conflict.

### cURL

```bash
curl --request POST "https://connect.trackany.click/v1/events" \
  --header "Authorization: Bearer $TRACKANY_SECRET_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "eventId": "evt_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
  "event": "purchase",
  "timestamp": "2026-09-08T17:00:00Z",
  "contactId": "crm_123",
  "value": 49.9,
  "currency": "USD",
  "conversion": true,
  "properties": {
    "plan": "pro"
  }
}'
```

### Node.js

```javascript
const response = await fetch("https://connect.trackany.click/v1/events", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRACKANY_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "eventId": "evt_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
    "event": "purchase",
    "timestamp": "2026-09-08T17:00:00Z",
    "contactId": "crm_123",
    "value": 49.9,
    "currency": "USD",
    "conversion": true,
    "properties": {
      "plan": "pro"
    }
  }),
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
```

### Python

```python
import os
import requests

payload = {
    "eventId": "evt_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
    "event": "purchase",
    "timestamp": "2026-09-08T17:00:00Z",
    "contactId": "crm_123",
    "value": 49.9,
    "currency": "USD",
    "conversion": True,
    "properties": {
        "plan": "pro",
    },
}

response = requests.post(
    "https://connect.trackany.click/v1/events",
    headers={
        "Authorization": f"Bearer {os.environ['TRACKANY_SECRET_KEY']}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

### PHP

```php
<?php

$payload = [
    'eventId' => 'evt_01JZ8J2K9M7P4Q6R8S1T3V5W7X',
    'event' => 'purchase',
    'timestamp' => '2026-09-08T17:00:00Z',
    'contactId' => 'crm_123',
    'value' => 49.9,
    'currency' => 'USD',
    'conversion' => true,
    'properties' => [
        'plan' => 'pro',
    ],
];
$curl = curl_init('https://connect.trackany.click/v1/events');

curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TRACKANY_SECRET_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
    CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($curl);
if ($response === false) {
    throw new RuntimeException(curl_error($curl));
}
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($status >= 400) {
    throw new RuntimeException("Request failed: $status");
}
echo $response;
```

## Connect a visitor to your system

After a form submission or sign-in, read the consented visitorId from window.trackany.getContext() and send it from your backend to POST /v1/identify with contactId, externalId or both. This endpoint requires the secret key; public browser keys are rejected.

### cURL

```bash
curl --request POST "https://connect.trackany.click/v1/identify" \
  --header "Authorization: Bearer $TRACKANY_SECRET_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "visitorId": "vis_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
  "contactId": "crm_123"
}'
```

### Node.js

```javascript
const response = await fetch("https://connect.trackany.click/v1/identify", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRACKANY_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "visitorId": "vis_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
    "contactId": "crm_123"
  }),
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
console.log(await response.json());
```

### Python

```python
import os
import requests

payload = {
    "visitorId": "vis_01JZ8J2K9M7P4Q6R8S1T3V5W7X",
    "contactId": "crm_123",
}

response = requests.post(
    "https://connect.trackany.click/v1/identify",
    headers={
        "Authorization": f"Bearer {os.environ['TRACKANY_SECRET_KEY']}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

### PHP

```php
<?php

$payload = [
    'visitorId' => 'vis_01JZ8J2K9M7P4Q6R8S1T3V5W7X',
    'contactId' => 'crm_123',
];
$curl = curl_init('https://connect.trackany.click/v1/identify');

curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('TRACKANY_SECRET_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
    CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($curl);
if ($response === false) {
    throw new RuntimeException(curl_error($curl));
}
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($status >= 400) {
    throw new RuntimeException("Request failed: $status");
}
echo $response;
```

## Choose an event model

Define a small vocabulary before implementation, for example page_view → form_submitted → qualified_lead → purchase. Keep acquisition activity and later customer outcomes as distinct events so reports can show the observed order and trust source.

## Preserve campaign attribution

Use consistent utm_source, utm_medium, utm_campaign and stable provider identifiers such as utm_id, utm_adgroup_id and utm_ad_id. TrackAny.Click retains first touch, current session touch and last non-direct touch separately; campaign names alone are not reliable join keys.

## Batching and outcomes

POST 1–100 events to /v1/events/batch when a server process has several independent facts. The service validates the complete batch first and can return HTTP 207 with per-event results if only some writes succeed. Keep each event ID and payload for safe retry.

## Read journeys and handle failures

HTTP 202 means the event was accepted. Handle 400 as a contract or timestamp error, 401 as an invalid project key, 402 as quota or credits required, 403 as an origin restriction, 409 as event-ID reuse with changed content and 429 as rate limiting. Retry transient failures with the unchanged event ID and payload.

Journey and funnel reports are bounded views, not an identity graph: they expose coverage and truncation, keep currencies and trust sources separate, and do not claim cross-device certainty.

## Products

- [TrackMailer](https://docs.markengroup.cloud/trackmailer.md): Reach customers reliably and keep every delivery clearly visible.
- [TrackAny.Click](https://docs.trackany.click/.md): Invest in the campaigns and customer journeys that create value.
- [TrackPost](https://docs.markengroup.cloud/trackpost.md): Create relevant content quickly and keep every decision clear.
- [LeadScoutEngine](https://docs.markengroup.cloud/leadscoutengine.md): Find and prioritize companies from your criteria, then unlock only the intelligence your team needs.
