Withdrawal button for ecommerce: Ireland 2026 rules
Steven | TrustYourWebsite · 20 April 2026 · Last updated: May 2026
On 19 June 2026, every EU webshop must display a clearly labelled withdrawal button on the customer account or order overview page. The source of this requirement is Directive (EU) 2023/2673 of 22 November 2023, which inserts a new Article 11a into the Consumer Rights Directive 2011/83/EU. Despite the directive's title referencing distance financial services, Article 11a applies horizontally to every online B2C contract with a right of withdrawal. Ireland missed the 19 December 2025 transposition deadline. The European Commission has issued a letter of formal notice. The required button label in English: "withdraw from contract here".
What Article 11a requires
Six requirements. The trader must provide a withdrawal function on the online interface. The button must bear the words "withdraw from contract here" or an unambiguous equivalent ("cancel contract here"). It must be prominently displayed and continuously available during the 14-day withdrawal window.
The process operates in two steps. The consumer clicks the button, submits a withdrawal statement (name, contract identifier, confirmation channel) and clicks "confirm withdrawal". The trader must acknowledge receipt on a durable medium (email). The burden of proof that the withdrawal was or was not exercised within the window sits with the trader.
The 14-day withdrawal right
The right of withdrawal applies to all distance and off-premises B2C contracts. The 14-day period begins on receipt of goods or conclusion of the contract for services.
Exceptions include bespoke goods, unsealed hygiene products, unsealed audio/video recordings, perishable goods and date-specific accommodation, transport, catering or leisure services.
The 12-month extension rule is the primary risk. If the trader has not informed the consumer about the existence and placement of the withdrawal button, the withdrawal period extends to 14 days plus 12 months. During that extended period, the trader cannot deduct normal depreciation.
Transposition status in Ireland
Ireland missed the 19 December 2025 deadline. A letter of formal notice from the European Commission has been issued. Transposition is planned via amendment to the Consumer Rights Act 2022. Until then, the duty of consistent interpretation applies: Irish courts must interpret domestic law in conformity with the directive as far as possible.
The Competition and Consumer Protection Commission (CCPC) is the primary enforcer for consumer rights. The Central Bank of Ireland handles financial services. The revised Consumer Protection Code came into force on 24 March 2026 and is relevant for financial services traders, though it addresses a separate set of obligations.
Realistic risk
The primary risk is civil: the 14-day withdrawal period extends to 14 days plus 12 months. Administrative penalties exist under EU enforcement mechanisms (up to 4% of turnover for EU-dimension infringements under Article 24 CRD), but regulators have signalled remediation-first enforcement.
For Irish SME webshops, the practical risk is a customer dispute where the extended withdrawal period applies. An item returned after 6 months at full refund, with no depreciation deduction, is a tangible financial exposure.
What the scanner detects
The TrustYourWebsite scanner runs ECOM-02 against your webshop and flags pages that contain no withdrawal/refund text and no links to a withdrawal/return/terms page in any EU language. The check looks at body copy and link anchors using multilingual patterns (English, Irish English variants, 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 / orders paths) and ECOM-02c (presence of the model withdrawal form, either as a download link or as an inline form).
What the scanner still does not verify, and what therefore requires manual review:
- 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. Pass the scanner and you still need to verify the two-step flow and the email loop end-to-end.
Implementation: button + form per platform
The directive describes outcomes, not implementation. The five samples below all satisfy the same six Article 11a requirements. Pick the one that matches your stack, adapt the labels to your store's language, and verify each piece end-to-end with a test order before the 19 June 2026 deadline.
All five samples use the exact button label "withdraw from contract here". If you change it, change it to another unambiguous equivalent, "cancel contract here" is acceptable, "contact support" is not.
Shopify (Liquid)
Add this snippet to customers/order.liquid so the button renders on every customer order detail page:
{%- comment -%}
Withdrawal button — Directive (EU) 2023/2673 Art. 11a, in force 19 June 2026.
Renders for orders within the 14-day window only.
{%- endcomment -%}
{%- 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 (a regular page template), render the two-step form:
{% form 'contact' %}
<h1>Withdraw from contract</h1>
<p>Step 2 of 2. Confirm to send your withdrawal statement.</p>
<input type="hidden" name="contact[subject]" value="Withdrawal — Art. 11a CRD" />
<input type="hidden" name="contact[order]" value="{{ 'order' | default: '' }}" />
<label>Your name
<input type="text" name="contact[name]" required />
</label>
<label>Order or contract identifier
<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" name="contact[withdraw]" value="confirmed">
Confirm withdrawal
</button>
{% endform %}
Acknowledgement email: in Shopify Flow, create a workflow triggered on "Contact us form submitted" with the condition subject contains "Withdrawal". The action is "Send email to customer" using the email captured in the form. The Flow action satisfies the durable-medium requirement in Article 11a(5).
WooCommerce (PHP / hook)
Add the following to your child theme's functions.php or a small custom plugin. The handler renders the button on the customer's order detail page and processes the withdrawal via a nonce-protected POST:
<?php
// Render the button on each customer-facing order detail page.
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' ) ); ?>" class="tyw-withdrawal-form">
<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
}
// Handle the POST. Confirm-step is the form submission itself; for a true
// two-step UX, render an intermediate confirmation page before reaching here.
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\nWe will process the refund 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 the two-step UX (separate "submit statement" then "confirm withdrawal" pages), insert an intermediate template that GETs ?order_id= and renders the confirm form, posting to admin-post.php only on the second submission.
Lightspeed eCom (template + Apps API)
Lightspeed eCom (now part of the Lightspeed Retail X-Series) does not expose a server-side templating hook for arbitrary form handling. The compliant pattern is:
- Theme template: edit
templates/customer/account/orders.rain(Rain templating) to render the button on the order list:
{% for order in orders %}
<div class="order-row">
<a href="/account/orders/{{ order.number }}">Order {{ order.number }}</a>
{% 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 %}
-
Withdraw page: create
/pages/withdrawwith the two-step form. Submission goes to a small backend you control (any Node, PHP or Cloudflare Worker endpoint) that:- Posts to the Lightspeed eCom API
PUT /orders/{id}.jsonwith{"order":{"status":"cancelled"}}. - Sends an acknowledgement email via your transactional provider (Postmark / SendGrid).
- Posts to the Lightspeed eCom API
-
Auth: the backend uses an API key from the Lightspeed merchant portal, scoped to read+write orders. Do not expose the key to the storefront.
If you do not want to run a backend, the next-best compliant fallback is a static page with a mailto: link plus a clearly labelled withdrawal form PDF, slower than a button, but still valid under Article 11a(1) if the form is interactive. Verify with your Lightspeed account manager whether a no-code app from the Lightspeed App Store satisfies the requirement.
Magento (Adobe Commerce)
Magento needs a small custom module. The high-level shape:
- Block + template, render the button on the order view page by adding to
app/code/Acme/Withdrawal/view/frontend/layout/sales_order_view.xml:
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<body>
<referenceContainer name="sales.order.info.buttons">
<block class="Acme\Withdrawal\Block\Button"
name="acme.withdrawal.button"
template="Acme_Withdrawal::button.phtml" />
</referenceContainer>
</body>
</page>
app/code/Acme/Withdrawal/view/frontend/templates/button.phtml:
<?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() ] );
$key = $block->getFormKey();
?>
<form action="<?= $block->escapeUrl( $action ); ?>" method="post">
<input type="hidden" name="form_key" value="<?= $block->escapeHtml( $key ); ?>" />
<button type="submit" class="action primary">Withdraw from contract here</button>
</form>
-
Controller,
app/code/Acme/Withdrawal/Controller/Cancel/Submit.phpvalidates the form key, calls$this->orderManagement->cancel( $orderId ), then triggers an order-cancelled transactional email viaTransportBuilder. Add a custom email template underview/frontend/email/withdrawal_confirmed.htmlso the wording matches the Article 11a(5) language. -
Two-step UX, render an intermediate confirm page before the controller cancels the order. Use a flash session message keyed by the order ID so a refresh cannot accidentally re-submit.
Custom / headless (HTML + serverless)
For a custom storefront with no e-commerce framework, two files:
<!-- order-detail.html: button -->
<form method="get" action="/withdraw">
<input type="hidden" name="order" value="ORD-2026-001" />
<button type="submit">Withdraw from contract here</button>
</form>
<!-- /withdraw.html: confirm step -->
<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 function)
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');
const name = form.get('name');
// 1. Record the withdrawal in your database (id, timestamp, channel).
await db.withdrawals.insert({ order, name, email, at: new Date() });
// 2. Cancel the order in your commerce backend.
await commerce.orders.cancel(order, { reason: 'Art. 11a CRD' });
// 3. Durable-medium acknowledgement — Postmark / SendGrid / Resend.
await mailer.send({
to: email,
subject: `Withdrawal received for order ${order}`,
text: [
`Your withdrawal from order ${order} was received at ${new Date().toISOString()}.`,
`We will process the refund within 14 days.`,
`This email is the durable-medium acknowledgement required by Article 11a(5) of the Consumer Rights Directive.`,
].join('\n\n'),
});
return Response.redirect(`/orders/${order}?withdrawal=confirmed`, 303);
}
The serverless function is the cleanest pattern because it makes the three obligations, cancel, record, acknowledge, explicit and testable.
Practical checklist
| Requirement | Legal basis | Action |
|---|---|---|
| Withdrawal function on online interface | Art. 11a(1) | Add button to order overview |
| Label "withdraw from contract here" | Art. 11a(2) | Exact or unambiguous text |
| Prominently displayed, continuously available | Art. 11a(3) | Button visible during 14-day window |
| Two-step process with confirmation | Art. 11a(4) | Statement + confirm button |
| Acknowledgement on durable medium | Art. 11a(5) | Automatic confirmation email |
| Model withdrawal form available | Annex I(B) CRD | PDF or inline form |
| 14-day period stated in terms | CRA 2022 / CRD Art. 9 | Period, start point, exceptions |
| Return cost policy stated | CRD Art. 14(1) | Who pays return shipping? |
The deadline is not the point
The deadline of 19 June 2026 is a date on a calendar. The point is that consumers gain a persistent, unambiguous escape route. Webshops that try to bury the withdrawal right by hiding the form or omitting the button are the ones on whom regulators will focus first. The 12-month extension means delay costs the trader more than the consumer.
Related reading
- What changed with the DMCCA for online cancellation in the UK, sibling regime for UK-based traders.
- Withdrawal button for Dutch webshops (herroepingsknop), same Article 11a, Dutch SERP and statute.
- Withdrawal button for Belgian webshops (Boek VI WER), Belgian transposition status.
- GDPR for Irish restaurants & hospitality, adjacent compliance surface for trade with consumer-facing webshops.
Same topic, other languages
- Widerrufsbutton im Onlineshop (DE)
- Widerrufsbutton für österreichische Webshops (AT)
- Bouton de rétractation pour webshops belges (BE-FR)
Run the free TrustYourWebsite scan to see whether ECOM-02 flags your webshop today.
This article is technical analysis, not legal advice. Consult a solicitor for advice on your specific situation.
Website Guides
Privacy policy requirements Ireland: DPC rules 2026
The 14 mandatory elements of a GDPR privacy policy for Irish websites. DPC guidance, LinkedIn EUR 310M transparency case and practical checklist for SMEs.
Website trading disclosures Ireland: Companies Act 2014
Mandatory website disclosures for Irish businesses. Companies Act 2014 s.151, e-commerce regulations, CRO requirements and practical checklist.
European Accessibility Act Ireland: online shop rules
SI 636/2023, enforceable since 28 June 2025. CCPC supervises, criminal penalties, micro-enterprise exemption.