
Every store owner has a gut feeling that checkout is “harder than it should be” at some point. Usually there’s no way to prove it — you can see how many people bought, but not how many almost didn’t. This is the story of how we turned that gut feeling into an actual, fixable list of problems, using nothing but data we already had sitting in our own database.
The Hunch
We run a small family of WordPress plugin sites, each selling a Free and a Pro version through Easy Digital Downloads. Support emails kept mentioning the same theme: customers who’d downloaded the free plugin weeks earlier would come back to buy Pro, hit checkout, and get stuck — usually around logging in. Nothing was throwing an obvious error. It just felt sticky.
Cart and checkout abandonment isn’t a niche problem — industry-wide research from the Baymard Institute puts average abandonment rates around 70%. Knowing that made us less interested in guessing at yet another generic “reduce friction” checklist, and more interested in finding out exactly where our own checkout was losing people.
“Felt sticky” isn’t something you can fix. So instead of guessing, we went looking for the actual page-by-page journey customers took before they bought — or didn’t.
Digging Into the Data
Easy Digital Downloads quietly tracks a “browsing history” for every order — the full sequence of pages a customer visited, with timestamps, before they completed a purchase. It’s stored as order meta in the database, which meant we could get at it directly with a SQL query in phpMyAdmin rather than relying on a third-party analytics dashboard.
The query itself is simple once you know which meta key to look for — find it, then join it against the order and product tables to scope it to a specific product:
-- Step 1: find the exact meta key that stores browsing history
SELECT DISTINCT meta_key
FROM wp_edd_ordermeta
WHERE meta_key LIKE '%history%';
-- Step 2: pull it for one specific product
SELECT
o.id AS order_id,
o.date_created,
om.meta_value AS browsing_history
FROM wp_edd_orders o
JOIN wp_edd_order_items oi ON oi.order_id = o.id
JOIN wp_edd_ordermeta om ON om.edd_order_id = o.id
WHERE oi.product_id = 123
AND om.meta_key = '_edd_browsing_history'
ORDER BY o.date_created DESC;
The export itself took a couple of false starts. phpMyAdmin’s default export format for a query result isn’t always the plain CSV you expect — it’s easy to accidentally pick an export type meant for generating code scaffolding instead of raw data. Once we exported properly as JSON, though, we had hundreds of real customer journeys sitting in a file: for each order, the exact list of URLs visited and how long each one held their attention.
There was one catch: WordPress stores that browsing history as PHP-serialized data — a format built for PHP to read back, not for humans. A single order’s history looked something like this:
a:3:{i:0;a:2:{s:3:"url";s:23:"https://example.com/";s:4:"time";i:1735689600;}i:1;a:2:{s:3:"url";s:45:"https://example.com/downloads/plugin-free/";s:4:"time";i:1735689720;}i:2;a:2:{s:3:"url";s:14:"Order Complete";s:4:"time";i:1735690000;}}
Rather than eyeballing hundreds of cryptic strings like that, we wrote a small script to parse it properly, deduplicate it, and turn it into something we could actually analyze: entry sources, how many pages each order touched, and — critically — how many orders bounced through a login or password-reset page before completing.
What the Data Actually Showed
Run across a large sample of real orders from two different products, the pattern was consistent and, frankly, more significant than we expected:
- Roughly half of all orders visited the checkout page more than once before completing — not a fluke in a couple of examples, but the norm.
- A meaningful share of orders — enough to matter, not a rounding error — bounced through a login or “lost password” page mid-purchase.
- A large share of orders had duplicate, near-empty tracking entries created after the sale already completed — a sign of an unrelated but real database bloat issue.
- The purchase receipt email promised a download link and license key it never actually delivered — the template referenced them in prose but never inserted the actual data.
The most useful discovery wasn’t a single bug — it was that two completely separate settings were both quietly requiring a login, so fixing one alone wouldn’t have changed anything.
That last point deserves its own callout, because it’s the kind of thing that’s nearly invisible until you go looking for it deliberately: the checkout process had a “require login to purchase” setting turned on, and — separately — the file download system had its own, independent “require login before delivering files” setting, also turned on. Even a perfect fix to one wouldn’t have solved the actual friction; both had to be found and addressed together.
From Data to Fix
With real evidence in hand instead of a hunch, the fixes split cleanly into two categories.
Settings, not code
- Allowed guest checkout instead of forcing every purchase through a login.
- Turned off the separate “require login” gate on file downloads, so a fixed receipt email could actually work for guests.
- Extended an aggressively short download-link expiration window that was quietly forcing customers back to a login page days after they’d already paid.
- Rewrote the purchase receipt email to actually include the download link and license key it had been promising all along.
- Made an optional “how did you hear about us?” survey field on checkout actually optional, instead of a second mandatory hurdle stacked on top of the login wall.
Theme code
- Added an inline, real-time prompt on the checkout email field: if a customer types an email address that already has an account, they immediately see a friendly “looks like you already have an account — log in here” message with a direct link, instead of discovering it only after a failed attempt.
- Extended the site’s sticky cart button with a lightweight account-status shortcut — “logged in as [name]” or “forgot password?” — so checking or recovering account access no longer requires navigating away from the page entirely.
- Along the way, found and corrected a couple of login links across the theme that were quietly using WordPress’s default
wp_lostpassword_url()behavior instead of the site’s actual custom login page — invisible in normal browsing, but a real dead end for anyone who clicked them.
What We Learned
None of this required expensive tooling or a rebuild. The data we needed was already being collected by the ecommerce plugin we were already running — it just needed to be exported, decoded, and actually looked at in aggregate instead of one order at a time. The most valuable step in the whole process wasn’t any single code change; it was replacing “checkout feels sticky” with a specific, measurable list of exactly where and how often customers were getting stuck.
If you run a WooCommerce or Easy Digital Downloads store and support tickets keep hinting at friction you can’t quite pin down, there’s a good chance the evidence is already sitting in your own database, waiting to be exported.

