Skip to content

About

Magento 2 EU right-of-withdrawal button (Directive (EU) 2023/2673, mandatory 19 June 2026) for customers and guests — with partial withdrawals, double opt-in, PDF cancellation form, admin workflow, auto-refund, GraphQL/REST APIs Hyvä and MageSuite support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

Magento 2 Withdrawal Module Comparison

TL;DR: This page compares free open-source modules with CopeX_OrderWithdrawal for the EU right of withdrawal button mandated by Directive (EU) 2023/2673, effective in every EU online shop from 19 June 2026. Goal: a technically honest decision aid for shop owners and developers — not a pure marketing brochure.

DE: A German version of this document is available at README_DE.md.


Contents


Why this comparison?

EU Directive 2023/2673 (modernisation of consumer rights) obliges every online shop selling to EU consumers to expose a clearly identifiable withdrawal button from 19 June 2026 onward. Shops without a compliant solution by then risk cease-and-desist letters (Abmahnung in the German market) — and competing legal firms are watching.

For Magento 2 there are roughly three paths:

  1. Free open-source modules (OSL-3.0, MIT, AFL) — typically maintained by individual developers or small teams. They cover the baseline.
  2. In-house build — high effort, full responsibility on you.
  3. copex/module-order-withdrawal — the module from CopeX GmbH, focused on security, compliance depth, refund automation, and business intelligence.

Modules at a glance

Typical free module copex/module-order-withdrawal
License OSL-3.0 / AFL / MIT (open source) Source code included & fully viewable
Magento compatibility Variable 2.4.6+
Minimum PHP version Variable 8.3
Hyvä theme support Usually a separate Composer package Built into the same package (layout switch)
Automated tests Rarely present 50+ unit tests + Playwright E2E
Static analysis No phpinsights
Roadmap transparency Variable Versioned + documented

Methodology note: The "typical free module" column reflects the picture you find today (May 2026) when inspecting the source code of the most popular open-source Magento 2 withdrawal modules. Individual modules may cover individual points better; the overall pattern is consistent.


Full feature matrix

Legend: ✅ present · ⚠ partial/limited · ❌ not present · 🛠 in development

1. Customer-facing flows

Feature Free CopeX
Withdrawal button in order history ✅ ✅
Detail page with order data ✅ ✅
Confirmation dialog before submit ⚠ JS confirm() ✅ Modal (Luma & Hyvä Alpine)
Success page after submit ✅ ✅
Public form for guest orders ✅ (usually search-by-email) ✅ (with double opt-in)
Partial (item-level) withdrawal ⚠ Some ✅ Checkbox + qty with already-withdrawn lock
Multiple partial submissions per order ⚠ Some ✅
Withdrawal reason selection ❌ ✅ Per-storeview configurable
Comment field ❌ ✅
PDF model withdrawal form ❌ ✅ Pre-filled with order data
Configurable disclaimer text ❌ ✅

2. Security & privacy

Feature Free CopeX
Double opt-in via tokenised email ❌ ✅ Configurable
Server-side reCAPTCHA enforcement ❌ ✅ Predispatch observer
CSRF protection (form key) ✅ ✅
Customer email as URL query parameter ⚠ Common (GDPR risk) ❌ Not in URLs
Token values in REST API responses n/a ❌ Deliberately excluded
Configurable token expiry n/a ✅
Cron cleanup of orphaned tokens n/a ✅ Daily at 02:00
IDOR protection on order_id ⚠ Usually only email-match ✅ Customer-ID match

3. Compliance & legal safety

Feature Free CopeX
Period counted from last shipment date ✅ ✅
Always-allow for unshipped orders ✅ ✅
Expected-shipping-days buffer ❌ ✅ Configurable
Grace period with needs_validation status ❌ Hard "expired" ✅ Configurable
Configurable allowed order statuses ⚠ Some ✅
Mandatory acknowledgement-of-receipt email to customer ✅ ✅
Reason code with label snapshot ❌ ✅ Audit-safe
Order-history comment on submit ✅ ✅
Order-history comment on confirm n/a ✅

4. Admin functionality

Feature Free CopeX
Admin grid under Sales > Withdrawals ✅ ✅
Inline status edit ⚠ Detail page only ✅
Detail page with full metadata ⚠ Variable ✅
Filter: ID, order #, status, date ✅ ✅
Filter: withdrawal reason ❌ ✅
Filter: type (Full/Partial) ⚠ When partial exists ✅
Filter: linked order status ❌ ✅
Bulk actions (mass approve/decline) ⚠ Some ✅
Row action "Approve" / "Decline" ⚠ Some ✅ Context-sensitive
Autocomplete for unresolved orders ❌ ✅
Auto-refund (create credit memo) ❌ ✅ Full & partial
ACL-gated backend permissions ✅ ✅

5. API & integration

