---
title: "How to catch duplicate orders before the shipping label is printed"
description: "A duplicate order is the same customer placing the same order twice, usually minutes apart. We catch duplicate orders by running the duplicate decision inside the step that creates the shipping label, matching on the normalised phone number, and cancelling automatically only pairs that are strictly identical; everything else goes to a person. Our first detector decided correctly but too late, and most of what we know came from the cases it got wrong."
date: 2026-10-11
lang: en
canonical: https://goingstellar.ro/methods/catch-duplicate-orders-before-the-label/
author: Going Stellar
publisher: GOING STELLAR S.R.L.
topic: E-commerce / Duplicate orders
license: CC BY 4.0
alternate_ro: https://goingstellar.ro/ro/metode/comenzi-duble-prinse-inainte-de-eticheta/
---

# How to catch duplicate orders before the shipping label is printed

*A duplicate order is the same customer placing the same order twice, usually minutes apart. We catch duplicate orders by running the duplicate decision inside the step that creates the shipping label, matching on the normalised phone number, and cancelling automatically only pairs that are strictly identical; everything else goes to a person. Our first detector decided correctly but too late, and most of what we know came from the cases it got wrong.*

> E-commerce · Duplicate orders · 2026-10-11 · https://goingstellar.ro/methods/catch-duplicate-orders-before-the-label/

## Key points

- Duplicate orders must be decided inside the step that creates the shipping label; a correct decision taken after the label exists cannot stop the second parcel.
- Match duplicate orders on the phone number's last digits, the set of SKUs and the total, because emails and names vary and cash-on-delivery forms create a new customer record per order.
- Cancel a duplicate automatically only when products and total are both identical; a different basket or value can be a real second purchase and belongs to a person.
- A duplicate check that fails should let the order ship, because a good order blocked by a bug costs more than one duplicate that escapes.
- Orders created by customer service, repurchases, reshipments and labels split between warehouse locations look like duplicates and must be exempt.

## What a duplicate order is and when to catch it

A duplicate order is the same customer placing the same order twice, usually minutes apart: a double tap on checkout, a second submission of a cash-on-delivery form, or the same click on two stores that share a catalogue and the same ads. You catch duplicate orders by running the duplicate decision inside the step that creates the shipping label, before the label exists, and by cancelling automatically only the pairs that are strictly identical. Every other suspicious pair goes to a person.

The timing matters because a shipped duplicate costs transport in both directions and, on cash on delivery, an almost certain refusal: the customer will not pay twice. Once a parcel has left, no safe rule can cancel it.

Our first duplicate detector made correct decisions too late. Measured over **24** hours, of **52** orders it had decided to cancel, **23** were cancelled and **29** already had a label, because the automatic label loop ran in the gap between the decision and the cancellation. That was roughly **29** double parcels a day.

## Step 1: match duplicate orders on the phone number, not on the customer record

The duplicate fingerprint we use is: the phone number reduced to its last **9** digits, the **set** of SKUs (so the order of the lines does not matter), and the same total in the same currency, inside a time window measured from the first order, not from the current time. A window measured from "now" misses exactly the common case, where the second order arrives after the first.

Matching on the customer record is not enough. Customers mistype their email, spell their name differently, and cash-on-delivery forms create a new customer record for every order. A set of **13** duplicate pairs that had all shipped twice had one thing in common: the same phone number. Matching on the phone caught all **13**, and it flags about 1.4% of orders.

For the human review list we rank pairs by confidence. **Exact**: identical lines, SKU by quantity, almost certainly an accidental double order. **Probable**: the same total within **2** hours. **Possible**: within **24** hours but with different products or totals, which is often a customer who came back to buy something else.

## Step 2: cancel only strict duplicates and hold everything else

The automatic cancellation rule is narrow on purpose: a duplicate order is cancelled only if it has the same SKU set *and* the same total and currency as the order being kept. Anything else is put on hold for customer service. A different basket or a different value can be a real second purchase, and an automatic cancellation of a real order is a lost sale. The case that forced the rule was two orders with the same total and different products, which the old logic would have cancelled. On **16** real pairs the strict rule gave **9** cancellations and **7** holds.

**Missing data is not identity.** If the line items of one order have not synchronised yet, the comparison returns "not comparable" and the pair is held, never declared identical. When our local records lagged, we added a fallback that reads both orders straight from the store platform, which has them immediately, and applies the same strict rule.

**Which order to keep.** Our ranking is: paid by card, then already shipped, then the newest. An order paid by card is never cancelled automatically, because that risks a double charge and a chargeback. Later the rule gained one more step: at equal quantities the lower total wins, because when the products are identical the difference between two totals is the shipping fee. In the real case that prompted the change, customer service had decided the other way after talking to the customer. A business rule in code is a snapshot of a decision, so check it with the person who owns it.

## Step 3: put the duplicate decision before the label, in one place

The fix for "correct but too late" was a function that returns the duplicate decision for one order, called by the label step *before* it creates a label. If the decision is cancel or hold, no label is made. The cancellation itself stays with the detector, so there is one rule, not two copies that drift apart.

**Fail open.** If the duplicate check throws an error, the order ships. A good order left unshipped because of a bug in a check costs more than one duplicate that escapes. Before switching it on, we simulated the check on **183** orders waiting for a label: **0** were blocked wrongly.

**Guard the same run.** Our records are a mirror that lags behind, so two duplicate orders processed in the same pass could not see each other. We counted 1.4 pairs with labels on both orders in **21** days, almost all with consecutive order numbers. The label job now keeps an in-memory set of fingerprints it has already labelled in the current run and holds any order whose fingerprint is already there.

