Why Online Stores Crash During Mexico's Buen Fin (and How to Prevent It): The 2026 Technical Guide
Table of Contents
El Buen Fin, Mexico’s answer to Black Friday, runs from Friday November 13 to Tuesday November 17, 2026. Almost everything published about getting a store ready for it is about banners, coupons and email. This guide is the other half: what breaks technically when the visitors you paid to attract all show up at once, and what to do beforehand. Nearly all of it is written down in your host’s, your payment gateway’s and your platform’s documentation, and almost nobody reads it until the store is already down.
Last year’s numbers show why it matters. According to Mexico’s Ministry of Economy, the 2025 edition sold 219.2 billion pesos, and digital commerce was 21% of the total, growing 31% year over year. The public AMVO report (Mexico’s online sales association) counted 1.686 billion page views on e-commerce sites and traffic 56% higher than the previous edition (which went from four days to five). The retailers’ association ANTAD reports that the last day alone took 26.1% of online sales. The peak doesn’t spread out: it arrives, and it arrives all at once.
If you sell into Mexico from abroad, or build stores for Mexican clients, the local details are what catch people out: the cash-at-OXXO payment method, the Mexican shared-hosting plans small businesses actually run on, and a gateway landscape where Mercado Pago matters as much as Stripe. I’ve built WooCommerce stores with catalogues in the thousands, Mercado Pago payments and WhatsApp checkout. This is what I check on each one before a date like this, with a source for every limit.
What those five days look like
| Buen Fin 2025 | Figure | Source |
|---|---|---|
| Total sales | 219.2 billion pesos | Ministry of Economy |
| Online sales | 21% of the total, +31% YoY (45.9 billion per AMVO) | Economy / AMVO |
| Traffic to online stores | +56% over the 5 days, +24% on comparable days | AMVO (Similarweb data) |
| Average ticket | $1,063 MXN online vs $780 overall | Mexican Banking Association, cited by Economy |
| How people paid online | Credit 48%, debit 43%, store cards 17%, card-free instalments 12%, cash at retail chains 12% | AMVO |
| Consumer agency complaints | 220 filed, 205 settled; mostly unhonoured prices and refused delivery | Profeco |
Two rows matter for the technical side. One in eight online buyers paid cash at a retail chain (OXXO and similar), which has a consequence for your inventory that I explain below. And 37% of consumers, per the AIMX survey the ministry cites, fear a data leak: an expired-certificate warning or a checkout page that looks off on your busiest day costs sales even if the site stays up.
Not everything that fails is yours, either. During Buen Fin 2024, Santander and BBVA customers reported card payment failures; during Hot Sale in May 2026 BBVA confirmed on X that its systems were down, with over five hours of Downdetector reports. And on November 18, 2025, the day after Buen Fin ended, Cloudflare had a global outage of more than three hours. You can’t stop your customer’s bank from going down. You can have a second payment method ready when it does.
1. Shared hosting has a ceiling, and it’s in writing
The shared hosting plan that costs a few hundred pesos a year isn’t “slow”: it has exact limits, and when you hit them it doesn’t slow down, it returns errors. Hostinger publishes its limits on its plan parameters page and says reaching them produces “503 – Service temporarily unavailable”:
| Hostinger plan | CPU | RAM | Concurrent PHP workers | MySQL connections |
|---|---|---|---|---|
| Web Single | 1 | 1 GB | 20 | 25 |
| Web Premium | 1 | 2 GB | 40 | 50 |
| Unlimited (formerly Business) | 2 | 3 GB | 60 | 75 |
HostGator Mexico puts it differently in its help centre: a cap of 25% CPU sustained for 90 seconds or more, and 25 concurrent processes per cPanel account.
Do the maths with your own store. An uncached WooCommerce product page holds a PHP worker while it renders. If it takes one second and you have 20 workers, your ceiling is about 20 pages per second; visitor number 21 doesn’t wait in line, they get an error. That’s why caching, next, isn’t an optimization: it decides whether those limits ever reach you.
2. Caching: what can be cached and what can’t
The idea is simple: most visitors, the ones just browsing, should get a prebuilt copy of the page and cost your server nothing. Only the cart, checkout and account pages need to reach the server every time.
What almost nobody knows is that Cloudflare doesn’t cache HTML by default, on free or paid plans. Its documentation is explicit: “The Cloudflare CDN does not cache HTML or JSON by default.” If you put your store behind Cloudflare and configured nothing else, images, CSS and JavaScript are cached, but every page still hits your host. The free plan gives you up to 10 Cache Rules and one is enough. This expression is for a Spanish-language WooCommerce store (adjust the paths to yours):
(http.host eq "tutienda.mx"
and not starts_with(http.request.uri.path, "/wp-admin")
and not http.request.uri.path contains "/carrito"
and not http.request.uri.path contains "/finalizar-compra"
and not http.request.uri.path contains "/mi-cuenta"
and not http.cookie contains "woocommerce_items_in_cart"
and not http.cookie contains "wordpress_logged_in")
With the “Eligible for cache” action and a short edge TTL (5 to 10 minutes), browsers get the cached copy, and anyone with something in the cart or a logged-in session goes straight to your server. Two warnings:
- Purge the cache when prices change. If your discounts start at midnight on the 13th, a copy cached at 11:58 pm still shows the old price, and “the price wasn’t the advertised one” is among the complaints Profeco receives most. Purge when you switch the offers on.
- A cookie on every page breaks everything. Cloudflare won’t cache a response carrying
Set-Cookie, and some plugins (currency switchers, geolocation, popups) send one on every visit. Check it like this:
curl -sI https://tutienda.mx/producto/tu-mas-vendido/ | grep -iE "set-cookie|cf-cache-status"
What you want to see, from the second request on, is cf-cache-status: HIT and no set-cookie. If you see DYNAMIC or BYPASS, that page is still hitting your server.
Two things look like safety nets and aren’t. Always Online is on every plan, but it only kicks in on 52x errors, serves Internet Archive snapshots and can’t serve dynamic content: nobody checks out from an archived copy. And Cloudflare’s Waiting Room, the virtual queue big retailers use, only exists on Business and Enterprise plans.
On WooCommerce, also check cart fragments: the script that updates the cart counter by calling the server on every page. WooCommerce acknowledges that on heavily trafficked stores “this could severely impact the load on the server”, and since version 7.8 it no longer loads on every page, but plenty of themes and plugins turn it back on. Open a product page with your browser’s dev tools and look for a request to ?wc-ajax=get_refreshed_fragments. If it fires on pages without a mini cart, that’s one server request per visit that caching can’t remove.
And slim down your product photos: they’re most of a store’s page weight, and on mobile, where most Mexican shoppers buy, every megabyte shows.
3. Your payment gateway has a limit too
The server isn’t the only thing that can say no. Stripe publishes its rate limits: 100 requests per second in live mode, with most individual endpoints capped at 25. And it says plainly that “a sudden increase in charge volume, such as a flash sale, might result in rate limiting”; if you expect a spike, it asks you to contact support beforehand. Mercado Pago doesn’t publish a number, but its Orders API answers 429 Too Many Requests with a Retry-After header when you exceed it.
For a small business, 100 charges a second is plenty. The problem shows up when the integration makes several calls per purchase (create customer, create payment intent, poll status) or retries without backing off: a badly handled 429 becomes “we couldn’t process your payment” for a customer who had the funds.
Bank verification (3-D Secure, the “confirm in your app” screen) changes the flow too. Mexico has no regulatory mandate for it, but Mercado Pago recommends enabling it in optional mode, and when the bank asks for a challenge the payment sits in pending with detail pending_challenge. If your integration treats “pending” as “declined”, you’re cancelling good orders. AMVO lists “payment method rejected” among the barriers to buying online.
4. The problem nobody mentions: cash at OXXO locks your inventory
This is what worries me most for a store with limited stock, and I didn’t see it in any Buen Fin guide I read. When a customer chooses to pay cash, the gateway issues a voucher with an expiry date, and until they pay, the item is in limbo:
| Gateway | Voucher validity | If they pay late |
|---|---|---|
| Stripe (OXXO) | 5 days by default, configurable from 1 to 7; confirmation arrives the next business day | The voucher expires (docs) |
| Mercado Pago (OXXO, Paycash) | Configurable from 1 to 30 days; they recommend 3. Crediting takes up to 2 business hours | “The amount will be refunded” (docs) |
| Conekta | Set by your integration with expires_at; signalled by the order.expired webhook | Up to your integration (docs) |
Now the WooCommerce side. Its “Hold stock” setting reserves items for orders pending payment for as long as you configure (60 minutes is the recommended value) and then cancels them, according to its guide. But the same guide says delayed payment methods leave the order on hold, where that automatic cancellation doesn’t apply. If your gateway plugin doesn’t cancel the order when the voucher expires, the item stays reserved for days by someone who may never pay, while you tell the customer holding a card that it’s sold out.
Before the 13th:
- Shorten voucher validity for the campaign. One or two days instead of five or thirty.
- Check that your plugin cancels the order on expiry. Place a test cash order with the minimum validity, don’t pay it, and check the next day that the order was cancelled and the stock came back.
- If you sell over WhatsApp with payment links, give them a short expiry. Clip, for example, lets a link expire the same day.
5. Overselling: two people buy the last unit
Since version 4.3, WooCommerce reserves stock during checkout to stop two simultaneous purchases taking the same unit (PR #26395). Even so, issue #44273, where the team confirms that “a race condition like this is possible”, is still open today. On a normal day it almost never happens. During Buen Fin, with hundreds of people on your best seller, is when it does.
For low-stock products: keep a buffer (list 18 if you have 20), cap quantity per customer, and decide in advance what you’ll do if it happens, with an apology and a fast refund. Refused delivery was among the complaints that dominated Profeco’s 2025 figures. Shopify’s flash sale guide recommends switching to manual payment capture for the same reason: charge only for what you can actually ship.
6. What runs in the background
Order confirmation emails, payment webhooks and stock updates in WooCommerce go through Action Scheduler, which by default processes batches of 25 actions for 30 seconds, triggered by WP-Cron. And WP-Cron only runs when someone visits the site. With caching done right, hardly anyone reaches the server, and tasks can pile up. The result: customers who paid and don’t get their confirmation, and message you asking whether the order went through.
The fix is a real server cron instead of the visit-driven one: set DISABLE_WP_CRON in wp-config.php and schedule a call to wp-cron.php every minute from your hosting panel. Almost every shared host allows it.
7. Test it first with fake traffic
All of the above can be checked without waiting for the 13th. A load test simulates many visitors at once and shows you where errors start. Two free options:
- k6, by Grafana: free on your own machine, and its free cloud tier includes 500 virtual user hours a month.
- Loader.io: the free plan allows 10,000 clients per test for one minute, run from US data centres.
A minimal k6 script that visits the home page and your best seller:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 }, // ramp to 50 concurrent visitors
{ duration: '5m', target: 50 }, // hold
{ duration: '1m', target: 0 },
],
thresholds: {
http_req_failed: ['rate<0.01'], // under 1% errors
http_req_duration: ['p(95)<2000'], // 95% under 2 seconds
},
};
export default function () {
check(http.get('https://tutienda.mx/'), { home: (r) => r.status === 200 });
sleep(3);
check(http.get('https://tutienda.mx/producto/tu-mas-vendido/'), { product: (r) => r.status === 200 });
sleep(5);
}
Run it with k6 run test.js. Three rules: test pages, never your payment gateway; on shared hosting, tell your provider first, because a load test looks a lot like an attack; and aim at three to five times your normal peak hour. There’s no public figure for how much a small store’s traffic rises during Buen Fin compared with an ordinary day; if your analytics kept last year’s, use that. If the test fails at 50 visitors, you know what to fix, and you have seven weeks to do it.
If your store runs on Shopify or Tiendanube
Infrastructure isn’t your problem: Shopify handled 489 million requests per minute at its edge over Black Friday and Cyber Monday 2025, and its guide says special preparation is only needed if you expect “tens of thousands of customers” starting checkout within minutes. Yours are the other sections: theme weight and the apps you load on every page, the gateway and its pending states, cash voucher validity, and your stock buffer.
The two-weeks-before checklist
| What | How you verify it |
|---|---|
| HTML caching on for browsers | cf-cache-status: HIT on the second request to a product page |
No page sends Set-Cookie to visitors | The same curl -sI as above |
| Cart, checkout and account excluded from cache | Add something to the cart in another window and check the counter updates |
| New prices visible | Purge the cache when offers go live and check in a private window |
| Short cash-voucher validity | Test OXXO order you don’t pay: on expiry, order cancelled and stock back |
| “Pending” payments treated as pending | Test purchase with 3-D Secure that you don’t complete |
| Real server cron | DISABLE_WP_CRON in wp-config.php and a task every minute |
| Buffer on best sellers | Listed stock below real stock |
| SSL certificate valid past November 17 | SSL lookup |
| Load test passed | k6 or Loader.io with no errors at three times your peak |
| Plan B for payments | Payment link and WhatsApp ready in case the gateway or the bank fails |
If you need a store or site in Mexico built to survive a date like this, that’s what I do.
Frequently asked questions
When is Buen Fin 2026?
From Friday November 13 to Tuesday November 17, 2026. It is the 16th edition and runs five days because it includes Monday November 16, the observed Revolution Day holiday. Business registration is free at elbuenfin.org, from September 8 to November 12.
Why do online stores crash during Buen Fin?
Usually because every visit reaches the server uncached and the host runs out of the processes it allows. Shared plans have fixed limits (20 PHP workers on Hostinger's entry plan, 25 processes per cPanel account on HostGator Mexico) and return a 503 error past them. The payment gateway can also fail when it rate-limits, or the customer's bank, which is out of your hands.
Does Cloudflare's free plan protect a store from Buen Fin traffic?
It helps, but not just by switching it on. Cloudflare does not cache HTML by default, so without a Cache Rule every page still hits your host. The free plan allows up to 10 rules, and one is enough to cache pages for browsers while excluding cart, checkout and account. The virtual queue (Waiting Room) only exists on Business and Enterprise plans.
Does a pending OXXO payment lock my inventory?
It can, for days. Stripe OXXO vouchers expire after 5 days by default (configurable from 1 to 7) and Mercado Pago's after 1 to 30. In WooCommerce, delayed-payment orders go on hold and the 60-minute hold-stock setting only cancels orders pending payment, so the item stays reserved until the gateway plugin cancels the order when the voucher expires. Shorten validity for the campaign and test it with an order you do not pay.
How do I load test an online store?
With k6, free and open source, or Loader.io, whose free plan runs up to 10,000 clients in a one-minute test. Simulate visitors on the home page and best sellers, never on the payment gateway, aim at three to five times your peak hour, and warn your shared hosting provider first, because a load test looks like an attack.
Found it useful? Get the next one by email
Once a week: what breaks when you upgrade, AI for developers and what I'm building, with sources. No spam.
By subscribing you accept our privacy policy.