Klaviyo Shows Double Conversions on Shopify: How to Find Which App Sends Twice

|Dan Giura
Klaviyo Shows Double Conversions on Shopify: How to Find Which App Sends Twice

TL;DR

Klaviyo does deduplicate events, but only inside one metric for one profile, keyed on the event ID the sender supplies [1]. Two apps sending an order event produce two separate metrics with two separate metric IDs, one carrying the Shopify logo and one carrying the gear icon [6], and a dedup key scoped to a metric cannot reach across that boundary [1]. So the first move is not to uninstall anything. The first move is to open the metrics list, count the order metrics, and find out which sender owns each one. Then decide which sender you want and turn the other one off at the source.

Key Takeaways

  • Klaviyo's dedup key is profile plus metric plus the sender's event ID; without an ID it falls back to the time to the second, which the docs describe as one event per profile per second [1].
  • Metrics written through the API are distinct from metrics written by the native Shopify integration, even when the names match exactly, which is why the counts add instead of collapsing [6].
  • In Analytics > Metrics the gear icon marks a metric written over the API and the Shopify logo marks one written by the native integration [6].
  • Four Klaviyo metric names collide by default between the native integration, Klaviyo onsite tracking, and a server-side tracking app: Placed Order, Checkout Started, Viewed Product, and Added to Cart.
  • Campaign and flow revenue does not double from this, because attributed revenue runs off the single account conversion metric with a 5-day default window for email and SMS [7]. Raw metric charts and flow triggers do double.
  • A metric can only be mapped once under Analytics > Metrics > Edit mapped metrics, so you have to pick an owner per concept rather than keeping both [4].
  • WeltPixel Conversion Tracking sends one Placed Order per order, stamped with an event ID derived from the Shopify order, so webhook retries and multiple pixel instances pointing at the same Klaviyo account collapse into a single event. Instances aimed at different Klaviyo accounts, such as one per Shopify Market, each record their own, which is the point of running them.

Why doesn't Klaviyo just deduplicate the second event?

It does deduplicate, inside a boundary that most people assume is wider than it is. Klaviyo's Create Event reference states that if a unique_id is repeated for the same profile and metric, only the first processed event is recorded, and that without one the system falls back to the time to the second, limiting you to one event per profile per second [1]. The documented dedup key names the metric, so the per-second fallback reads as per-metric too, but that last step is our reading of the sentence rather than something Klaviyo spells out. The custom-integration FAQ says the same thing from the sender's side: every event for a given profile needs a unique combination of event name and event ID, and a repeat gets accepted with a 1 response but never ingested [2].

Read that carefully and the failure mode falls out. Deduplication is scoped to a metric. Klaviyo files events written through the API as their own metrics, separate from the ones its native Shopify integration writes, which is why merchants end up looking at two rows both labelled Placed Order with two different metric IDs. The icons tell them apart: a gear for the API-written one, the Shopify logo for the integration's [6]. There is no shared identifier across those rows, nothing like the event_id that lets Meta and Snapchat collapse a browser hit and a server hit into one conversion. If you want the mechanics of that other pattern, we wrote them up in event deduplication on Shopify.

A store we worked with hit this exactly. Their email agency reported that conversions in Klaviyo had doubled, the report landed in the same week a tracking app went in, and the app was switched off for a month while everyone argued. Nobody opened the metrics list. The two rows had been sitting there the whole time.