Feature Free CopeX
REST API – list withdrawals ⚠ GET only ✅
REST API – CRUD ❌ ✅ Full CRUD (5 endpoints)
REST API – items endpoint (partial) ❌ ✅
GraphQL schema + resolvers ❌ ✅ Query + mutation
ACL-gated API ✅ ✅

You can build webhook / ERP integrations on top of REST or GraphQL yourself. A dedicated webhook subsystem inside the module would be redundant surface area.

6. Technical quality

Feature Free CopeX
Minimum PHP version Variable 8.3
Minimum Magento version Variable 2.4.6
declare(strict_types=1); ⚠ Partial ✅ Consistent
Service-oriented architecture ⚠ Logic often in controllers ✅ Clear separation
Repository pattern ⚠ Mixed ✅ Complete
Unit tests Rare ✅ 50+ tests
Playwright E2E ❌ ✅ Including Mailpit verification
Static analysis ❌ ✅ phpinsights

7. Hyvä theme integration

Feature Free CopeX
Hyvä-compatible ⚠ Separate package needed ✅ Same package
Tailwind templates ⚠ Only with compat package ✅
Alpine.js components ⚠ Only with compat package ✅
Mechanism Composer sub-package hyva_default layout handle
CSP compatibility (PCI-DSS 4.0) ⚠ Not documented ✅ CSP-safe by default

Security analysis: double opt-in vs. direct submit

This is by far the most important security differentiator between our module and many free implementations.

The typical free-module pattern: direct submit after email match

Many open-source modules implement the guest-withdrawal flow by simply looking up order number + email in the order repository and, on a match, redirecting the visitor straight to the submit view — with the email address passed in the URL query string.

The problem: Order numbers are sequential (100000001, 100000002, ...). Email addresses appear on every invoice, every delivery note, every order confirmation email. Anyone who gets hold of that data — through a leak, a database dump, a shared invoice, a phishing attack, or a disgruntled ex-employee — can submit withdrawals for someone else's orders without any further verification.

There is no reCAPTCHA, no token, no identity check.

CopeX: double opt-in via tokenised link

In default mode CopeX requires a two-step verification:

  1. Customer submits order number + email + reCAPTCHA
  2. CopeX creates a record with status awaiting_confirmation and a 64-character token
  3. Customer receives an email with a confirmation link
  4. Only after clicking → status pending → final processing

Result: Only someone who controls the customer's email inbox can complete the withdrawal. Database leaks and invoice access are not sufficient.

Additionally: reCAPTCHA is enforced server-side in a predispatch observer — a client-side bypass via bot scripts is not possible.

Optionality: If you don't want the double-opt-in friction (e.g. because reCAPTCHA + IP rate-limiting are enough), you can disable it via copex_orderwithdrawal/general/require_email_confirmation = 0. Default remains enabled.

Concrete scenario

A disgruntled ex-employee of a mid-sized B2C shop still has access to an old DB export from their time there. With 50,000 order records, they set up a script that submits a withdrawal per order.

  • With a direct-submit module: 50,000 valid withdrawal requests land in the admin grid. The shop has to verify and reject each one — effort: 5-10 min per record, so 4,000-8,000 hours of admin work. Meanwhile real withdrawals pile up in the same inbox = get overlooked = legal risk.
  • With CopeX (double opt-in enabled): 50,000 emails go out to the real customers. Since the script doesn't have access to their inboxes, nobody clicks the link. Zero filed withdrawals. The cron cleans up after 24 h.

GDPR / privacy: where does the customer's email end up?

A subtle but GDPR-relevant detail in many free implementations.

Typical free-module pattern

The guest-view URL carries the email address directly in the query string, e.g. /withdrawal/guest/view?order_id=12345&email=max.mustermann@example.com. This means:

Location Email stored
Browser history ✅ In plaintext
Browser bookmarks ✅ In plaintext
Apache/Nginx access logs ✅ In plaintext
Referer headers (on click to external links) ✅ In plaintext
Reverse proxies (Cloudflare, Varnish) ✅ In plaintext
CDN logs ✅ In plaintext
Browser extensions ✅ In plaintext

A personally identifying information item (email = personal data per GDPR Art. 4(1)) thus ends up in at least 5-7 locations outside the shop's control. In case of a data breach (log leak, Cloudflare misconfiguration) this is reportable under GDPR Art. 33.

CopeX

Emails only ever live in the POST body and in the copex_orderwithdrawal table. URLs only contain:

  • Unguessable 64-character tokens (/withdrawal/request/confirm?token=Ab7…)
  • Numeric order IDs (only for logged-in customers, with an IDOR guard)

No personal data in the URL path or query string.


Code quality & update safety

Test coverage

In most free Magento 2 withdrawal modules the test suite is empty or absent. CopeX ships 50+ PHPUnit unit tests plus a Playwright E2E suite covering the guest public form, registered order history, partial withdrawal, and the PDF cancellation form.

