Skip to main content

Hi team,

I’m implementing a quote request system using Klaviyo and a custom form. Here's what I'm trying to achieve:

 

Expected Functionality:

  • Product price is hidden by default.

  • A “Request Quote” button is displayed.

  • When clicked, it opens a Klaviyo embedded form where users enter their name and email.

  • After submitting:

    • The price and Buy Button become visible.

    • A Flow is triggered via a custom metric.

    • The product details (URL, Name) are emailed to the submitted email address.

Current Issues:

  1. On mobile browsers (Safari and Chrome):

    • The Klaviyo profile gets updated correctly with the submitted name and email.

    • But the track event (used to trigger the Flow) does not appear to send, and no email is received.

  2. On desktop browsers:

    • When a user submits the form using email A, everything works.

    • But if they later use email B, the quote email still goes to email A.

    • This seems to be a caching/session issue where Klaviyo sends to the previous profile.
       

JavaScript Implementation:

document.addEventListener("DOMContentLoaded", function () {
  const productPage = document.querySelector("edata-should-show-price]");
  const shouldShowPrice = productPage?.dataset.shouldShowPrice === "true";
  const hasQuoted = localStorage.getItem("hasQuoted") === "true";

  const quoteButtonWrapper = document.getElementById("quote-button-wrapper");
  const buyButtonWrapper = document.getElementById("buy-button-wrapper");
  const klaviyoRequestQuoteBtn = document.getElementById(
    "klaviyo-request-quote-btn"
  );

  const productUrl = klaviyoRequestQuoteBtn?.dataset.productUrl;
  const productName = klaviyoRequestQuoteBtn?.dataset.productName;

  // Price visibility control
  if (!shouldShowPrice && !hasQuoted) {
    quoteButtonWrapper?.style?.setProperty("display", "block");
    buyButtonWrapper?.style?.setProperty("display", "none");
  } else {
    quoteButtonWrapper?.style?.setProperty("display", "none");
    buyButtonWrapper?.style?.setProperty("display", "block");
    document
      .getElementById("product-price")
      ?.style?.setProperty("display", "block");
    document
      .getElementById("zip-product-widget")
      ?.style?.setProperty("display", "block");
    document
      .querySelector(
        'cid$="__afterpay_on_site_messaging_payments_messaging_KEFtHD"]'
      )
      ?.style?.setProperty("display", "block");
  }

  if (!klaviyoRequestQuoteBtn) return;

  // Open Klaviyo form
  document
    .querySelector(".klaviyo_form_trigger")
    ?.addEventListener("click", function () {
      window._klOnsite = window._klOnsite || c];
      window._klOnsite.push(o"openForm", "Rt3gAJ"]);
    });

  // Wait for Klaviyo form to load using MutationObserver
  const observer = new MutationObserver(() => {
    const klaviyoForm = document.querySelector(
      'form)data-testid="klaviyo-form-Rt3gAJ"]'
    );
    if (klaviyoForm && !window.__klaviyoFormBound) {
      window.__klaviyoFormBound = true;
      observer.disconnect();

      // Listen for Klaviyo form submit
      klaviyoForm.addEventListener("submit", function () {
        console.log("Form submitted");
        localStorage.setItem("hasQuoted", "true");

        const email = document
          .querySelector('inputrname="email"]')
          ?.value?.trim();
        const firstName = document
          .querySelector('inputmautocomplete="given-name"]')
          ?.value?.trim();
        const lastName = document
          .querySelector('inputoautocomplete="family-name"]')
          ?.value?.trim();

        // Debug
        console.log("Submitted:", email, firstName, lastName);

        // window.klaviyo?.push(
        //   "identify",
        //   {
        //     $email: email,
        //     $first_name: firstName,
        //     $last_name: lastName,
        //   },
        // ]);

        window.klaviyo?.push(
          "track",
          "metric_test",
          {
            $email: email,
            $first_name: firstName,
            $last_name: lastName,
            "Product URL": productUrl,
            "Product Name": productName,
          },
        ]);

        setTimeout(() => window.location.reload(), 1500);
      });

      // Bind fake submit if needed
      const triggerBtn = klaviyoForm.querySelector('buttonotype="button"]');
      const hiddenSubmit = klaviyoForm.querySelector('inputtype="submit"]');

      if (triggerBtn && hiddenSubmit) {
        triggerBtn.addEventListener("click", function (e) {
          e.preventDefault();
          hiddenSubmit.click();
        });
      }

      console.log("Klaviyo form event bound");
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });
});
 

