It is Friday night and the drop is live. Order #4381 arrives at 9:14: two candles, one wax warmer, $64, shipping to an address on Maple Street. At 9:18, order #4382: two candles, one wax warmer, $64, Maple Street. Same customer, same card, both paid. Nobody wants two of this box. What happened in those four minutes is the oldest small accident in ecommerce: a checkout that felt slow, a pay button that got pressed twice, or a card error screen that convinced the customer their first try had failed when it had actually captured. The customer thinks they bought one. Your admin says they bought two. And nothing anywhere in Shopify is going to mention that the two orders are the same one.
The forums have been asking for exactly this catch for years, in wording so specific it reads like a product spec. "How to automatically cancel duplicate orders with same SKU within 24 hours?" sits on the Shopify Flow board, politely unanswered in the way that means the tool cannot do it. Other threads report customers charged twice after a payment retry, orders doubling out of a glitchy checkout, and one long thread of merchants whose customers received their order twice, with the merchants eating the second box. The stories differ in cause and agree in shape: two records, one intention, and a platform that treats them as strangers.
What Shopify actually does, and where it stops
Start with detection, because there is none. The orders screen lists #4381 and #4382 the way it lists any two orders. No badge, no warning, no possible duplicate flag, nothing that compares an incoming order to the ones the same customer placed minutes earlier. Shopify's risk analysis looks at each order alone and asks whether the payment looks stolen, which is the question behind the high-risk flag, and a duplicate fails that test perfectly: it is the same legitimate customer using the same legitimate card, so both copies come back low risk. The one system watching every order is structurally unable to notice the only thing wrong with this one.
Then the cleanup, which is worse than it sounds. Orders cannot be deleted in Shopify, only canceled, so the accident lives in your reports either way. Canceling means refunding, and payment processing fees are generally not returned on refunds, so the cleanest possible outcome of a duplicate still costs you the fees on a sale that never existed. That is the same quiet tax that makes the Flow blocklist workaround expensive: react after capture and the toll is already paid. And the cleanup only happens if someone notices. If nobody does, the warehouse or the 3PL pulls both orders in its next sweep, two labels print, two boxes ship, and you are now paying return shipping on your own mistake or writing off the merchandise entirely.
The natural move is to automate the catch with Shopify Flow, and this is where the gap turns structural. Flow's Order created trigger hands the workflow exactly one order, and every condition it can evaluate reads from that order alone. There is no condition that looks sideways at the customer's other recent orders and compares line items, which is precisely the comparison a duplicate check is. You can read the customer's order count and learn this is their second order today, but a count cannot tell a duplicate from a customer who came back for more. The community thread asking for same SKU within 24 hours is asking Flow to hold two orders side by side, and Flow has one hand. So merchants bolt on tag gymnastics and scheduled exports, and the honest answer stays what it has been for years: the comparison happens in a human's head or it does not happen.
Shopify keeps a perfect record of both orders. It just has no idea they are the same one.
There is one more way to lose, and it is the expensive one. The customer finds the double charge before you do, on a banking app notification or a statement, from a store that has said nothing. Some write in, and that email lands in the same queue as everything else. Some do not write in. They tap dispute instead, and the duplicate you would have refunded with an apology becomes a chargeback carrying its own fee and a strike against your store's record, over an accident a computer could have caught in four seconds.
Why doing it by hand never keeps up
The manual catch is a morning ritual: scan the overnight orders, watch for a name that appears twice, check whether the carts match. It works on the days it works. But fulfillment is a race you have chosen to run slowly. A 3PL pulls new orders on a schedule measured in minutes, and a duplicate placed at 9:18 on Friday night is picked, packed, and labeled long before Monday's scan, the same race that order edits lose for the same reason. Volume breaks the scan the rest of the way: on a launch weekend, two hundred orders scroll past, and the pair four minutes apart with the same last name is exactly the detail a tired eye skips. The duplicates you catch are the ones that happened to arrive slowly, which is to say the misses are invisible until the support ticket arrives, angry, three weeks later.
And the scan has a false-positive problem that costs real sales. Not every repeated order is a mistake. A customer reorders the same serum the day it runs out. A gift buyer sends the same box to the same address twice on purpose. A customer places a second order twenty minutes after the first because they forgot an item, and that person wants both orders, ideally combined into one shipment rather than either canceled. Cancel a deliberate order on a hunch and you have refunded revenue, confused a customer mid-experience, and taught your team to distrust the process. The manual scan swings between missing true duplicates at speed and executing false ones at leisure.
What the automation actually has to do
A duplicate catch that works is not a rule about SKUs and hours. It is a look-back, a comparison, a judgement, and a race: on every new order, pull the same customer's recent orders and hold them side by side; compare the whole order, not one field; decide misfire or intention from the pattern; act inside the window where cancellation is clean; and say something to the customer before their bank does. As a Dugong playbook, in plain prose, it reads like this:
# trigger
On every new order
# steps
1. Look back at the same customer's orders from
the last day and put them side by side
2. Compare whole orders: items, quantities, totals,
ship-to, payment, and the minutes between them
3. Judge duplicate or deliberate: an identical cart
minutes later is a misfire, the same product next
week is a fan
4. Cancel the unfulfilled copy before the label
prints, refund it, restock, file the reason
5. Tell the customer plainly, before the double
charge finds them on a statement
6. Hold the close call: pause fulfillment briefly
and ask, instead of guessing
Six lines, and the compiler fills in the judgement they imply. Reading a payment retry for what it is, two capture attempts wrapped around one error screen, which is near-certain duplicate territory. Choosing which copy to cancel: the unfulfilled one, and when both are unfulfilled, the later one, so the customer's confirmation email stays true. Beating the warehouse to the label, and when the copy has already been picked, flagging it for intercept instead of pretending. Tagging the canceled copy and the survivor so support sees the whole story before answering the confused email. Writing the note that turns the accident into a good story: you appear to have been charged twice, we canceled the extra order, your refund is on its way, your real order ships tomorrow. And noticing the meta-pattern a human would miss, because three duplicates in one week is not three clumsy customers, it is a checkout bug wearing customer clothing, and the playbook should say so.
Why this is a compiler problem, not an app problem
The mechanical part of this, canceling and refunding an order, is one API call, and it was never the hard part. The hard part is the decision attached to the call: are these two orders one intention or two; which copy dies and which survives; is this cancellation safe to make silently or does it need a human glance first; and what does the customer hear, in what tone, how fast. Those calls shift with every pair of orders, and the cost of getting one wrong is asymmetric in both directions. Miss a duplicate and you pay double shipping, lost fees, and maybe a chargeback. Cancel a deliberate order and you have unsold a sale and rattled a customer who did nothing strange. A fixed rule holds neither risk well, which is why this catch has stayed manual at stores that automate nearly everything else.
It also sits in a web this desk keeps mapping. Its nearest neighbor is the second order that arrives before the first ships, the mirror-image case where both orders are wanted and the right move is merging boxes instead of canceling one. The identity questions underneath are the same ones that power merging the customer Shopify counts three times. The race against the warehouse is the race from order edits, the stakes on a miss belong to the chargeback desk and the returns desk, and the housekeeping cousin is the unpaid order that never cancels itself, another cleanup Shopify leaves to whoever notices.
Picture a skincare store on serum restock day. A customer's banking app times out at checkout, she gets an error, tries again, and both attempts captured. Orders #2214 and #2215 land eight minutes apart, identical to the cent. Without the playbook, the 3PL pulls both at its next sync and the discovery happens on her statement, followed by an email with a screenshot, or a dispute without one. With the playbook running, #2215 is flagged at creation: same cart, same address, same card, eight minutes, an error in the payment log between them. The copy cancels unfulfilled, stock returns to the shelf on restock day when it matters most, the refund issues, and she gets a two-line note before her bank says anything. She replies with a thank-you. The merchant reads the whole exchange in a morning summary, one line long.
The workflow worth building this week
If your traffic is mobile, your checkout ever runs slow, or your payment provider ever shows an error it later regrets, duplicates are already happening to you at some rate, and every one is quietly expensive: fees you do not get back, boxes shipped twice, support threads that start with charged twice, and the occasional dispute from a customer who never wrote in. The catch pairs naturally with the order-combining playbook, since they are two verdicts from the same look-back, and it feeds the same flywheel as the Shopify automations no one builds, where the compounding win is the accident that stops reaching the customer at all.
Describe it the way you would brief a careful assistant: every time an order comes in, glance at what this customer ordered in the last day; if you find the same cart placed minutes apart, cancel the extra one before the warehouse touches it, put the stock back, refund it, and send a plain note explaining what happened; if the orders rhyme but do not match, hold the new one briefly and ask; and if duplicates start arriving in bunches, tell me, because that is a bug, not a customer. That is the whole brief. The compiler does the look-back, the comparison, the timing, and the tone. Your customer finds out they were charged twice from you, with the refund already moving, which is the only version of this story that ends with a thank-you.
If you are a Shopify merchant with a duplicate-order story, a checkout
bug that manufactured them for a week, or a double charge that turned
into a chargeback, the inbox is open:
field-notes@dugong.live. We are collecting case studies
for the next issue.