What customer data WooCommerce actually stores
It's worth being precise here, because "customer data" on a WooCommerce store isn't one thing in one place — it's several categories spread across a few different tables, and where exactly it lives depends on how the store is configured.
Every order captures a billing address and, for physical goods, a shipping address — name, email, phone, street address. On a store still using the legacy order storage model, that data is saved as post meta on the order (itself stored as a special post type) inside wp_postmeta, keyed to the order ID. On a store running WooCommerce's newer High-Performance Order Storage (HPOS), that same data moves into purpose-built tables instead: wp_wc_orders holds the core order record (status, customer ID, billing email, totals), and wp_wc_order_addresses holds the billing and shipping address fields specifically, with a separate wp_wc_order_operational_data table for things like shipping method and payment metadata. Either way, the underlying fact is the same — full name, contact details, and physical address for every order ever placed, retained indefinitely unless something explicitly prunes it.
On top of that, a registered customer account adds a WordPress user record (wp_users / wp_usermeta) with saved default addresses, and — if the store supports it — a payment gateway may store a tokenized reference to a saved card. If the store is set up correctly, that token is meaningless outside the gateway's own systems and isn't a card number at all; if it isn't, that's a much bigger problem than anything else on this page.
Guest checkout vs. accounts: a real retention tradeoff
Every WooCommerce store has to decide whether checkout requires an account, allows guest checkout, or leaves it optional — and that choice is a genuine data-retention tradeoff, not just a UX one. An account gives a returning customer faster checkout and order history, but it also means WooCommerce is holding a standing, indefinitely-retained personal record tied to a login. Guest checkout still creates the order record with the same billing details, but there's no persistent account object accumulating more data over time, and nothing to compromise via a reused or weak password.
Neither option is universally correct. A store with repeat customers has a real case for accounts; a low-frequency or one-off purchase store has a real case for defaulting to guest checkout and treating accounts as optional. What matters is that this is a deliberate setting — WooCommerce > Settings > Accounts & Privacy — and not just whatever the install defaults happened to be.
WooCommerce's built-in export and erasure tools
This is a case where the tooling already exists and the most common failure is simply not knowing it's there. WordPress core ships built-in personal-data tools under Tools > Export Personal Data and Tools > Erase Personal Data, designed to handle exactly the kind of subject-access and erasure requests GDPR (and similar regimes) require a business to be able to fulfill. WooCommerce integrates directly with both: it registers its own data exporters and erasers so that a request against a customer's email address pulls in their orders, downloads, and account data alongside their comments and core WordPress profile — not just the generic WordPress fields.
Retention is configured separately, under WooCommerce > Settings > Accounts & Privacy > Personal data retention. From there a store can set automatic time limits for clearing out cancelled, failed, and pending orders, and separately for anonymizing completed orders after a set period — which strips the personal data while keeping the order for sales reporting. A store sitting on years of unpruned guest-checkout orders with full names and addresses attached is holding more liability than it needs to; this setting is the direct fix, and it's off by default on most installs.
The practical takeaway: before reaching for a third-party GDPR plugin, check what's already built in. For most stores, the native exporter/eraser tools plus a sensible retention policy cover the actual legal requirement. See our breakdown of the GDPR 72-hour breach notification rule for what happens when that data is exposed rather than requested.
Not every staff account needs to see every customer
WooCommerce's default Shop Manager role can view every order, every customer record, and every piece of billing data on the store — full visibility, by default, for anyone assigned that role. That's appropriate for a small store with one or two trusted operators. It's a much larger exposure surface on a bigger team, or on an agency-managed site where several people touch the store for different reasons — one person handling fulfillment doesn't need visibility into every past customer's full order history, and a support contractor troubleshooting a single ticket doesn't need store-wide export access.
The fix is ordinary least-privilege, applied to a role WooCommerce doesn't split further on its own: a custom role (via a role-editor plugin, or a small `WP_Role`-based function) that grants order-handling capabilities without full customer-data visibility, assigned based on what a given person's job actually requires rather than granting Shop Manager to everyone who touches the store. It's also worth periodically reviewing who currently holds Shop Manager or Administrator — this is the same audit our dormant admin account guide covers, just applied specifically to who can see customer PII rather than who can log in at all.
The REST API and add-on plugins are a quieter exposure path
WooCommerce ships a REST API used by its own mobile app, headless storefronts, and countless integrations — and API keys for it are generated per-user, inheriting that user's capabilities. A key generated under a Shop Manager or Administrator account and then leaked, hardcoded into a public script, or left active for a long-departed integration is a direct, silent path to bulk customer and order data, with none of the friction of an actual login. API keys deserve the same lifecycle discipline as passwords: scoped to the minimum permission level actually needed (read-only where possible), rotated when a project or contractor relationship ends, and audited under WooCommerce > Settings > Advanced > REST API periodically rather than left to accumulate.
The other quiet exposure path is plugins that touch customer data as a side effect of a feature that seems unrelated to security — a customer-reviews plugin that surfaces reviewer email addresses, a wishlist or "recently viewed" plugin that stores customer identifiers in a custom table with no access controls of its own, a loyalty-points add-on that exposes a REST endpoint for point balances tied to customer IDs. None of these are the store's core checkout or account system, which is exactly why they get less scrutiny — and exactly why a vulnerability in one of them can expose customer data without ever touching WooCommerce's own tables directly. The same update discipline and vulnerability monitoring that applies to payment-gateway plugins applies here too; a plugin doesn't need to process payments to be a meaningful risk to customer data.
The short version
- Know where customer data actually lives —
wp_postmetaon legacy order storage, orwp_wc_orders/wp_wc_order_addressesunder HPOS — and set a real retention policy instead of keeping it indefinitely by default. - Treat guest checkout vs. accounts as a deliberate retention decision, not a default left untouched.
- Use WooCommerce's built-in exporter/eraser tools (Tools > Export/Erase Personal Data) before reaching for a third-party plugin — they already integrate with orders and accounts.
- Scope staff access to customer PII by role, not by convenience — not everyone touching the store needs full Shop Manager visibility.
- Audit REST API keys and any plugin that stores customer identifiers, even ones that don't look security-relevant at first glance.
See what a finding on your store actually means before you decide how urgent it is.
Install free →