Guide

The technical Giving Tuesday checklist: 11 things to verify on your donation form before the traffic arrives

Every Giving Tuesday readiness guide you can find is a marketing plan. This one is not. It is the list of things that actually break on the first Tuesday of December and again at 11:59pm on 31 December, written for the person who has to fix them.

Short answerFour things break donation forms on a high-traffic day, in roughly this order of frequency: a webhook endpoint still pointed at a staging URL, live traffic running on test API keys, a page cache or CDN swallowing the plugin's REST routes, and receipt email that has never been tested above a trickle. All four are verifiable in under an hour. None of them are marketing problems, and none of them show up until money is already moving.

Giving Tuesday 2026 falls on 1 December. If you build or maintain WordPress sites for nonprofits, you will get the "is the site ready?" email sometime in early November, and the honest answer is that nobody can tell you without opening four dashboards and checking. This page is that check, in order, with what a pass looks like.

How do I make sure our donation page can handle Giving Tuesday?

Start from the failure mode, not the feature list. On a busy day, donation pages almost never fail by refusing payments. They fail by taking the payment and never recording it. The donor's card is charged, the money lands in the Stripe or PayPal balance, and the website shows nothing. No receipt, no campaign thermometer movement, no row in the donations table. Then someone reconciles in January and finds a gap.

That single failure pattern has four common causes. Work them in this order, because the first one is the most common and the cheapest to fix.

  1. The webhook endpoint points at the wrong host. Usually a staging URL left behind after a rebuild, or a URL from the site's old domain.
  2. Test keys in production, or the reverse. Real gifts charged against a sandbox, or test gifts that look real in your reports.
  3. A page cache or CDN is intercepting the plugin's REST routes. The processor gets a cached or 403 response and records a delivery failure.
  4. Receipt email has never been tested at volume. It works for you at your desk; it silently fails to 200 Gmail addresses in ten minutes.

1. Is the webhook endpoint live, and pointed at production?

Donor Merchant 2.5.2 listens on two REST paths:

  • https://yourdomain.org/wp-json/donor-merchant/v1/webhook/stripe
  • https://yourdomain.org/wp-json/donor-merchant/v1/webhook/paypal

Open the Stripe Dashboard, go to Developers then Webhooks, and read the destination URL character by character. The failure you are hunting for is a hostname like staging.yourdomain.org, yourdomain.wpengine.com, or an old pre-migration domain. It will look plausible at a glance. Do the same in the PayPal Developer dashboard under your app's webhooks.

Then read the delivery log, which is the part most people skip. Stripe shows recent attempts and response codes per endpoint. A healthy endpoint shows a run of 200s. A sick one shows 404, 403, 301 or timeouts. Stripe's webhook documentation says it retries a failed delivery with exponential backoff for up to three days in live mode (commonly reported as roughly 16 attempts) and then disables the endpoint. PayPal retries a non-2xx response up to 25 times over about three days per PayPal's webhooks overview, and stops the moment it receives a 2xx.

The practical consequence: if your endpoint is broken on 1 December and you notice on 5 December, the events are gone. Stripe will not replay them automatically. You will be re-keying gifts by hand from the processor's payments list. Our guide on Stripe donations not showing in WordPress covers the recovery path if that has already happened to you.

Pass looks likeBoth webhook URLs contain your live public hostname, use HTTPS, and the processor's delivery log shows 200 responses for the last several events. Takes 10 minutes.

2. Test keys versus live keys, and how to test without spending real money

Donor Merchant ships a test mode. Use it deliberately in the first week of November: turn it on, put Stripe's test keys in, run a one-off gift, a monthly recurring gift, a PayPal gift, a tribute gift, and a gift with fee recovery enabled. Confirm each one lands in the donations table, fires a receipt, and moves the campaign thermometer. That is how you test a donation form without spending real money, and it is far better than the alternative of charging your own card £1 and refunding it, which costs you the fee and teaches you less.

Then switch back. Write it on a sticky note. The number of sites that go into December still in test mode is not zero, and the symptom is deeply confusing: the form works perfectly, the thank-you page appears, and no money ever arrives.

The reverse disaster is worse and more common. You point the webhook at staging while you test, then push to live and forget to move it back. Real donors are now really charged, and your site records nothing. This is the number one cause of the January reconciliation gap, and it is why reconciling payouts against your donation records is worth doing monthly rather than annually.

