---
title: Installation
slug: installation
docTags: 
createdAt: 2024-05-15T18:59:36.130Z
---

To install the Chord web pixel on your Shopify store:

1. Ask the Chord team for the full web pixel code (see the example below).
2. Navigate to **Settings** > **Customer events** in your Shopify store.
3. Select **Add custom pixel**.
4. Enter "Chord Analytics" as the name for your pixel.
5. Select **Add pixel**.
6. Review the customer privacy settings, and see our guide to [consent management](docId\:dbKzUyYJsHKX7dzHiSfeZ) to understand how these settings will impact your event tracking.
7. In the **Code** text box, copy and paste the provided web pixel code.
8. Before you publish the provided web pixel, you need to update the settings `const` variables at the very top of the JavaScript code. See the [configuration guide](docId\:qMM8Kz1WShyJhs9qbh0vm) for a detailed explanation of each `const` variable. After you've updated the `const` variables, select **Save**.
9. Once the pixel has been saved successfully, you can select **Connect** to enable the pixel on your Shopify store. Once you select **Connect**, the pixel will immediately load and start tracking events, so make sure you finalize the pixel settings first.

::::CodeDrawer{title="Shopify web pixel code (EXAMPLE ONLY)" isResponseExpanded="false" autoGeneratedAnchorSlug="shopify-web-pixel-code-example-only" legacyHash="6FPBlIHJ__YC4LBSYdosk"}
:::CodeblockTabsExamples
```javascript
const CDP_WRITE_KEY =
  ''
const CDP_DOMAIN = 'https://production.cdp.ingest.chord.co'
const CHORD_OMS_ID = ''
const CHORD_STORE_ID = ''
const CHORD_TENANT_ID = ''
const DEFAULT_LOCALE = 'en-US'
const STORE_DOMAIN = ''
const PIXEL_VERSION = '1.0.0'
let customerPrivacyStatus = init.customerPrivacy
let currency = init.data.cart?.cost?.totalAmount.currencyCode
let locale = DEFAULT_LOCALE

function getStorefrontAnonymousId() {
  return document.cookie
    .split('; ')
    .find((c) => c.startsWith('__eventn_id='))
    ?.split('=')[1]
}
// ============================================================================
// CDP Initialization (lazy — loads p.js on first checkout event)
// ============================================================================
let cdpInitialized = false
function initCdp() {
  if (cdpInitialized) return
  if (!CDP_WRITE_KEY || !CDP_DOMAIN) return
  cdpInitialized = true
  window.chordQ = window.chordQ || []
  window.chord = window.chord || {
    identify: (...args) => window.chordQ?.push((cdp) => cdp?.identify(...args)),
    page: (...args) => window.chordQ?.push((cdp) => cdp?.page(...args)),
    track: (...args) => window.chordQ?.push((cdp) => cdp?.track(...args)),
  }
  const script = document.createElement('script')
  script.async = true
  script.src = `${CDP_DOMAIN}/p.js`
  script.setAttribute('data-init-only', 'true')
  script.setAttribute('data-namespace', 'chord')
  script.setAttribute('data-write-key', CDP_WRITE_KEY)
  document.head.appendChild(script)
  const cdpUserId = window.chord?.user?.()?.userId
  const userId = init.data.customer?.id
  if (userId && userId !== cdpUserId) {
    const traits = getInitCustomerTraits(init)
    cdpIdentify(userId, traits)
  }
}
// ============================================================================
// Consent Management
// ============================================================================
api.customerPrivacy.subscribe('visitorConsentCollected', (event) => {
  customerPrivacyStatus = event.customerPrivacy
})
;(function identifyOnLoad() {
  const customer = init.data.customer
  if (!customer?.id) return
  const traits = {}
  if (customer.email) traits.email = customer.email
  if (customer.firstName) traits.firstName = customer.firstName
  if (customer.lastName) traits.lastName = customer.lastName
  if (customer.phone) traits.phone = customer.phone
  if (customer.ordersCount) traits.ordersCount = customer.ordersCount
  forward('identify', customer.id, traits)
})()
// ============================================================================
// Event Subscriptions — All 13 Shopify events
// ============================================================================
// --- Storefront-only events (postMessage only) ---
analytics.subscribe('page_viewed', (event) => {
  forward('page', {
    path: event.context.document.location.pathname,
    url: event.context.document.location.href,
    title: event.context.document.title,
  })
})
analytics.subscribe('product_viewed', (event) => {
  const { productVariant } = event.data
  forward('track', 'Product Viewed', formatProduct(productVariant))
})
analytics.subscribe('product_added_to_cart', (event) => {
  const { cartLine } = event.data
  if (!cartLine) return
  const product = formatCartLine(cartLine)
  forward('track', 'Product Added', {
    ...product,
    products: [product],
  })
})
analytics.subscribe('product_removed_from_cart', (event) => {
  const { cartLine } = event.data
  if (!cartLine) return
  const product = formatCartLine(cartLine)
  forward('track', 'Product Removed', {
    ...product,
    products: [product],
  })
})
analytics.subscribe('cart_viewed', (event) => {
  const { cart } = event.data
  if (!cart) return
  forward('track', 'Cart Viewed', {
    cart_id: cart.id,
    currency: cart.cost.totalAmount.currencyCode,
    value: cart.cost.totalAmount.amount,
    products: cart.lines.map(formatCartLine),
  })
})
analytics.subscribe('collection_viewed', (event) => {
  const { collection } = event.data
  forward('track', 'Product List Viewed', {
    list_id: collection.id,
    item_list_id: collection.id,
    list_name: collection.title,
    item_list_name: collection.title,
    products: collection.productVariants.map(formatProduct),
  })
})
analytics.subscribe('search_submitted', (event) => {
  forward('track', 'Products Searched', {
    query: event.data.searchResult.query,
  })
})
// --- Checkout events (postMessage + direct CDP) ---
analytics.subscribe('checkout_started', async (event) => {
  const { checkout } = event.data
  // postMessage (sync, fire-and-forget)
  forward('track', 'Checkout Started', formatCheckout(checkout))
  // Direct CDP
  const coupon = getCoupon(checkout)
  const discount = getDiscount(checkout)
  const props = {
    checkout_type: 'Shopify',
    coupon,
    currency: checkout.currencyCode,
    discount,
    products: checkout.lineItems.map(getLineItem),
    revenue: checkout.subtotalPrice.amount,
    shipping: checkout.shippingLine?.price.amount,
    tax: checkout.totalTax.amount,
    value: checkout.subtotalPrice.amount,
  }
  await cdpTrack('Checkout Started', props)
})
analytics.subscribe('checkout_contact_info_submitted', async (event) => {
  const { checkout } = event.data
  // postMessage (sync, fire-and-forget)
  // Use undefined for userId — email is not a stable ID; the real customer ID
  // is set at checkout_completed when checkout.order.customer.id is available.
  forward('identify', undefined, {
    email: checkout.email,
    phone: checkout.phone,
  })
  forward('track', 'Checkout Step Completed', {
    checkout_id: checkout.token,
    step: 1,
    step_name: 'Contact Info',
  })
  // Direct CDP
  const checkoutTraits = getCheckoutTraits(checkout)
  const initTraits = getInitCustomerTraits(init)
  const traits = {
    ...initTraits,
    ...checkoutTraits,
  }
  const userId = traits.id || undefined
  await cdpIdentify(userId, traits)
  const props = {
    checkout_id: checkout.token,
    step: 1,
  }
  await cdpTrack('Checkout Step Completed', props)
})
analytics.subscribe('checkout_address_info_submitted', async (event) => {
  // postMessage (sync, fire-and-forget)
  forward('track', 'Checkout Step Completed', {
    checkout_id: event.data.checkout.token,
    step: 2,
    step_name: 'Shipping Address',
  })
  // Direct CDP
  const props = {
    checkout_id: event.data.checkout.token,
    step: 2,
  }
  await cdpTrack('Checkout Step Completed', props)
})
analytics.subscribe('checkout_shipping_info_submitted', async (event) => {
  // postMessage (sync, fire-and-forget)
  forward('track', 'Checkout Step Completed', {
    checkout_id: event.data.checkout.token,
    step: 3,
    step_name: 'Shipping Method',
  })
  // Direct CDP
  const props = {
    checkout_id: event.data.checkout.token,
    step: 3,
  }
  await cdpTrack('Checkout Step Completed', props)
})
analytics.subscribe('payment_info_submitted', async (event) => {
  const { checkout } = event.data
  // postMessage (sync, fire-and-forget)
  forward('track', 'Payment Info Entered', {
    checkout_id: checkout.token,
    step: 4,
    currency: checkout.currencyCode,
    value: checkout.subtotalPrice.amount,
    products: checkout.lineItems.map(formatLineItem),
  })
  // Direct CDP
  const coupon = getCoupon(checkout)
  const props = {
    checkout_id: checkout.token,
    coupon,
    currency: checkout.currencyCode,
    products: checkout.lineItems.map(getLineItem),
    step: 4,
    value: checkout.subtotalPrice.amount,
  }
  await cdpTrack('Payment Info Entered', props)
})
analytics.subscribe('checkout_completed', async (event) => {
  const { checkout } = event.data
  // postMessage (sync, fire-and-forget)
  const userId = checkout.order?.customer?.id || undefined
  forward('identify', userId, {
    email: checkout.email,
    phone: checkout.phone,
    firstName: checkout.shippingAddress?.firstName,
    lastName: checkout.shippingAddress?.lastName,
  })
  forward(
    'track',
    'Order Completed',
    formatOrderCompleted(checkout, event.timestamp)
  )
  // Direct CDP
  const coupon = getCoupon(checkout)
  const discount = getDiscount(checkout)
  const orderProps = {
    checkout_id: checkout.token,
    checkout_type: 'Shopify',
    coupon,
    currency: checkout.currencyCode,
    discount,
    email: checkout.email || undefined,
    first_name: checkout.shippingAddress?.firstName || undefined,
    last_name: checkout.shippingAddress?.lastName || undefined,
    order_date: event.timestamp,
    order_id: checkout.order?.id,
    phone: checkout.phone || undefined,
    products: checkout.lineItems.map((item, i) => {
      const price = item.variant?.price.amount
      const itemDiscount = item.discountAllocations.reduce(
        (acc, { amount }) => acc + (amount.amount || 0),
        0
      )
      const revenue = price ? (item.quantity || 1) * price - itemDiscount : 0
      return {
        ...getLineItem(item, i),
        revenue,
      }
    }),
    revenue: checkout.subtotalPrice.amount,
    shipping: checkout.shippingLine?.price.amount,
    shipping_city: checkout.shippingAddress?.city || undefined,
    shipping_country: checkout.shippingAddress?.country || undefined,
    shipping_state: checkout.shippingAddress?.province || undefined,
    shipping_zipcode: checkout.shippingAddress?.zip || undefined,
    subtotal: checkout.subtotalPrice.amount,
    tax: checkout.totalTax.amount,
    total: checkout.totalPrice.amount,
  }
  const checkoutTraits = getCheckoutTraits(checkout)
  const initTraits = getInitCustomerTraits(init)
  const traits = {
    ...initTraits,
    ...checkoutTraits,
  }
  const cdpUserId = traits.id || undefined
  await cdpIdentify(cdpUserId, traits)
  await cdpTrack('Order Completed', orderProps)
})
function forward(type, ...args) {
  try {
    const target =
      typeof window !== 'undefined' && window.top ? window.top : self
    target.postMessage(
      {
        source: 'chord-web-pixel',
        type,
        payload: args,
      },
      '*'
    )
  } catch (err) {
    // Silently fail if postMessage is not available
  }
}
// ============================================================================
// Lightweight Data Formatters (for postMessage forwarding)
// ============================================================================
function formatProduct(variant) {
  const product = variant?.product
  return {
    product_id: product?.id,
    sku: variant?.sku,
    name: product?.title || product?.untranslatedTitle,
    price: variant?.price?.amount,
    currency: variant?.price?.currencyCode,
    category: product?.type,
    brand: product?.vendor,
    variant: variant?.title || variant?.untranslatedTitle,
    variant_id: variant?.id,
    image_url: variant?.image?.src,
    url: product?.url,
  }
}
function formatCartLine(cartLine) {
  const variant = cartLine.merchandise
  const product = variant?.product
  return {
    product_id: product?.id,
    sku: variant?.sku,
    name: product?.title || product?.untranslatedTitle,
    price: variant?.price?.amount,
    currency: cartLine.cost.totalAmount.currencyCode,
    quantity: cartLine.quantity,
    category: product?.type,
    brand: product?.vendor,
    variant: variant?.title || variant?.untranslatedTitle,
    variant_id: variant?.id,
    image_url: variant?.image?.src,
    url: product?.url,
    value: cartLine.cost.totalAmount.amount,
  }
}
function formatLineItem(item, index) {
  const variant = item.variant
  const product = variant?.product
  return {
    product_id: product?.id,
    sku: variant?.sku,
    name: product?.title || product?.untranslatedTitle,
    price: variant?.price?.amount,
    quantity: item.quantity,
    category: product?.type,
    brand: product?.vendor,
    variant: variant?.title || variant?.untranslatedTitle,
    variant_id: variant?.id,
    image_url: variant?.image?.src,
    url: product?.url,
    position: typeof index === 'number' ? index + 1 : undefined,
  }
}
function formatCheckout(checkout) {
  const discount = checkout.lineItems.reduce((acc, item) => {
    return (
      acc +
      item.discountAllocations.reduce(
        (sum, d) => sum + (d.amount.amount || 0),
        0
      )
    )
  }, 0)
  const coupon = checkout.discountApplications.find((d) => {
    if ('amount' in d.value) return d.value.amount > 0
    return d.value.percentage > 0
  })?.title
  return {
    checkout_id: checkout.token,
    currency: checkout.currencyCode,
    value: checkout.subtotalPrice.amount,
    revenue: checkout.subtotalPrice.amount,
    shipping: checkout.shippingLine?.price?.amount,
    tax: checkout.totalTax?.amount,
    discount,
    coupon,
    products: checkout.lineItems.map(formatLineItem),
  }
}
function formatOrderCompleted(checkout, timestamp) {
  const base = formatCheckout(checkout)
  return {
    ...base,
    order_id: checkout.order?.id,
    order_date: timestamp,
    total: checkout.totalPrice.amount,
    subtotal: checkout.subtotalPrice.amount,
    email: checkout.email,
    phone: checkout.phone,
    first_name: checkout.shippingAddress?.firstName,
    last_name: checkout.shippingAddress?.lastName,
    shipping_city: checkout.shippingAddress?.city,
    shipping_state: checkout.shippingAddress?.province,
    shipping_country: checkout.shippingAddress?.country,
    shipping_zipcode: checkout.shippingAddress?.zip,
  }
}
// ============================================================================
// Direct CDP Methods (for checkout events in the sandbox)
// ============================================================================
function cdpEnabled() {
  if (window.chord) return true
  if (!CDP_WRITE_KEY || !CDP_DOMAIN) return false
  initCdp()
  return !!window.chord
}
async function cdpIdentify(userId, traits) {
  if (!cdpEnabled()) return
  const options = await getOptions()
  const anonymousId = getStorefrontAnonymousId()
  await window.chord.identify(userId, traits, {
    ...options,
    ...(anonymousId && {
      anonymousId,
    }),
    context: {
      page: options.page,
    },
  })
}
async function cdpTrack(event, props) {
  if (!cdpEnabled()) return
  const options = await getOptions()
  const meta = await getMeta()
  const anonymousId = getStorefrontAnonymousId()
  await window.chord.track(
    event,
    {
      ...props,
      meta,
      context: {
        page: options.page,
      },
    },
    {
      ...options,
      ...(anonymousId && {
        anonymousId,
      }),
    }
  )
}
// ============================================================================
// CDP Options & Metadata
// ============================================================================
async function getCategoryPreferences() {
  return {
    analytics: customerPrivacyStatus?.analyticsProcessingAllowed,
    marketing: customerPrivacyStatus?.marketingAllowed,
    preferences: customerPrivacyStatus?.preferencesProcessingAllowed,
    sale_of_data: customerPrivacyStatus?.saleOfDataAllowed,
  }
}
async function getOptions() {
  const categoryPreferences = (await getCategoryPreferences()) || {}
  return {
    consent: {
      categoryPreferences,
    },
    page: {
      path: init.context.document.location.pathname,
      url: init.context.document.location.href,
    },
  }
}
async function getMeta() {
  if (!currency) {
    currency = await browser.cookie.get('cart_currency')
  }
  return {
    i18n: {
      currency,
      locale,
    },
    ownership: {
      oms_id: CHORD_OMS_ID,
      store_id: CHORD_STORE_ID,
      tenant_id: CHORD_TENANT_ID,
    },
    platform: {
      name: 'Shopify',
      type: 'web',
    },
    store: {
      domain: STORE_DOMAIN,
    },
    version: {
      major: 3,
      minor: 0,
      patch: 0,
    },
  }
}
// ============================================================================
// Rich Data Formatters (for direct CDP — adapted from legacy pixel)
// ============================================================================
function getLineItem(item, position) {
  const variant = 'variant' in item ? item.variant : item.merchandise
  const product = variant?.product
  const discountAllocations =
    'discountAllocations' in item ? item.discountAllocations : undefined
  const coupon = discountAllocations?.find((al) => al?.amount?.amount > 0)
    ?.discountApplication.title
  return {
    brand: product?.vendor,
    category: product?.type || undefined,
    coupon,
    image_url: variant?.image?.src,
    line_item_id: 'id' in item ? item.id : undefined,
    name: product?.title || product?.untranslatedTitle,
    position: typeof position === 'number' ? position + 1 : undefined,
    price: variant?.price.amount,
    product_id: product?.id,
    quantity: ('quantity' in item && item.quantity) || undefined,
    sku: variant?.sku || undefined,
    url: product?.url,
    variant: variant?.title || variant?.untranslatedTitle || undefined,
    variant_id: variant?.id,
  }
}
function getDiscount(checkout) {
  return checkout.lineItems.reduce((acc, item) => {
    const { discountAllocations } = item
    const discount = discountAllocations.reduce((innerAcc, { amount }) => {
      return innerAcc + (amount.amount || 0)
    }, 0)
    return acc + discount
  }, 0)
}
function getCoupon(checkout) {
  return checkout.discountApplications.find(({ value }) => {
    if ('amount' in value) return value.amount > 0
    return value.percentage > 0
  })?.title
}
function getCheckoutTraits(checkout) {
  const traits = {}
  if (checkout.email) traits.email = checkout.email
  if (checkout.phone) traits.phone = checkout.phone
  const customerId = checkout.order?.customer?.id
  if (customerId) traits.id = customerId
  return traits
}
function getInitCustomerTraits(init) {
  const { customer } = init.data
  const traits = {}
  if (customer?.email) traits.email = customer.email
  if (customer?.firstName) traits.firstName = customer.firstName
  if (customer?.id) traits.id = customer.id
  if (customer?.lastName) traits.lastName = customer.lastName
  if (customer?.ordersCount) traits.ordersCount = customer.ordersCount
  if (customer?.phone) traits.phone = customer.phone
  return traits
}

```
:::

:::CodeblockTabsResponses
```javascript
```
:::
::::

