> For the complete documentation index, see [llms.txt](https://docs.getpurpledot.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.getpurpledot.com/docs/shopify-stores/pre-order-tracking/custom-server-side-tracking-integration.md).

# Custom server side tracking integration

{% hint style="info" %}
This guide applies only when selling pre-orders through Purple Dot's own checkout.
{% endhint %}

Purple Dot sends server-side checkout and pre-order events to an HTTPS endpoint you control. Connect it in the Purple Dot merchant portal under **Settings → Connections → Analytics** as **Webhook**.

Once connected, Purple Dot automatically sends events as shoppers move through your checkout and when they complete a pre-order. This works with:

* **Google Tag Manager server-side** (GTM SS) - forward events into your server container and on to Meta, Google Ads, TikTok, etc.
* **A custom webhook** - any HTTPS endpoint that accepts JSON `POST` requests.

### **What you need before you start**

* An **HTTPS endpoint** ready to receive events.
  * For **GTM server-side**: your server container URL
  * For a **custom webhook**: a URL on your backend or event router.
* **Optional:** a **Bearer token** if your endpoint requires authentication.

> Your webhook URL **must** use `https://`. HTTP URLs cannot be saved.

### **Step 1 - Set up your receiving endpoint**

Your endpoint must accept `POST` requests with a JSON body and return a **2xx** response to confirm receipt.

#### **Option A - Google Tag Manager server-side (recommended)**

If you use GTM server-side to route events to ad platforms:

1. Open your **server-side GTM container**.
2. Create or identify the **Client** that receives HTTP requests (commonly a **Custom Client** or your host’s default ingest client).
3. Copy the **HTTPS URL** for that client - this is the URL Purple Dot will POST to.
4. In your server container, configure **Tags** and **Triggers** to map incoming Purple Dot events to your ad platform tags (Meta CAPI, Google Ads, TikTok, etc.).

Map Purple Dot `event_name` values to the events your tags expect:

| **Purple Dot `event_name`** | **Typical GTM / ad platform event**    |
| --------------------------- | -------------------------------------- |
| `AddToCart`                 | `add_to_cart`                          |
| `InitiateCheckout`          | `begin_checkout` / `initiate_checkout` |
| `AddPaymentInfo`            | `add_payment_info`                     |
| `Purchase`                  | `purchase`                             |

> Work with your analytics agency or GTM administrator if you are unsure which client URL or tag mapping to use.

#### **Option B - Custom webhook**

If you are building your own integration:

1. Deploy an HTTPS route that accepts `POST` with `Content-Type: application/json`.
2. Parse the JSON body using the **event schema** below.
3. Return **2xx** on success.

If your endpoint uses authentication, configure it to accept:

Authorization: Bearer \<your-token>

Purple Dot only sends this header when a Bearer Token is configured in the connection.

### **Step 2 - Add credentials in Purple Dot**

1. Log in to the **Purple Dot merchant portal**.
2. Go to **Settings → Connections**.
3. Under **Analytics**, click **Connect** for **Webhook**.
4. Enter:

| **Field**        | **Value**                                                                      |
| ---------------- | ------------------------------------------------------------------------------ |
| **Webhook URL**  | Your HTTPS endpoint (GTM server container client URL or custom webhook URL).   |
| **Bearer Token** | *(Optional)* Secret token your endpoint expects in the `Authorization` header. |

1. Click **Save**.

> **What this is:** The Webhook URL is where Purple Dot sends all analytics events. The Bearer Token is stored securely and only sent when you provide one.

<figure><img src="/files/ChrnbeJmaY5zVAmCipB9" alt=""><figcaption></figcaption></figure>

***

### **Step 3 - Verify the connection and test events**

#### **Option A - Test from the merchant portal (quick check)**

1. In **Settings → Connections**, open your Webhook connection.
2. Click **Test**.
3. Purple Dot sends a `PurpleDotTestEvent` to your endpoint.
4. If your endpoint returns **2xx**, the connection is marked healthy.

**Test event payload:**

```json
{
  "event_name": "PurpleDotTestEvent",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_time": "2024-01-15T12:00:00.000Z"
}
```

#### **Option B - Run a real checkout (deep check)**

1. Complete a test pre-order through your Purple Dot embedded checkout.
2. Confirm your endpoint (or GTM server container preview / request logs) receives:
   * `InitiateCheckout` when checkout starts
   * `AddPaymentInfo` when payment details are submitted
   * `Purchase` when the pre-order is completed

For GTM server-side, use **Preview mode** in your server container to confirm events arrive and your tags fire.

### **What happens in production**

Once the connection is saved, Purple Dot sends events automatically when checkout milestones are triggered:

| **Shopper action**      | **`event_name`**   | **When it fires**               |
| ----------------------- | ------------------ | ------------------------------- |
| **Add to cart**         | `AddToCart`        | Item added in embedded checkout |
| **Initiate checkout**   | `InitiateCheckout` | Checkout session starts         |
| **Add payment info**    | `AddPaymentInfo`   | Payment details submitted       |
| **Pre-order completed** | `Purchase`         | Pre-order successfully created  |

Events are sent server-side shortly after each action. Exact timing depends on background processing, not a fixed delay.

### **Event payload schema**

Every production event is a `POST` with `Content-Type: application/json`.

#### **Request format**

| **Property** | **Value**                                                              |
| ------------ | ---------------------------------------------------------------------- |
| Method       | `POST`                                                                 |
| URL          | Your configured Webhook URL                                            |
| Headers      | `Content-Type: application/json`                                       |
| Auth         | `Authorization: Bearer <token>` *(only if Bearer Token is configured)* |

#### **Event fields**

| **Field**                   | **Type** | **Required** | **Description**                                                                                                                |
| --------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `event_name`                | string   | Yes          | `Purchase`, `AddToCart`, `InitiateCheckout`, or `AddPaymentInfo`                                                               |
| `transaction_id`            | string   | Yes          | Unique ID for the event. On `Purchase`, this is your pre-order reference when available; on funnel events, a session event ID. |
| `event_time`                | string   | Yes          | ISO 8601 timestamp, e.g. `2024-01-15T12:00:00.000Z`                                                                            |
| `user_data`                 | object   | No           | Hashed customer identifiers — see **PII handling**                                                                             |
| `user_data.email`           | string   | No           | SHA-256 hash of customer email                                                                                                 |
| `user_data.phone`           | string   | No           | SHA-256 hash of customer phone                                                                                                 |
| `order`                     | object   | Yes          | Order / cart summary                                                                                                           |
| `order.reference`           | string   | No           | Pre-order reference (usually on `Purchase` only)                                                                               |
| `order.currency`            | string   | Yes          | Currency code, lowercased (e.g. `usd`)                                                                                         |
| `order.value`               | number   | Yes          | Total order value                                                                                                              |
| `order.contents`            | array    | No           | Line items (omitted if empty)                                                                                                  |
| `order.contents[].id`       | string   | Yes          | Product / variant ID (typically your Shopify variant ID)                                                                       |
| `order.contents[].quantity` | number   | Yes          | Quantity                                                                                                                       |
| `order.contents[].amount`   | number   | Yes          | Unit price                                                                                                                     |
| `click_ids`                 | object   | No           | Ad platform click IDs captured during checkout                                                                                 |
| `click_ids.fbc`             | string   | No           | Meta (`_fbc`)                                                                                                                  |
| `click_ids.ttclid`          | string   | No           | TikTok click ID                                                                                                                |
| `click_ids.gclid`           | string   | No           | Google Ads click ID                                                                                                            |
| `click_ids.gbraid`          | string   | No           | Google Ads iOS attribution                                                                                                     |
| `click_ids.wbraid`          | string   | No           | Google Ads web-to-app attribution                                                                                              |

`user_data`, `click_ids`, and `order.contents` are **omitted** when there is nothing to send.

#### **Example `Purchase` event**

```json
{
  "event_name": "Purchase",
  "transaction_id": "998231",
  "event_time": "2024-01-15T12:00:00.000Z",
  "user_data": {
    "email": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
    "phone": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"
  },
  "order": {
    "reference": "998231",
    "currency": "usd",
    "value": 99.5,
    "contents": [
      {
        "id": "45678901234",
        "quantity": 2,
        "amount": 49.75
      }
    ]
  },
  "click_ids": {
    "fbc": "fb.1.1234567890.AbCdEf",
    "gclid": "CjwKCAjw..."
  }
}
```

#### **Example funnel event (`InitiateCheckout`)**

```json
{
  "event_name": "InitiateCheckout",
  "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_time": "2024-01-15T12:00:00.000Z",
  "order": {
    "currency": "usd",
    "value": 99.5,
    "contents": [
      {
        "id": "45678901234",
        "quantity": 2,
        "amount": 49.75
      }
    ]
  }
}
```

### **PII and customer data**

Purple Dot does **not** send raw email addresses or phone numbers.

When available, customer contact details appear in `user_data` as **SHA-256 hashes** (lowercase hex strings):

| **Field** | **How it is prepared before hashing**                                                    |
| --------- | ---------------------------------------------------------------------------------------- |
| **Email** | Trimmed and lowercased                                                                   |
| **Phone** | Converted to international **E.164** format (using the shopper’s country when available) |

This matches what major ad platforms expect for server-side matching (Meta CAPI, TikTok Events API, Google Ads enhanced conversions, etc.), so you can forward hashed identifiers without Purple Dot transmitting plaintext PII.