3. Is a page cache or CDN swallowing your REST routes?

This one is genuinely hard to spot because the site gets faster and the donation form still looks fine. What breaks is the machine-to-machine traffic behind it.

Caching layers that serve a stored copy of /wp-json/ responses, or that strip cookies and nonces from the donation page, will break a payment integration in ways that look like a plugin bug. GiveWP's own support forum carries repeated threads on exactly this, including cached donor payment history; the standard remedy across those threads is to exclude the donation, donation-confirmation and donor-dashboard paths from cache. Cloudflare's community has the parallel case for the REST API, where a cached nonce produced 403s on wp-json. The rule that follows from both: never cache a page that carries a nonce, and never cache a REST namespace that handles payments.

Exclude, at minimum: the REST namespace /wp-json/donor-merchant/, your donation page, your thank-you or confirmation page, and the donor portal page (/my-donations/ by default).

LayerWhere the exclusion lives
WP RocketAdvanced Rules, Never Cache URL(s). Add the donation, confirmation and portal paths plus /wp-json/donor-merchant/(.*)
W3 Total CachePage Cache, Advanced, "Never cache the following pages"
LiteSpeed CacheCache, Excludes, "Do Not Cache URIs"
Cloudflare (including APO)A Cache Rule with "Bypass cache" where URI Path starts with /wp-json/. Do not stack a Cache Everything rule on top of APO
SiteGround OptimizerCaching, "Exclude URLs from caching" (applies to Dynamic Cache too)
WP EngineCache exclusions are set through the user portal or support; object cache also needs checking
KinstaMyKinsta, Tools, cache exclusion URLs

Verify the fix rather than trusting it. Request the Stripe webhook URL directly in a browser: you should get a JSON error from WordPress, not an HTML page, not a 403, and not a Cloudflare challenge page. If the response carries a cf-cache-status: HIT header, you are not done.

4. Will the receipt email actually arrive?

Test this in November, not on 2 December. Send a real test receipt to three mailboxes: a Gmail address, an Outlook or Hotmail address, and an address on the organisation's own domain. Then check where it landed, not just whether it sent.

Validity's 2023 Email Deliverability Benchmark Report, summarised here, found that over 16% of nonprofit email either goes to spam or is never delivered at all. The usual causes on a WordPress site are mundane: host-level throttling of wp_mail() once you exceed an hourly quota, a From address on a domain the server is not authorised to send for, and missing SPF, DKIM or DMARC alignment.

Check that the From address on your email receipts is on a domain whose DNS publishes SPF and DKIM records covering whatever is actually sending, and that DMARC alignment passes. If your host throttles, route transactional mail through a dedicated SMTP service before the spike, not after. A donation receipt is transactional email, not marketing: it should not be sent through your newsletter tool, and it should not carry an unsubscribe link that a donor could use to switch off their own tax documentation.

A donation made on December 31 was receipted for the next year - why?

Because three systems disagree about what day it is, and each of them is right from its own point of view.

  • Your website dates the gift using the WordPress timezone setting in Settings, General. If that is still on UTC and your organisation is in Los Angeles, a gift at 4:30pm on 31 December Pacific is already 1 January in UTC.
  • The processor dates the charge by its own account timezone, which you set separately in Stripe or PayPal and probably never looked at.
  • The bank sees the money later still, because a card charge on 31 December typically settles in the first days of January and ACH later than that.

Fix the controllable part first: open Settings, General and set the WordPress timezone to the organisation's actual city before December, not to a UTC offset (a city handles daylight saving; an offset does not). Then set the Stripe and PayPal account timezones to match. Then decide, once, which date your receipts and annual statements use, and write it down for whoever prepares the January mailing.

On substance rather than software: for a US donor, a gift charged to a credit card on 31 December is generally treated as made on 31 December even though it settles in January, and a cheque is generally treated by the postmark date. That is the practical rule most organisations work to, and it is why the settlement date is the wrong field to build your statements on. Tax treatment varies by jurisdiction and by circumstance, so confirm the specifics with your accountant before you send anything a donor will file. Donor Merchant's annual year-end tax statements are generated from the donation date recorded on the site, which is exactly why the timezone setting matters.

Will per-IP rate limiting block real donors during a surge?

Donor Merchant's donation form protection is a honeypot field plus per-IP rate limiting. There is no CAPTCHA, and we are not going to claim parity with Stripe Radar plus reCAPTCHA. The tradeoff is deliberate: a honeypot costs the donor nothing and blocks unsophisticated bots, while rate limiting caps how fast a single address can hammer the form.

