Webshop Withdrawal Button: New Rule June 2026
Steven | TrustYourWebsite · 6 April 2026 · Last updated: May 2026
Directive (EU) 2023/2673, which amends the Consumer Rights Directive (2011/83/EU), introduces a new requirement for online service providers: a digital button through which consumers can exercise their right of withdrawal (herroepingsrecht). The deadline for implementation is June 19, 2026.
The Background: The Right of Withdrawal
Under Dutch consumer law (implementing the Consumer Rights Directive), consumers who purchase online have a 14-day cooling-off period during which they can withdraw from the contract without giving a reason. This applies to:
- Distance contracts (purchases made online, by phone, or by catalogue)
- Off-premises contracts
- Most B2C purchases of goods and services
For digital services and subscriptions specifically, the right of withdrawal exists for 14 days from the date the contract is concluded, unless the consumer has explicitly consented to immediate delivery and acknowledged that the right of withdrawal is lost upon commencement.
The withdrawal right does not apply to:
- Custom-made goods
- Perishable goods
- Goods that cannot be returned for hygiene reasons after opening
- Fully delivered digital content where the consumer consented to immediate delivery
- Some service contracts fully performed before the withdrawal period ends
What Regulation 2023/2673 Adds
Before this regulation, exercising the right of withdrawal typically required consumers to:
- Find the withdrawal form in the seller's terms and conditions
- Send an email or letter
- Fill out a paper withdrawal form
Many consumers did not exercise their rights because the process was deliberately or accidentally made complicated.
Regulation 2023/2673 (Article 11a of the amended Consumer Rights Directive) requires that if a trader provides an online interface (website or app) through which the consumer concluded the contract, the trader must provide a button or equivalent function allowing the consumer to exercise the right of withdrawal online.
Technical Requirements for the Withdrawal Button
The regulation imposes five concrete requirements. Quick checklist for your build:
| # | Requirement | Compliant pattern | Non-compliant pattern |
|---|---|---|---|
| 1 | Clearly labelled button | "Herroep hier" / "Opzeggen" / "Cancel contract here" / "Withdraw here" | Generic "Contact us", "Help", or label hidden behind a "Manage" menu |
| 2 | Single-step access | Maximum 2 navigation clicks from the account/order-history page where the contract was concluded | Buried in a help-centre article, requires opening a ticket |
| 3 | Electronic confirmation | Immediate on-screen acknowledgement + email confirmation on a durable medium | Confirmation page that only says "we received your message" |
| 4 | No additional hurdles | Click triggers the withdrawal directly | "Request to cancel" requiring trader approval, retention-team call, or wait period |
| 5 | Availability throughout the 14-day window | Button visible for the entire withdrawal period after the contract starts | Button hidden after first day, "out of office" banner blocking access |
These mirror the five conditions in Article 11a of the amended Consumer Rights Directive. A pattern that violates any one of them is non-compliant on its face.
Who This Affects
Primarily affected:
- SaaS products with consumer subscriptions (software, streaming, cloud storage)
- Digital content providers (e-books, music, video, if withdrawal still applies)
- Online course and education platforms
- Gym membership apps
- Any subscription-based online service sold directly to consumers
Also affected:
- Webshops where consumers can initiate returns online (the button facilitates withdrawal for goods too, though goods returns via post remain valid)
Less directly affected:
- Physical product webshops where the return process is entirely by post (the existing written/email withdrawal process remains valid for goods if consumers can also use it electronically)
The ACM (Autoriteit Consument & Markt) is expected to clarify scope in guidance. The safest interpretation: any platform through which a consumer concluded a contract that carries a withdrawal right should implement the button.
Implementation: What You Need to Build
For a typical subscription service:
-
In the user account dashboard: A clearly labelled button "Cancel subscription" or "Withdraw from contract", positioned prominently, not buried in settings.
-
The button triggers: A confirmation screen that explains what withdrawal means (contract ends, refund if applicable, data deletion timeline).
-
After confirmation: An immediate email confirmation to the consumer stating that their withdrawal has been received and the cancellation date.
-
Record keeping: Log the withdrawal with timestamp, for your own records and for ACM audit purposes.
Example flow:
- Consumer logs into account → Account page has "Cancel subscription" button (one click)
- Consumer clicks → Confirmation screen: "Are you sure? Your subscription ends on [date]. You will not be charged further. Click 'Confirm withdrawal' to proceed."
- Consumer clicks "Confirm" → Subscription cancelled immediately, email sent
- Consumer is on "Subscription cancelled" page with details
The entire process: 2-3 clicks maximum, no contact with a human required, immediate effect.
Per-platform code samples
Below are minimal working implementations for the five most common stacks used by Dutch webshops. Each sample uses the exact label "Withdraw from contract here" (acceptable equivalent: "Cancel contract here"). For pages targeted at Dutch-speaking visitors, use "Hier de overeenkomst ontbinden" instead.
Shopify (Liquid)
Add to customers/order.liquid so the button appears on every customer order detail page:
{%- assign window_seconds = 1209600 -%}
{%- assign order_age = 'now' | date: '%s' | minus: order.created_at | date: '%s' -%}
{%- if order_age < window_seconds and order.cancelled_at == blank -%}
<a href="{{ shop.url }}/pages/withdraw?order={{ order.name | url_encode }}&email={{ order.email | url_encode }}"
class="btn btn-primary withdrawal-button">
Withdraw from contract here
</a>
{%- endif -%}
On /pages/withdraw, render the confirmation form using Shopify's contact-form helper:
{% form 'contact' %}
<input type="hidden" name="contact[subject]" value="Withdrawal, Art. 11a CRD" />
<label>Your name <input type="text" name="contact[name]" required /></label>
<label>Order number
<input type="text" name="contact[order_id]" value="{{ request.query_params.order }}" required />
</label>
<label>Confirmation email
<input type="email" name="contact[email]" value="{{ request.query_params.email }}" required />
</label>
<button type="submit">Confirm withdrawal</button>
{% endform %}
The acknowledgement email is sent via a Shopify Flow workflow triggered on "Contact us form submitted" with the condition subject contains "Withdrawal".
WooCommerce (PHP / hook)
Add to your child theme's functions.php:
<?php
add_action( 'woocommerce_order_details_after_order_table', 'tyw_render_withdrawal_button', 10, 1 );
function tyw_render_withdrawal_button( $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return;
$age = time() - $order->get_date_created()->getTimestamp();
if ( $age > 14 * DAY_IN_SECONDS || $order->has_status( array( 'cancelled', 'refunded' ) ) ) {
return;
}
$nonce = wp_create_nonce( 'tyw_withdraw_' . $order->get_id() );
?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<input type="hidden" name="action" value="tyw_submit_withdrawal" />
<input type="hidden" name="order_id" value="<?php echo esc_attr( $order->get_id() ); ?>" />
<input type="hidden" name="_wpnonce" value="<?php echo esc_attr( $nonce ); ?>" />
<button type="submit" class="button">Withdraw from contract here</button>
</form>
<?php
}
add_action( 'admin_post_tyw_submit_withdrawal', 'tyw_handle_withdrawal' );
add_action( 'admin_post_nopriv_tyw_submit_withdrawal', 'tyw_handle_withdrawal' );
function tyw_handle_withdrawal() {
$order_id = isset( $_POST['order_id'] ) ? (int) $_POST['order_id'] : 0;
if ( ! $order_id || ! wp_verify_nonce( $_POST['_wpnonce'], 'tyw_withdraw_' . $order_id ) ) {
wp_die( 'Invalid request', 400 );
}
$order = wc_get_order( $order_id );
if ( ! $order ) wp_die( 'Order not found', 404 );
$order->update_status( 'cancelled', 'Withdrawn by customer under Art. 11a CRD.' );
wp_mail(
$order->get_billing_email(),
sprintf( 'Withdrawal received for order %s', $order->get_order_number() ),
sprintf( "Your withdrawal from order %s was received at %s.\n\nRefund will be processed within 14 days.\n\nThis email is the durable-medium acknowledgement required by Article 11a(5) of the Consumer Rights Directive.",
$order->get_order_number(), current_time( 'mysql' ) )
);
wp_safe_redirect( add_query_arg( 'withdrawal', 'confirmed', $order->get_view_order_url() ) );
exit;
}
For a true two-step UX, render an intermediate confirmation page before this handler cancels the order.
Lightspeed eCom (template + Apps API)
Lightspeed eCom exposes no server-side form-handler hook. The compliant pattern is to edit the customer orders Rain template and post the form to a backend you control:
{% for order in orders %}
<div class="order-row">
{% if order.age_seconds < 1209600 and order.cancelled == false %}
<a href="/pages/withdraw?order={{ order.number | url_encode }}"
class="btn btn-primary">Withdraw from contract here</a>
{% endif %}
</div>
{% endfor %}
The backend (Node, PHP, Cloudflare Worker) calls PUT /orders/{id}.json on the Lightspeed eCom API with {"order":{"status":"cancelled"}} and then sends an acknowledgement email via your transactional provider.
Magento (Adobe Commerce)
Add a small custom module with layout, block, template, and controller. The button template:
<?php /** @var \Acme\Withdrawal\Block\Button $block */
$order = $block->getOrder();
if ( ! $block->isWithinWindow( $order ) ) return;
$action = $block->getUrl( 'withdrawal/cancel/submit', [ 'order_id' => $order->getId() ] );
?>
<form action="<?= $block->escapeUrl( $action ); ?>" method="post">
<input type="hidden" name="form_key" value="<?= $block->escapeHtml( $block->getFormKey() ); ?>" />
<button type="submit" class="action primary">Withdraw from contract here</button>
</form>
The controller calls $this->orderManagement->cancel( $orderId ) and triggers a transactional email via TransportBuilder using a custom template that mentions Article 11a(5).
Headless / custom (HTML + serverless)
<form method="post" action="/api/withdraw">
<input type="hidden" name="order" value="ORD-2026-001" />
<label>Your name <input type="text" name="name" required /></label>
<label>Confirmation email <input type="email" name="email" required /></label>
<button type="submit">Confirm withdrawal</button>
</form>
// api/withdraw.js (Vercel / Cloudflare / Netlify)
export default async function handler(req) {
if (req.method !== 'POST') return new Response('Method not allowed', { status: 405 });
const form = await req.formData();
const order = form.get('order');
const email = form.get('email');
await db.withdrawals.insert({ order, email, at: new Date() });
await commerce.orders.cancel(order, { reason: 'Art. 11a CRD' });
await mailer.send({
to: email,
subject: `Withdrawal received for order ${order}`,
text: `Your withdrawal from order ${order} was received. Refund within 14 days. This email is the durable-medium acknowledgement required by Article 11a(5).`,
});
return Response.redirect(`/orders/${order}?withdrawal=confirmed`, 303);
}
The serverless pattern is the cleanest because it makes the three obligations, cancel, record, acknowledge, explicit and individually testable.
What the TrustYourWebsite scanner detects
The scanner runs ECOM-02 against your webshop and flags pages with no withdrawal/refund text and no links to a withdrawal/return/terms page in any EU language. The check uses multilingual patterns: English, Dutch (herroeping), German (Widerrufsrecht), French (rétractation), Italian (recesso), Spanish (desistimiento).
The scanner also runs ECOM-02b (Article 11a button-label match against the directive's exact wording per language — HIGH severity on customer-account paths) and ECOM-02c (presence of the model withdrawal form as either a download link or an inline form).
What the scanner still does not verify (manual review required):
- The two-step process (statement → "Confirm withdrawal") end-to-end.
- The durable-medium acknowledgement email.
- The continuous availability of the button during the full 14-day window.
Findings are technical signals, not legal verdicts.
Shipping Cost Disclosure (Related Requirement)
Also effective from July 2025 (ACM enforcement), webshops must clearly display the full shipping cost before the consumer enters checkout. This came into force earlier but is sometimes missed:
- Shipping costs must appear on the product page or category page, not just in the cart
- "Calculate in cart" is not compliant if the consumer has no indication of shipping costs before adding to cart
- Country-based shipping rates must be selectable before checkout
The ACM has issued guidance and begun enforcement on shipping cost transparency as part of its broader e-commerce consumer rights focus.
ACM Enforcement
The ACM is the enforcement authority for consumer rights law in the Netherlands under the Wet handhaving consumentenbescherming (WHC). Since 2024, the ACM has increased enforcement in e-commerce:
- In 2024-2025, the ACM focused on hidden fees, fake countdown timers, and subscriptions that are difficult to cancel
- The "subscription trap" problem (moeilijk opzegbare abonnementen) has been a priority, services that make cancellation deliberately difficult
- The withdrawal button requirement directly addresses this, it is a response to widespread non-compliance with the right of withdrawal
Maximum fine under WHC: €900,000. For consumer rights violations in e-commerce, the ACM typically starts with a compliance order (last-uiting) before imposing a fine.
Checklist: Preparing for June 19, 2026
- Identify every online service you offer where the right of withdrawal applies
- For each: locate where in your account/portal the consumer concluded the contract
- Design and implement a clearly labelled withdrawal button accessible from that area
- Implement immediate email confirmation of withdrawal
- Test the entire flow end-to-end as a consumer
- Update your terms and conditions to reference the digital withdrawal mechanism
- Update your privacy policy if withdrawal triggers data deletion
Related guides
- Herroepingsknop voor Nederlandse webshops (NL), Dutch-language sibling with the same code samples and statute references.
- Withdrawal button for Irish webshops (EN), Irish transposition status and CCPC enforcement.
- Herroepingsknop voor Belgische webshops (NL), Belgian WER Boek VI framing.
- Widerrufsbutton im Onlineshop (DE), German sibling with the § 312k BGB Kündigungsbutton distinction.
- Widerrufsbutton für österreichische Webshops (AT), Austrian FAGG framing.
- Bouton de rétractation pour webshops belges (BE-FR), French-language Belgian sibling.
- Consumer cancellation online in the UK (DMCCA), UK post-Brexit equivalent, different statute.
Run a free TrustYourWebsite scan to see if ECOM-02 triggers on your webshop today.
This article is technical analysis, not legal advice. Consult a lawyer for advice specific to your situation.
Website Guides
Dutch Webshop T&Cs: What BW Boek 6 Requires
Dutch webshop terms and conditions (algemene voorwaarden) under Boek 6 BW: what they must contain, how to make them binding, and what the ACM checks.
Dutch Webshop Compliance: Complete Checklist
A full checklist of legal requirements for online shops in the Netherlands. KVK, order buttons, withdrawal rights, pricing rules and more.
EU Consumer Rights for Online Sellers: Plain-Language Guide
EU consumer rights for online sellers: the 14-day withdrawal right, Omnibus pricing rules and pre-contractual disclosures in plain language.
EU Checkout Rules: Button Text, Pricing, Consent
EU checkout rules under Directive 2011/83/EU: order button text, price display, withdrawal rights and consent before the customer clicks Buy.
"Buy Now" vs "Order": Why Your Button Text Matters Legally
EU law requires specific wording on order buttons. The wrong text could make your orders non-binding. Here's what your checkout button must say.