Find the second sender in ten minutes

  1. Go to Analytics > Metrics in Klaviyo and search for the metric name that looks inflated, usually Placed Order [5].
  2. Count the rows that share the name. Two rows is your answer already. Note the icon on each: Shopify logo for the native integration, gear for anything sent over the API by a third-party app or a developer [6].
  3. Open each row and read its recent events. Compare the property sets. The native integration's Placed Order carries Shopify's order payload; an app-written one carries whatever that app decided to send, so the property lists rarely match.
  4. Compare timestamps on the same order across both rows. Server-side senders fire from the order webhook within seconds of checkout, so the two entries usually sit a few seconds apart rather than minutes.
  5. Identify the API sender by elimination. Check Settings > Apps and sales channels in Shopify admin for anything with Klaviyo credentials: a tracking app, a forms or popups app, a subscriptions app, a second store syncing into the same Klaviyo account.
  6. Check whether Klaviyo's own onsite snippet is loaded twice. Klaviyo's Shopify data reference lists Active on Site, Viewed Product, Viewed Collection, Submitted Search, and Added to Cart as onsite-tracking metrics, and gear-marks Active on Site and Viewed Product explicitly; the rest of that set follows the same pattern [3]. A second copy of klaviyo.js in the theme is worth checking here.
  7. Turn one sender off at the source, then watch the metric for 48 hours. Deleting the metric row does not stop the sender.

Step 3 is the one people skip, and it is the one that ends the argument, because two property sets that do not match cannot be the same event twice.

The four metric names that collide

Not all seven overlap. Klaviyo's native Shopify integration writes Checkout Started, Placed Order, Ordered Product, Fulfilled Order, Cancelled Order, and Refunded Order, among others, while its onsite snippet writes Active on Site, Viewed Product, Viewed Collection, Submitted Search, and Added to Cart [3]. A server-side tracking app that sends browse and order events to Klaviyo overlaps on some of those names and not others.

Metric sent by a tracking app Native Klaviyo equivalent Collides?
Placed Order Placed Order (Shopify integration) Yes
Checkout Started Checkout Started (Shopify integration) Yes
Viewed Product Viewed Product (onsite tracking) Yes
Added to Cart Added to Cart (onsite tracking) Yes
Viewed Category Viewed Collection (onsite tracking) No, different name
Product Searched Submitted Search (onsite tracking) No, different name
Viewed Page Active on Site (onsite tracking) No, different name

Four collide, three do not. The three that do not collide are the ones that quietly give you two different pictures of the same behaviour under two different names, which is its own kind of mess but not the one that makes the revenue number look wrong.

What does the doubling actually break?

Less than the panic suggests, and in stranger places. Attributed campaign and flow revenue runs off the single account conversion metric you select, with a last-touch model and a default window of 5 days for email and SMS for accounts created after October 9, 2024 [7]. One metric is selected, so attributed revenue does not double. What doubles is anything that reads the metrics directly: custom reports summing both rows, the metric charts themselves, and any analysis someone builds by hand.

The real damage is on the trigger side. A flow built on the API-written Placed Order and a second flow built on the Shopify-written Placed Order both fire for the same purchase, and the buyer gets two post-purchase emails. That is the version of this bug customers notice, and it is worth checking before you touch anything else.

There is also a mapping constraint that decides the fix for you. Under Analytics > Metrics > Edit mapped metrics, Klaviyo maps integration metrics onto seven semantic concepts including Revenue, Started checkout, Added to cart, and Viewed product, and a metric can only be mapped once [4]. There is no merge. You choose which sender owns each concept and you turn the other one off.

How is this different from retries double-counting a purchase?

Different layer entirely, and worth separating because the symptoms look alike. Retry double-counting happens when one sender delivers the same purchase more than once, usually because Shopify redelivers a webhook that timed out; we covered that mechanism and its fix in why server-side retries double-count Shopify purchases. The Klaviyo case here is two senders each delivering once, correctly, into two metrics.

The tell is the metric count. One metric row with duplicate events inside it is a retry problem, and a sender that stamps a stable event ID per order will not have it. Two metric rows is a sender problem, and no amount of idempotency inside either sender will fix it, because each one is behaving perfectly.

Deciding which sender owns each metric

Decide by what the metric has to carry rather than by which app you installed first.

The native Shopify integration is the right owner for Placed Order when your flows depend on Shopify's own order payload shape, on the fulfilment and refund metrics that come with it, or on Klaviyo's back-population of order history. It is the default for a reason and most stores should keep it.

A server-side tracking app is the right owner when you need the browse funnel to survive ad blockers and closed tabs, when you want the same event stream feeding your ad platforms and Klaviyo from one place, or when Klaviyo's onsite snippet is being blocked. WeltPixel Conversion Tracking delivers all seven of its Klaviyo metrics server-side and stands down entirely if Klaviyo's own snippet is already on the page, so it does not stack a second onsite loader on top of yours. The full picture of how that path works is in Klaviyo server-side tracking on Shopify.

Running both on purpose is defensible for exactly one reason: a transition period where you want to compare the two streams before cutting over. Give it two weeks, pick the winner, kill the loser.

FAQ

Does Klaviyo deduplicate events sent by two different apps?

Not across metrics. Deduplication is scoped to one profile and one metric, keyed on the event ID the sender supplies [1]. Because API-written metrics are separate from integration-written ones even when the names match, two senders produce two metric IDs and both sets of events are recorded.

Why do I see two Placed Order metrics in Klaviyo?

One is written by the native Shopify integration and carries the Shopify logo; the other is written over the API by an app or a custom sender and carries a gear icon [6]. Open both in Analytics > Metrics and compare their recent events to see which sender each one belongs to.

Will disabling one sender fix my historical numbers?

No. Turning off a sender stops new events from that day forward; the existing events stay in their metric. Choose the metric you want mapped under Analytics > Metrics > Edit mapped metrics [4] and treat the crossover period as a known break in the series.

Does double counting in Klaviyo inflate my flow revenue?

Usually not. Attributed revenue uses the single account conversion metric with a last-touch model and a 5-day default window for email and SMS on accounts created after October 9, 2024 [7]. Raw metric totals and duplicate flow triggers are what actually go wrong.

Can I merge two Klaviyo metrics into one?

There is no merge. A metric can only be mapped once to a given semantic concept [4], so the workable path is to pick one sender per concept, disable the other, and rebuild any flow that was triggering off the retired metric.

If you want the order side of this settled without adding a second sender to the pile, WeltPixel Conversion Tracking sends at most one server-side event per connected platform per order, and its recent-events view shows server events arriving for GA4, Meta, TikTok, and most other connected platforms, so you can see what left your store before you go looking at what Klaviyo received: install it here. Whichever sender you keep, check the metrics list first, because the two rows have usually been sitting there longer than the app everyone blamed.

Sources

  1. Klaviyo Developers, "Create Event" API reference (unique_id deduplication behaviour), developers.klaviyo.com/en/reference/create_event, accessed September 4, 2026
  2. Klaviyo Developers, "Custom integration FAQs" (event name plus event ID uniqueness per profile), developers.klaviyo.com/en/docs/custom_integration_faqs, accessed September 4, 2026
  3. Klaviyo Help Center, "Shopify data reference" (metrics synced by the Shopify integration and by onsite tracking), help.klaviyo.com/hc/en-us/articles/115005080447, accessed September 4, 2026
  4. Klaviyo Help Center, "How to use account-level mapped metrics" (Analytics > Metrics > Edit mapped metrics; a metric can only be mapped once), help.klaviyo.com/hc/en-us/articles/25829057055899, accessed September 4, 2026
  5. Klaviyo Help Center, "Troubleshooting placed order tracking" (Analytics > Metrics navigation), help.klaviyo.com/hc/en-us/articles/7000906101019, accessed September 4, 2026
  6. Klaviyo Community, "Seeing 2 different placed order data" (gear icon marks an API-written custom metric; Klaviyo employee response; supports the icon distinction only), community.klaviyo.com/accounts-and-settings-2/seeing-2-different-placed-order-data-6506, November 29, 2022
  7. Klaviyo Help Center, "Understanding message conversion tracking" (last-touch attribution; 5-day email and SMS default window for accounts created after October 9, 2024), help.klaviyo.com/hc/en-us/articles/115005248128, accessed September 4, 2026

Ready to upgrade your tracking?

Server-side tracking for Magento and Shopify — accurate data, better attribution, full privacy compliance.