There is one real false-positive case, and it is worth knowing before the day: many legitimate donors behind a single NAT. A church giving appeal made from the pews on the building's wifi, a workplace matching drive, a school. Every one of those donors presents the same public IP. If legitimate donors report being blocked, that is almost always what happened. Check the IP in your server logs against the venue, and confirm your host is passing the real visitor IP rather than a proxy address (if you are behind Cloudflare without mod_remoteip or the equivalent, every visitor looks like the same handful of edge IPs, which will absolutely produce false positives).

Card-testing bots pick high-traffic days on purpose

Donation forms are the preferred target for card testing because they accept arbitrary amounts, do not require an account, and are often on sites with no fraud tooling. Attackers prefer busy periods because the noise hides them. Because you own the Stripe integration directly rather than renting it through a platform, you can configure Radar rules in your own Stripe account before the event: block or review small-amount charges from high-risk countries, throttle repeat attempts from one IP, and turn on the 3D Secure rules that suit your donor base. Our guide on stopping a card-testing attack on a donation form has the specific rule set and the cleanup steps if one is already running.

Campaign, fund and form hygiene

The boring half hour that prevents the awkward email on the day:

  • Set the campaign goal and start date so the thermometer starts where you intend rather than at whatever last year left behind.
  • Check that your designations and funds are named exactly as the appeal copy names them. If the email says "Winter Shelter Fund" and the dropdown says "Shelter (winter)", donors will ask, and your finance volunteer will have to map them by hand.
  • Confirm the form's accent colour and button shape still read correctly against whatever December banner or seasonal theme change is going up. Theme changes and form styling are set in different places and nobody checks both.
  • Load the donation page on a real phone on cellular data, not on desktop with devtools. Then complete a test gift on it.
  • Confirm recurring options are switched on. Monthly giving is the highest-value thing on the page and the easiest to leave disabled.

December cheques that arrive in January

Cheques postmarked in December routinely land in the first two weeks of January, and the donor expects them on the December statement. Enter them through offline donation entry with the correct December date, before you generate annual statements. Doing it in that order means the statement is right the first time and you are not reissuing corrected documents in February. Offline entry is free, as is everything else in the plugin.

The pre-flight table

#CheckWherePass looks likeTime
1Stripe webhook URLStripe, Developers, WebhooksLive hostname, HTTPS, path /wp-json/donor-merchant/v1/webhook/stripe5 min
2PayPal webhook URLPayPal Developer, your appLive hostname, path ends /webhook/paypal5 min
3Delivery logsBoth processor dashboardsRecent attempts all 2005 min
4Live keys, test mode offDonor Merchant settingsLive keys saved, test mode disabled5 min
5Cache and CDN exclusionsCache plugin plus Cloudflare/wp-json/, donation, confirmation and portal pages bypassed20 min
6Receipt deliverabilityGmail, Outlook, own domainInbox, not spam, in all three20 min
7SPF, DKIM, DMARCDNS plus a mail testerAll three pass and align with the From domain20 min
8WordPress timezoneSettings, GeneralSet to a city, matching the processor account2 min
9Stripe Radar rulesStripe, RadarCard-testing rules active before the event20 min
10Campaign, goal, fundsDonor Merchant, CampaignsGoal and dates set, fund names match the appeal15 min
11End-to-end test giftTest mode, then liveRecorded, receipted, thermometer moved30 min

What this checklist is not

It is not a marketing plan. There is nothing here about email sequences, countdown timers, UTM parameters or social banners, and plenty of other people write those well. It is also honest about what Donor Merchant does not ship: there is no load-testing tool and no CAPTCHA in the plugin. Load testing, if you need it, is a question for your host, and most shared hosting will not survive a genuine spike regardless of what your plugin does.

The reason a checklist like this exists here and not on a platform vendor's blog is structural. If the infrastructure being checked is the vendor's own, publishing the failure list admits the failures. On a self-hosted plugin the infrastructure is yours, so the list is just useful. If you want a hand working through it before December, that is what the support plans are for; the plugin itself stays free either way.

Your next monthly donor is on your website right now

Give them a form worth filling out. Install Donor Merchant free and take your first recurring gift today.

Download Donor Merchant free No signup. No platform fees. Or try the live demo first.