Practical meaning: On every Magento update (typically 2-4 per year), with a free module you have to manually test whether everything still works. With CopeX you run the test suite and it tells you immediately if something broke.


Legal basis: what does the EU require?

So you understand what your module actually has to cover.

Directive 2011/83/EU (current law)

  • Art. 9: 14-day withdrawal period from receipt of goods
  • Art. 11: Withdrawal declaration "on a durable medium" — i.e. an email acknowledgement of receipt is legally mandatory
  • Annex I (A): model withdrawal instructions
  • Annex I (B): model withdrawal form — must be offered as an alternative form

→ Most modules implement the period (Art. 9) and the acknowledgement (Art. 11). The Annex I (B) PDF download is delivered by very few — CopeX does.

Directive (EU) 2023/2673 (NEW, effective 19 June 2026)

  • Art. 11a (new): "A clearly identifiable withdrawal button" in the trader's online interface
  • Art. 11a(3): The button may not impose preconditions beyond those required to identify the customer
  • Art. 11a(4): Immediate confirmation of withdrawal receipt on a durable medium

→ "Reason as a mandatory field" would be unlawful (it violates 11a(3)). For that reason, CopeX makes the reason field optional only, never required.

Practical implications for shop operators

What you need by 19 June 2026:

  1. ✅ Withdrawal button (every serious module delivers this)
  2. ✅ Period calculation from last shipment (most modules)
  3. ⚠ Optional identity-verification step (Free: usually no real verification, CopeX: double opt-in)
  4. ✅ Acknowledgement-of-receipt email to customer (most modules)
  5. ⚠ Model withdrawal form as PDF (typically only premium modules) — debated whether strictly required by 2023/2673 or whether the online form suffices. The PDF route is the only certain one.
  6. ⚠ Audit capability: who withdrew what when, and when was it verified? — fully tracked in CopeX, basic-info-only in most free modules.

Who should pick what?

Honest recommendation, against our own sales pressure:

Pick a free module if ...

  • You run a hobby/mini shop (< 50 orders per month, < 5 withdrawals per year)
  • You have strong in-house Magento 2 development that can patch and test on its own
  • You're stuck on PHP 7.4 or 8.0 and can't upgrade (legacy stack)
  • You only need the statutory minimum and don't want analytics

Pick CopeX if ...

  • You run a B2C shop with meaningful volume (> 100 orders/month)
  • You care about data protection (you have a data protection officer / are compliance-obliged)
  • You want to analyse withdrawal reasons to improve products
  • You have many orders → many potential refunds and want to save admin time
  • You want to upgrade or already run on modern PHP (8.3+)
  • You run Hyvä with PWA / headless and need GraphQL
  • You want EU 2023/2673 compliance without doing the audit yourself

FAQ

Can I see the source code? Yes. The complete source code ships with the module and is fully viewable.

Does the module work with Adobe Commerce (Magento Enterprise)? The module is built entirely on Magento Open Source APIs and therefore also runs on Adobe Commerce. It has been tested with Magento 2.4.6+ on the Luma, Hyvä and MageSuite frontends.

Which reCAPTCHA version is supported? Magento_ReCaptchaUi (v2 Invisible, v2 Checkbox, v3). Configurable per store view.

Is there a trial? Yes. A 14-day free trial is available — contact office@copex.io.


Contact / demo

CopeX GmbH Web: https://copex.io Email: office@copex.io Product page & pricing: https://copex.io/module/order-withdrawal/ — more details and current pricing Module docs: https://docs.copex.io/modules/order-withdrawal/

Disclaimer: This document is maintained by CopeX GmbH and at its core is an argument for our own product. We strive for fairness and accurate comparison. The claims about "typical" free modules describe patterns we observe when inspecting the source code of the most popular free Magento 2 withdrawal modules — individual modules may cover individual points better. Verify our claims by your own source inspection.


Search keywords

Magento 2 withdrawal · Magento 2 withdrawal button · Magento 2 EU 2023/2673 · Magento 2 right of withdrawal · Magento 2 cancellation form · Magento 2 GDPR withdrawal · Magento 2 module comparison · Magento 2 consumer rights directive · Magento 2 Hyvä withdrawal · Magento 2 PWA withdrawal GraphQL · Magento 2 partial withdrawal · Magento 2 open source withdrawal · Adobe Commerce withdrawal module · Magento Open Source withdrawal extension · Magento 2 Widerruf · Magento 2 Widerrufsbutton · Magento 2 Widerrufsformular · Magento 2 Datenschutz Widerruf · Magento 2 Verbraucherrechte · Magento 2 Teilwiderruf · Magento 2 Open Source Widerruf

About

Magento 2 EU right-of-withdrawal button (Directive (EU) 2023/2673, mandatory 19 June 2026) for customers and guests — with partial withdrawals, double opt-in, PDF cancellation form, admin workflow, auto-refund, GraphQL/REST APIs Hyvä and MageSuite support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors