Using Shopify Checkout Personalization with Manual Dynamic Yield Implementation

The use case this article addresses:

You have a manual implementation of Dynamic Yield on your storefront, running our scripts.

You want to use the Dynamic Yield app's checkout personalization (the Dynamic Banner checkout block), because third-party scripts aren't directly supported in Shopify checkout. But you don't want our app's regular storefront scripts to clash with your running scripts.

And you can!

The Dynamic Yield Shopify integration includes two separate parts:

  • Storefront implementation scripts: Include Dynamic Yield scripts, page context, event tracking, and so on.
  • Checkout personalization: The checkout UI block that calls Dynamic Yield to fetch and render personalized content in a banner.

Therefore, you can turn on checkout personalization while leaving the regular storefront scripts off. The only additional step is to pass your existing Dynamic Yield visitor/session identity through to checkout, so that the personalization shown at checkout is based on the same visitor identity Dynamic Yield already knows — instead of a brand new, disconnected one.

This guide walks through exactly how to do that. The steps include:

  • Enable checkout personalization
  • Add checkout placement blocks
  • Pass Dynamic Yield identity values into checkout
  • Fetch and render personalized experiences using a consistent visitor identity
  • Validate the implementation

How checkout personalization works

At a high level, the checkout extension:

  1. Reads Dynamic Yield identity values from the cart attributes (or line item properties of the "buy it now" flow).
  2. Uses those values when calling the Dynamic Yield Choose API.
  3. Renders the retrieved experience as a native Shopify checkout block.
  4. Reports impressions and clicks back to Dynamic Yield.

Important: The Shopify Checkout extension expects the identity to already exist in the cart attributes or line item properties when the visitor reaches checkout. As you are managing your own Dynamic Yield implementation, you must make sure the required values are passed.


Step 1: Enable checkout personalization

In Experience OS:

  1. Go to Settings › API Keys.
  2. Copy a client-side API key to use for Choose and Engagement API requests.

In Shopify:

  1. Go to the DY Shopify app, and add the API key to the Experience API Key field.
  2. Enable checkout personalization in the app settings. You can toggle this on/off as needed.
⚠️

Important

Do not enable DY Embed Block in your theme if you only want checkout personalization. The embed block deploys the same Dynamic Yield script elements you're already managing yourself.


Step 2: Add the checkout block

  1. In Shopify, go to Settings › Checkout.
  2. Click Customize.
  3. Add the Dynamic Banner block to the desired checkout location.
  4. In the block settings, enter the selector used by your checkout personalization campaign or variation in the Selector Name field.
  5. Repeat for any additional placements, using a different selector for each one.

Preview and publish the block the same way as any other checkout customization.


Step 3: Pass Dynamic Yield identity values to checkout

This step is at the center of this process. The Dynamic Yield script creates a user identifier and a session identifier for every visitor, and stores them as follows:

  • localStorage['_dyid'] — the persistent user ID
  • window.DY.jsession — the current session ID

The Dynamic Yield Shopify Checkout extension can't read these values directly (it can't access your storefront's localStorage or window state).

Instead, the extension reads the following cart attributes:

Cart AttributeDescription
_dyid_serverDynamic Yield visitor identifier
_dy_app_jsessionDynamic Yield session identifier

For direct checkout flows such as Buy it now, where no persistent cart exists, the checkout extension also checks for the same values as line item properties:

  • properties[_dyid_server]
  • properties[_dy_app_jsession]

→ Make sure to use these exact attribute and property names.


Step 4: Add an identity bridge script

Add the following script to your storefront theme (for example, in theme.liquid or via your tag manager) so that it runs on every storefront page.

The script waits for Dynamic Yield to create the identifiers, then copies them into the cart attributes and any product or checkout forms Dynamic Yield needs.

