> For the complete documentation index, see [llms.txt](https://docs.chord.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chord.co/activate/event-streaming/destinations/email-and-marketing/dotdigital/dotdigital-tag.md).

# Dotdigital Tag

Dotdigital is a marketing automation platform for email, SMS and cross-channel programs. This destination loads Dotdigital in the browser and feeds it your Chord events, so it can track web behaviour, recover abandoned browses and abandoned carts, and report orders. See [Dotdigital](/activate/event-streaming/destinations/email-and-marketing/dotdigital.md) for how it fits with the [Dotdigital server](/activate/event-streaming/destinations/email-and-marketing/dotdigital/dotdigital-server.md) version.

This is the version that makes abandonment work. Dotdigital's abandoned cart program starts its timer from the last cart update it saw in the browser, and abandoned browse depends on the visitor session the Tag establishes. Neither can be driven from a server.

## Getting started

You need one value, and one thing removed.

**Your Tag URL.** In Dotdigital go to **Connect > Connect website**, select **View code**, and copy the `src` value out of the script tag. It looks like `https://r1.ddlnk.net/DM-0000000000-01/ddgtag`, or `https://emails.yourbrand.com/DM-0000000000-01/ddgtag.js` if your account uses a branded domain. Dotdigital generates this per account, so use the one your account shows. The host varies, and it is the host your storefront's Content Security Policy has to allow.

**Remove any Dotdigital Tag you installed yourself**, including one added through a commerce-platform app. Two tags on one page create two sessions, double every page view, and split one shopper's behaviour across both. This destination replaces that installation.

## Settings

* **Destination Name** (required): a name to tell this destination apart.
* **Tag URL** (required): your Dotdigital Tag URL, pasted whole.
* **Abandoned Cart Delay (minutes)** (optional): how many minutes after the last cart update Dotdigital waits before enrolling the contact into your abandoned cart program. Leave empty to use your Dotdigital account default.
* **Abandoned Cart Program ID** (optional): the Dotdigital program an abandoned cart enrols into. Find the ID in the URL when you open the program under **Automation > Programs**.
* **Cart URL** (required): your storefront's cart page URL. Dotdigital rejects a cart update unless every line has a product URL, and Chord falls back to this for a line that has none. Leaving it empty stops cart tracking working at all. It is also the link a shopper follows out of an abandoned cart email.
* **Site Brand** (optional): required only if your Dotdigital account uses Personalization.
* **Send Custom Events** (optional): forwards events Chord has no specific Dotdigital mapping for under their own name, creating an Insight data collection for each. On by default. It requires the CXDP package on your Dotdigital account. Turn it off if you don't have it, because the calls fail silently in the browser.
* **Consent Requirements** (optional): the consent categories a visitor must accept before Chord sends data to this destination. See [Consent](/activate/event-streaming/consent.md).

## Connect

Add **Dotdigital Tag** from the destination catalog, using the settings above. See [Connect a destination](/activate/event-streaming/connect-a-destination.md) for the full steps.

## Event mapping

| Chord event                                                                         | Dotdigital event                                                      | Notes |
| ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ----- |
| `page`, `screen`                                                                    | Page view                                                             |       |
| `Product Viewed`                                                                    | Product browse                                                        |       |
| `Product List Viewed`                                                               | Product list                                                          |       |
| `Product Added`, `Product Removed`, `Cart Viewed`                                   | Cart update                                                           |       |
| `Checkout Started`                                                                  | Checkout                                                              |       |
| `Order Completed`                                                                   | Purchase, with the order reference and cart                           |       |
| `identify`, and the `track` events `Email Captured`, `Signed Up` and `User Created` | Contact identification                                                |       |
| Any other `track` event                                                             | Custom event under its own name — see [Custom events](#custom-events) |       |

## Product and cart data

Dotdigital uses two different product shapes, and Chord sends the right one for each call.

**Product browse and product list** send:

| Chord event                                                  | Dotdigital event                   | Notes |
| ------------------------------------------------------------ | ---------------------------------- | ----- |
| `product_id`, falling back to `id` then `sku`                | `productId`                        |       |
| `sku`                                                        | `sku`                              |       |
| `name`                                                       | `name`                             |       |
| `url`, falling back to the page URL (product browse only)    | `url`                              |       |
| `image_url`                                                  | `imageUrl` and `imageThumbnailUrl` |       |
| `price`                                                      | `price`                            |       |
| `currency`, falling back to `meta.i18n.currency`, then `USD` | `currency`                         |       |
| `brand`                                                      | `brand`                            |       |
| `category`                                                   | `categories`                       |       |
| `description`                                                | `description`                      |       |
| `variant_id`                                                 | `variantId`                        |       |

`imageThumbnailUrl` is filled from the same image as `imageUrl` because Chord's tracking plan carries one product image. Dotdigital's default content blocks read the thumbnail, so an empty one renders a blank image in a browse-abandonment email.

**Cart lines** send:

| Chord event                                                                                                                    | Dotdigital event | Notes |
| ------------------------------------------------------------------------------------------------------------------------------ | ---------------- | ----- |
| `product_id`, falling back to `id` then `sku`                                                                                  | `productId`      |       |
| `sku`, falling back to `variant_id` then `product_id`                                                                          | `sku`            |       |
| `name`                                                                                                                         | `name`           |       |
| `price`                                                                                                                        | `price`          |       |
| `quantity`, defaulting to `1`                                                                                                  | `quantity`       |       |
| `price` × `quantity`                                                                                                           | `totalPrice`     |       |
| `image_url`                                                                                                                    | `imageUrl`       |       |
| `url`, falling back to the event's `url` for the line that changed, then the event's `cart_url`, then the **Cart URL** setting | `url`            |       |
| `brand`                                                                                                                        | `brand`          |       |
| `category`                                                                                                                     | `categories`     |       |
| `description`                                                                                                                  | `description`    |       |
| `variant_id`                                                                                                                   | `variantId`      |       |

**Cart totals** send:

| Chord event                                                                 | Dotdigital event | Notes |
| --------------------------------------------------------------------------- | ---------------- | ----- |
| `cart_id`, falling back to `order_id` or `checkout_id`                      | `cartId`         |       |
| `currency`, falling back to `meta.i18n.currency`, then `USD`                | `currency`       |       |
| `subtotal`, falling back to the sum of the line totals                      | `subtotal`       |       |
| `total`, falling back to `value`, `price`, or the sum of the product prices | `grandTotal`     |       |
| `cart_url`, falling back to the **Cart URL** setting                        | `cartUrl`        |       |
| `shipping`                                                                  | `shipping`       |       |
| `discount`                                                                  | `discountAmount` |       |
| `tax`                                                                       | `taxAmount`      |       |

If an event carries both a cart ID and an order ID, Chord uses the cart ID as `cartId`. On `Order Completed`, Chord sends the order ID separately as `orderId`. It falls back to `order_name`, then to the cart ID, if there is no order ID.

A product line with no resolvable product ID is dropped rather than sent blank, because Dotdigital keys its catalogue and its abandonment content off the product ID.

### Fields Dotdigital requires

Dotdigital rejects a call outright when any of these is missing, and Chord's tracking plan marks them optional. Chord fills each one so your events are not refused, but **the substituted value is a fallback, not your data** — send the real one and it is always preferred.

| Field                        | Substituted with                                                        | What you lose by relying on it                                                                                                                                                                                                                              |
| ---------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Product `url` on a browse    | The URL of the page the event fired on                                  | Nothing, normally. On a `Product Viewed` the page *is* the product's page.                                                                                                                                                                                  |
| Product `url` on a cart line | The event's own `url` for the line that changed, then your **Cart URL** | Every other line links to your cart page instead of its product. The shopper still returns to their basket, but not to the item they were looking at.                                                                                                       |
| `sku` on a cart line         | `variant_id`, then `product_id`                                         | If your Dotdigital catalogue is keyed on real SKUs, the line will not match a catalogue entry, so merchandising blocks in your emails have nothing to render.                                                                                               |
| Cart `subtotal`              | The sum of the line totals                                              | Nothing, normally — it is arithmetic on the lines you sent, and excludes tax and shipping exactly as Dotdigital's own subtotal does. If no line carries a price, Chord sends no subtotal and Dotdigital refuses the cart, rather than reporting it as free. |

**Sending `sku` and `url` on your cart lines is worth the effort.** They are the two whose fallbacks change what a shopper sees in an email. Note that Chord's tracking plan currently documents a product `url` at the event level but not inside the `products` array — so per-line URLs are something to add to your event payload deliberately.

**Every cart update sends your whole basket, not just the line that changed.** Dotdigital's cart update *replaces* the cart it has stored, and its abandonment timer runs against that. So if your `Product Added` event carries a `products` array, Chord sends all of it. Send the full basket on those events, or Dotdigital's cart will be narrower than your shopper's.

A cart update with no cart ID (`cart_id`, `order_id` or `checkout_id`) is skipped, because Dotdigital tracks abandonment against the cart identifier and a cart with no stable ID looks like a new abandoned cart on every change.

## Identity

Dotdigital receives the email address, mobile number and name **in plaintext**, and this is deliberate. Dotdigital has to actually deliver mail and SMS to the person, so unlike an advertising pixel it accepts no hashed identifier — hashing would break delivery rather than protect anything. If your security review needs to know exactly what leaves the page, that is the list.

| Chord source (priority order)                                                                  | Dotdigital field | Notes |
| ---------------------------------------------------------------------------------------------- | ---------------- | ----- |
| `email`, from `properties.email`, `context.traits.email` or `traits.email`                     | `email`          |       |
| `phone`, from `properties.phone`, `context.traits.phone` or `traits.phone`                     | `mobileNumber`   |       |
| `first_name`, from `properties.first_name`, `context.traits.first_name` or `traits.first_name` | `firstName`      |       |
| `last_name`, from `properties.last_name`, `context.traits.last_name` or `traits.last_name`     | `lastName`       |       |
| `first_name` + `last_name`                                                                     | `fullName`       |       |

**Mobile numbers must be in E.164 format** — `+14155550123`. A number with no country code is skipped rather than guessed at: completing it would mean assuming a country, and a wrong assumption can resolve to a real contact somewhere else and send them someone else's messages. Formatting like spaces, dashes and brackets is fine; a leading `00` is treated the same as `+`.

An identify with neither an email nor a valid E.164 mobile number is skipped, since Dotdigital has no contact to attach it to.

The name fields are Personalization-only. Dotdigital's Marketing platform ignores them, so they matter only if your account uses Personalization.

## Custom events

Dotdigital's event taxonomy is **open**: an event Chord has no specific mapping for is forwarded under its own name, and Dotdigital creates an Insight data collection for it. `Loyalty Tier Changed` becomes a `Loyalty_Tier_Changed` collection — Dotdigital replaces non-alphanumeric characters with underscores when it names the collection.

Chord sends only the event name and the mapped properties described under Property mappings, plus the event's `messageId`. It doesn't send the event's other properties. Chord trims the event name and cuts it to 80 characters.

Two limits:

* **Custom events need the CXDP package** on your Dotdigital account. Without it Dotdigital cannot accept them, and because the Tag's calls are fire-and-forget the rejection is invisible from the page. Turn **Send Custom Events** off if your account does not have CXDP. Turning it off does not affect any of the mapped commerce events.
* **Nine collection names are reserved** by Dotdigital for its own features: `cartInsight`, `catalog`, `consentInsight`, `easyEditorExtensions`, `nostoEmailCampaigns`, `orders`, `productCategories`, `webInsight` and `wishList`. An event whose name matches one of those is skipped, and the reason is logged to the browser console.

## Property mappings

You can map any event property onto a destination field from the connection's mapping configuration. Mapped properties use a **bare path** on this destination — `properties.customer_type → customer_type`, with no `properties.` prefix on the destination side.

**Mapped properties reach custom events only.** They are forwarded as attributes on the custom-event call, and nowhere else. That is a Dotdigital constraint rather than a Chord choice: `identify`, the product calls and every cart call take a fixed set of fields with no property bag anywhere, so an extra key has nowhere to go. A mapping you configure will not appear on a product view, a cart update or an order.

Mapping onto a field Dotdigital *does* accept still works — a mapping that rewrites `properties.sku` changes what Chord reads for the product's `sku`, because mappings are applied before the payload is built. It is only destination keys with no Dotdigital equivalent that have nowhere to land.

Personal fields — `email`, `phone`, `first_name`, `last_name` and their camelCase forms — are never forwarded as custom attributes. They go through the identification call above instead.

## Content security policy

If your storefront sets a Content Security Policy, the Dotdigital Tag will not load until its hosts are allowed. The symptom is silence: no tracking, no abandonment, and a `Refused to load` or `Refused to connect` message in the browser console.

**The first host to allow is the one in your own Tag URL, and it is account-specific.** Dotdigital serves the Tag from `ddlnk.net` for some accounts and from a domain of your own for others — an account configured with a branded sending domain gets a Tag URL like `https://emails.yourbrand.com/DM-0000000000-01/ddgtag.js`. Read the host off the **Tag URL** you pasted into the destination and allow that one, rather than assuming the table below covers you.

| Directive     | Host                                                                               |
| ------------- | ---------------------------------------------------------------------------------- |
| `script-src`  | the host from your Tag URL, plus `https://*.ddlnk.net`                             |
| `connect-src` | the host from your Tag URL, plus `https://*.ddlnk.net`, `https://*.trackedweb.net` |

Both directives are required. `script-src` lets the Tag load; `connect-src` lets it report — and a policy that allows only the first fails in a way that looks like it worked, because the script runs and nothing reaches Dotdigital.

**This list was confirmed on a live account**, with one addition worth knowing: the account tested had a branded domain, and its Tag URL host had to be allowed in `script-src` on top of the two Dotdigital domains. That host differs per account, which is why it cannot be listed here.

Dotdigital does not publish its CSP requirements, and the Tag routes to a regional host at runtime, so treat the table as a starting point rather than a complete list. Verify it during setup: load a page with the destination active, then fire a product view, a cart update and an order, and add any host named in a violation. Check the Network tab as well as the console — a blocked image beacon can be quieter than a blocked script.

## Gotchas

**Two tags is the most common problem.** If page views look doubled or abandonment fires against a cart that does not match, check whether a hand-installed Dotdigital Tag or a platform app is still on the page.

**Dotdigital's calls are fire-and-forget.** They return nothing and throw nothing, by design, so a rejected call does not surface on the page. To confirm a call succeeded, inspect the request in your browser's Network tab: a `200` means Dotdigital accepted it, a `4xx` means something is misconfigured.

**Cart abandonment needs a cart update on every page.** Dotdigital's timer runs from the last cart update it saw, so a storefront that only reports the cart on the cart page will trigger abandonment early. Fire a cart-bearing event as the shopper continues browsing.

**An empty `Order Completed` is skipped.** An order event with no products is not sent, because it would write an empty order into the collection your post-purchase programs and order content blocks read — an email with nothing in it.

**Consent gating applies.** If the destination is configured with required consent categories, no Dotdigital call is made for visitors who have not accepted them.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.chord.co/activate/event-streaming/destinations/email-and-marketing/dotdigital/dotdigital-tag.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