**Look across stores.** Stores that share a catalogue and run the same ads get the same customer ordering twice on two sites. Over **7** days we found **324** cross-store pairs with the same phone within **24** hours, of which **24** had exactly the same SKUs and total. A simulation on **411** orders and 1.4 phone numbers gave **1** cancellation and **23** cases for a person, all with a correct reason and no false positives. The duplicate decision also has to come before any address correction: we once asked for an address fix on an order that was itself a duplicate.

## Orders that look like duplicates and are not

**Replacements placed by customer service.** An order created from a draft, for a swap or a resend, looks like a perfect duplicate: same customer, same products, same total. The order's source field tells them apart. Our protections for these orders lived on one of two code paths, and a single settings toggle would have routed orders around them. The guard now runs before any action and fails closed: if the platform does not answer, the order is not touched.

**Repurchases.** If the first order was delivered before the second was placed, the second is a new purchase and is kept.

**Two labels in the same second.** One order should leave with one label carrying several numbered parcels, but two labels can be a legitimate split between warehouse locations. We once cancelled one half of such a split and the goods from the second location stayed behind. Check which products each label covers before calling it a duplicate.

**Reshipments.** We cancelled **47** labels believing they were duplicates because the orders already had a delivered label. They were reshipments of incomplete parcels: one order had **7** items and the delivered parcel held one. Compare at line-item level, not by "a label already exists".

**Cancellation requests.** A customer can request cancellation without the order being cancelled. When we lifted holds in bulk to ship **16** orders, one of them shipped although the customer had asked to cancel it days earlier; we had no check for that request at the time. Before lifting a hold, read who placed it and why.

## Where we were wrong

**Two jobs with opposite rules.** One job kept the older order with a label and ran every **3** minutes; another kept the newest and ran every **15**. We retired the first and moved the whole decision into the job that creates labels.

**A decision that did nothing.** The detector recorded "would cancel" and only logged it. Our fix had two bugs of its own: the platform's list of cancellation reasons has no "duplicate" value, and the decision was written with a hyphen while we compared it with an underscore. A run with a clean build detected **5** duplicates and cancelled **0**. We caught both by checking the effect in the store, not the build.

**Mismatched windows.** The customer lookup searched **7** days while the job scanned **30**, so older duplicates came back "unknown" and stayed blocked for good: **25** of **27** orders on one market.

**Removing a tag triggers nothing.** Removing a "duplicate" tag does not re-run the automation that makes labels, so the kept order has to get its label directly from the job.

**A checker greedier than the rule.** Our parity check reported **12**% duplicates because it counted the same phone and SKUs at any time in the interval, which includes loyal customers who reorder. Narrowed to the rule's real window, it stopped raising false alarms.

## Limits of the method

The duplicate rule cannot tell a discount code from a shipping fee: if two identical baskets differ in total because of a code, the lower total still wins. Failing open lets a few duplicates through by design. A cancellation request in the order timeline is a separate signal that this method does not read.

## Checklist

**1. Decide before the label.** Call the duplicate decision from the step that creates the label, and keep the cancellation in one place.

**2. Match on the phone.** Last digits of the phone, SKU set, total and currency, window measured from the order.

**3. Cancel only exact pairs.** Hold everything else, and treat missing data as "not comparable".

**4. Protect the right orders.** Card-paid, already shipped, customer-service replacements, repurchases, reshipments and location splits.

**5. Verify the effect.** Count cancellations in the store after a run, not decisions in the log.

## Questions and answers

### How do I detect duplicate orders in an online store?

Group orders by the phone number reduced to its last digits, compare the set of SKUs and the total, and look within a time window measured from the first order. Emails and names are unreliable because customers mistype them and cash-on-delivery forms create a new customer per order. Rank pairs as exact, probable or possible, and run the check before the shipping label is created so a duplicate can still be stopped.

### Should duplicate orders be cancelled automatically?

Only strict duplicates: the same set of products and the same total and currency as the order you keep. Anything else, including the same total with different products, should be held for customer service, because it may be a real second purchase. Never cancel an order paid by card automatically, since that risks a double charge, and treat missing line-item data as not comparable rather than identical.

### Which of two duplicate orders should I keep?

We keep the order paid by card first, then the one already shipped, then the newest. When the products and quantities are identical, the order with the lower total wins, because the difference is usually the shipping fee. That last rule cannot tell a discount code from a shipping fee, and customer service may decide differently after speaking to the customer.

### Why do duplicate orders still ship when the detector finds them?

Usually because the decision runs after the label is created. In our case the automatic label loop ran between the detector's decision and the cancellation, so most identified duplicates already had a label and were then correctly protected as shipped. Moving the decision into the label step, and guarding orders processed in the same run, closed the gap.

### Which orders look like duplicates but are not?

Replacement orders created by customer service from a draft, repurchases where the first order was delivered before the second was placed, reshipments of incomplete parcels, and two labels that split one order between warehouse locations. Each looks like a duplicate on customer and products alone. Check the order source, delivery dates and the items each label covers before cancelling anything.

## How to cite

**Cite this as:** Going Stellar (2026). *How to catch duplicate orders before the shipping label is printed*. GOING STELLAR S.R.L.. https://goingstellar.ro/methods/catch-duplicate-orders-before-the-label/

```bibtex
@misc{goingstellar2026catch,
  title  = {How to catch duplicate orders before the shipping label is printed},
  author = {{Going Stellar}},
  year   = {2026},
  url    = {https://goingstellar.ro/methods/catch-duplicate-orders-before-the-label/},
  note   = {2026-10-11}
}
```

Licence. Free to quote with attribution.

## Also available

- This page as HTML: https://goingstellar.ro/methods/catch-duplicate-orders-before-the-label/
- Same article in Romanian: https://goingstellar.ro/ro/metode/comenzi-duble-prinse-inainte-de-eticheta/