<script>
(function () {
  const POLL_INTERVAL_MS = 500;
  const MAX_ATTEMPTS = 20;
  let attempts = 0;

  function getDyIdentity() {
    const dyid = localStorage.getItem('_dyid');
    const jsession = window.DY && window.DY.jsession;
    return dyid && jsession ? { dyid, jsession } : null;
  }

  async function syncToCartAttributes({ dyid, jsession }) {
    await fetch('/cart/update.js', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        attributes: {
          _dyid_server: dyid,
          _dy_app_jsession: jsession,
        },
      }),
    });
  }

  function injectLineItemProperties(form, { dyid, jsession }) {
    form.querySelectorAll(
      'input[name="properties[_dyid_server]"], input[name="properties[_dy_app_jsession]"]'
    ).forEach((el) => el.remove());

    const dyidInput = document.createElement('input');
    dyidInput.type = 'hidden';
    dyidInput.name = 'properties[_dyid_server]';
    dyidInput.value = dyid;
    form.appendChild(dyidInput);

    const sessionInput = document.createElement('input');
    sessionInput.type = 'hidden';
    sessionInput.name = 'properties[_dy_app_jsession]';
    sessionInput.value = jsession;
    form.appendChild(sessionInput);
  }

  function isProductForm(form) {
    return (
      (form.action && form.action.includes('/cart')) ||
      form.querySelector('[name="add"]') !== null
    );
  }

  function tagAllProductForms(identity) {
    document.querySelectorAll('form').forEach((form) => {
      if (isProductForm(form)) {
        injectLineItemProperties(form, identity);
      }
    });
  }

  const poll = setInterval(() => {
    attempts++;
    const identity = getDyIdentity();

    if (identity) {
      syncToCartAttributes(identity);
      tagAllProductForms(identity);
      clearInterval(poll);
      return;
    }

    if (attempts >= MAX_ATTEMPTS) {
      clearInterval(poll);
    }
  }, POLL_INTERVAL_MS);

  new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      mutation.addedNodes.forEach((node) => {
        if (
          node.nodeType === 1 &&
          node.tagName === 'FORM' &&
          isProductForm(node)
        ) {
          const identity = getDyIdentity();

          if (identity) {
            injectLineItemProperties(node, identity);
          }
        }
      });
    });
  }).observe(document.body, {
    childList: true,
    subtree: true,
  });
})();
</script>

That's basically it. With the script deployed, you can use checkout personalization without enabling the DY Embed Block in your theme, as long as the cart or line item properties are present.

Step 5: Validate the implementation

After configuring the identity bridge and checkout placement, verify that Dynamic Yield identifiers are successfully passed into Shopify Checkout.

Verify Dynamic Yield identity values

Open your storefront in a new browser or incognito/private session, and use the browser dev tools to confirm that Dynamic Yield has created both identifiers and that each returns a value:

localStorage.getItem('_dyid'); 
window.DY.jsession; 

Verify cart attributes

Add a product to the cart and confirm that the required cart attributes were populated:

fetch('/cart.js')
  .then((r) => r.json())
  .then((cart) => console.log(cart.attributes));

Expected output:

{
  _dyid_server: "...",
  _dy_app_jsession: "..."
}

Verify checkout personalization

  1. Proceed to checkout.
  2. Confirm that the Dynamic Banner block appears in the configured location.
  3. Verify that the personalized experience is displayed as expected.

Verify accelerated checkout flows

If your storefront supports direct checkout options such as Buy it now, verify that the required Dynamic Yield identifiers are included as line item properties (view the checkout via Shopify order or draft order attributes, or check network requests for properties[_dyid_server]).

Troubleshooting

If the checkout block is not displayed, verify that:

  • Checkout personalization is enabled in the Dynamic Yield Shopify app
  • The block’s Selector Name matches a live Dynamic Yield campaign/variation
  • The Experience API Key is configured correctly
  • The _dyid and DY.jsession identifiers are being created before the identity bridge script runs
    (Note that some tag manager implementations load Dynamic Yield asynchronously, so you might need to increase the polling window in the bridge script)
  • The required cart attributes or line item properties are being populated correctly

Frequently asked questions

Do I need to enable your app's theme embed block?

No. Checkout personalization works without enabling our storefront embed — as long as the required Dynamic Yield identifiers are passed into checkout using the bridge script provided in this article.

What happens if I don't bridge the identity?

Checkout personalization can still function, but each checkout session is treated as a separate anonymous Dynamic Yield visitor. It won’t be linked to the browsing or behavioral history your own implementation has already built for that visitor. Bridging the identity is what keeps checkout personalization consistent with the rest of your Dynamic Yield activity.

Can I use both — my own implementation AND your regular scripts?

No. Running multiple Dynamic Yield tags on the same storefront at once can create conflicting visitor identities, duplicate events, and other inconsistencies.

Choose one method for your storefront (either your manual implementation or our embedded app) and then layer checkout personalization on top of it.

Does this affect consent or privacy handling?

Checkout personalization calls Dynamic Yield directly from the checkout block. If your organization requires specific consent handling before calling Dynamic Yield, make sure that’s accounted for in terms of how and when your bridging script runs (for example, only writing the cart attributes after consent has been given).





Did this page help you?