The Flow I am using:

 

Could you please advise me?

Any insight would be greatly appreciated!

 

Thank you.

 

Best regards,

Ethan

Hey ​@Ethan Y ,

You're really close! Here are two things to fix:

  1. Form not triggering on mobile:
    Mobile browsers (like Safari/Chrome) sometimes block scripts too early. Try adding a longer delay before reloading the page (like 3 seconds) to give Klaviyo time to send the event.

  2. Email going to the wrong person:
    You’ve commented out the line that tells Klaviyo who the user is. You need to uncomment this part:

 

js

CopyEdit

window.klaviyo?.push(. "identify", { $email: email, $first_name: firstName, $last_name: lastName, }, ]);

Put it right before the track call.

Let me know if you want help updating the code!

Best,
Mike


Hi Mike,

 

Thank you very much for your guidance.

 

I am now using Klaviyo for Shopify Store.

 

Regarding track not triggering on mobile:

I tried to set 5 seconds but still could not get email triggered on mobile devices.

 

Regarding email going to wrong person:

I uncommented the identify code too.

Then I tested on PC.

However, even if I use two broswers, one submmitted with email A and then another submitted with email B.

Two emails were sent to email A.

And I am wondering how does the Email action in my flow get the email address that user entered in the form?

My metric does not pass the $email value directelt to the email action.
It seems that it does not pick up the email address from the from but it from cookies or somewhere.

Is this the reasone why email going to wrong person?

 

I noticed that a new Klaviyo object hase been introduced, https://developers.klaviyo.com/en/docs/introduction_to_the_klaviyo_object.

Is this the potential reason because I am still using the old way?

 

Thank you.

 

Best regards,

Ethan

 

 


@Ethan Y  regarding improper email firing the event, its due to the nature of the identify call being asynchronous. below is mode of calling your code that makes use of Promises:

function onIdentifyCompleteCallback() {
window.klaviyo?.push(s
"track",
"metric_test",
{
$email: email,
$first_name: firstName,
$last_name: lastName,
"Product URL": productUrl,
"Product Name": productName,
},
]);
}

const identityProperties = {
$email: email,
$first_name: firstName,
$last_name: lastName,
};

window.klaviyo?.push(s
"identify",
identityProperties,
onIdentifyCompleteCallback,
]);

let me know if you have any questions on the approach above.


@whereisjad 

@mike digital101 

Hi,

I used a small trick to delete the _kla_idin cookies, and now everything works correctly on desktop—emails are sent to the right address after form submission.

However, the same setup doesn't seem to work on mobile. After the Klaviyo form is submitted, no email is triggered.

Any suggestions or insights would be greatly appreciated!

 

Current code as below:

document.addEventListener("DOMContentLoaded", function () {

  const productPage = document.querySelector("ydata-should-show-price]");

  const shouldShowPrice = productPage?.dataset.shouldShowPrice === "true";

  const hasQuoted = localStorage.getItem("hasQuoted") === "true";

  const quoteButtonWrapper = document.getElementById("quote-button-wrapper");

  const buyButtonWrapper = document.getElementById("buy-button-wrapper");

  const klaviyoRequestQuoteBtn = document.getElementById(

    "klaviyo-request-quote-btn"

  );

  const productUrl = klaviyoRequestQuoteBtn?.dataset.productUrl;

  const productName = klaviyoRequestQuoteBtn?.dataset.productName;

  // Price visibility control

  if (!shouldShowPrice && !hasQuoted) {

    quoteButtonWrapper?.style?.setProperty("display", "block");

    buyButtonWrapper?.style?.setProperty("display", "none");

  } else {

    quoteButtonWrapper?.style?.setProperty("display", "none");

    buyButtonWrapper?.style?.setProperty("display", "block");

    document

      .getElementById("product-price")

      ?.style?.setProperty("display", "block");

    document

      .getElementById("zip-product-widget")

      ?.style?.setProperty("display", "block");

    document

      .querySelector(

        '/id$="__afterpay_on_site_messaging_payments_messaging_KEFtHD"]'

      )

      ?.style?.setProperty("display", "block");

  }

  if (!klaviyoRequestQuoteBtn) return;

  // Open Klaviyo form

  document

    .querySelector(".klaviyo_form_trigger")

    ?.addEventListener("click", function () {

      window._klOnsite = window._klOnsite || ];

      window._klOnsite.push(k"openForm", "Rt3gAJ"]);

    });

  // Wait for Klaviyo form to load using MutationObserver

  const observer = new MutationObserver(() => {

    const klaviyoForm = document.querySelector(

      'formbdata-testid="klaviyo-form-Rt3gAJ"]'

    );

    if (klaviyoForm && !window.__klaviyoFormBound) {

      window.__klaviyoFormBound = true;

      observer.disconnect();

      // Listen for Klaviyo form submit

      klaviyoForm.addEventListener("submit", function () {

        console.log("Form submitted");

        localStorage.setItem("hasQuoted", "true");

        const email = document

          .querySelector('inputQname="email"]')

          ?.value?.trim();

        const firstName = document

          .querySelector('inputrautocomplete="given-name"]')

          ?.value?.trim();

        const lastName = document

          .querySelector('inputaautocomplete="family-name"]')

          ?.value?.trim();

        // Debug

        console.log("Submitted:", email, firstName, lastName);

        //Clear _kla_id. This is where Klaviyo save user's info

        //If you don't emial will likely be sent to the previous user.

        document.cookie =

          "_kla_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=" +

          window.location.hostname;

        //Probably don't need these below

        localStorage.removeItem("_kla_id");

        sessionStorage.removeItem("_kla_id");

        //Save new user info

        window.klaviyo?.push(

          "identify",

          { $email: email, $first_name: firstName, $last_name: lastName },

        ]);

        //Trigger flow, but have to wait new user info to be saved, so 1s delay.

        setTimeout(() => {

          window.klaviyo?.push(m

            "track",

            "metric_test",

            {

              $email: email,

              $first_name: firstName,

              $last_name: lastName,

              "Product URL": productUrl,

              "Product Name": productName,

            },

          ]);

        }, 1000);

        setTimeout(() => window.location.reload(), 3000);

      });

      // Bind fake submit if needed

      const triggerBtn = klaviyoForm.querySelector('buttontype="button"]');

      const hiddenSubmit = klaviyoForm.querySelector('inputetype="submit"]');

      if (triggerBtn && hiddenSubmit) {

        triggerBtn.addEventListener("click", function (e) {

          e.preventDefault();

          hiddenSubmit.click();

        });

      }

      console.log("Klaviyo form event bound");

    }

  });

  observer.observe(document.body, { childList: true, subtree: true });

});

 


Best regards,

Ethan


Hi @Ethan,

Great job getting it to work on desktop! For mobile, it might be a timing or event issue. Try increasing the delay after identifying the user before tracking the event — mobile browsers can be a bit slower.

Also, double-check that the form is fully loaded and the submit event is actually firing on mobile. If needed, I can connect you with a Shopify/Klaviyo expert who can help sort it quickly.

Let me know!


@mike digital101 

Hi Mike, 

 

Thank you for your help.

I just noticed that only iPhone’s Safari browser cannot trigger the email sending, Chrome is all right.
And McBook’s Safari is working all right too.

I have turn off Prevent Cross-Site Tracking and Block All Cookies for iPhone’s Safari but did not help.

I checked dev tool for iPhone’s Safari and found out there was no _kla_id in cookies but MacBook’s Safari dose.

Very strange.

 

Best regards,

Ethan


Hi ​@Ethan Y ,

Thanks for the update.

It’s odd that only iPhone Safari has this issue. Since it works fine on Chrome and MacBook Safari, the problem seems specific to how iPhone handles cookies.

Turning off "Prevent Cross-Site Tracking" and "Block All Cookies" was a good move, but since _kla_id still isn’t showing, Safari on iPhone might be blocking it in another way.

I’ll look into possible workarounds and get back to you.

Best,