WordPress Proxy
The WordPress plugin stores nothing about errors, leads or pageviews itself: everything it collects is forwarded to the Platform. What it adds is server-side enrichment a page script cannot produce — the logged-in user, the WooCommerce cart, an IP the server vouches for — and that enrichment decides which calls still pass through WordPress at all.
What goes through WordPress, and what does not
| Data | Path | Why |
|---|---|---|
| Errors, interactions, session recordings, time-on-page | Browser → Platform directly (/sdk/v1/*) | Nothing WordPress could add |
| Pageview of an anonymous visitor | Browser → Platform directly | The page states which product it is, signed by the shop's server (below) |
| Pageview of a logged-in visitor | Browser → WordPress → Platform | The user id is read from the WordPress cookie on the request, never printed into the page |
| Leads and forms | Browser → WordPress → Platform | The live WooCommerce cart, WooCommerce's session id and the user id are attached in PHP |
| Surveys | Browser → WordPress → Platform | Kept same-origin so a strict Content-Security-Policy needs no exception |
| Orders, PHP errors, catalogue changes | WordPress → Platform (server-side hooks) | These originate in PHP; there is no browser request |
The WordPress routes live under /wp-json/storepilot/v1/ and each one is rate-limited and
checked against the page's Origin. A route that still exists but that the browser no longer
uses (the anonymous pageview) stays registered for pages cached before the plugin was updated
and for a shop whose Platform was unreachable when the loader was last fetched.
The page vouches for itself
An anonymous product page prints a short signed statement into window.StorePilot:
window.StorePilot = {
// ...
page_facts: "<base64url claims>.<hmac-sha256>" // { v: 1, path: "/product/red-hat", p: "917", n: "Red hat", l: "https://…" }
};
It is signed with a key derived from the site's API key, which only the shop's server and the Platform hold, so the Platform can believe a value that arrived from a browser: what is believed is a claim the shop's server made, carried unchanged. The claim names the page's path, so it cannot be attached to a pageview of another page (a client-side navigation to the cart keeps the old token, and the Platform simply refuses it there). It carries no user id and no expiry — a product is a fact about the URL, so a copy cached for a week still vouches correctly, and a logged-in render prints no token at all.
Server-side enrichment (leads)
When a checkout or form payload passes through the leads route, PHP attaches:
wp_user_id— the logged-in user, from the request's own cookiewc_session_id— WooCommerce's own id for the visit, which is what lets an order that never rendered our hidden field still find its lead- The live cart: each line's parent product id, name, quantity and line total, plus the cart total in both the shop's display format and as a raw figure
- The visitor's IP from the socket (or from a proxy header only when the site has declared its proxy, or is behind Cloudflare's published ranges)
Security
- Origin check — every collector route accepts only requests whose
OriginorRefereris the site's own host - Rate limits — each route has its own per-IP ceiling, keyed on the socket address so a forged header cannot buy more
- The API key is never in the page — PHP adds
X-StorePilot-Keywhen forwarding; the browser only ever sees the site's public key, which identifies the site and authorises nothing but collection from the site's own origin - Consent — the collector's consent flag is forwarded on every proxied route, so a site that requires consent in the dashboard is honoured whichever path a request took
Failures
A proxied request that cannot reach the Platform answers the browser with a named reason
(unreachable, rejected_key, refused) rather than a generic error, is bounded by a short
timeout on every route whose next call is its own retry, and trips a circuit breaker after
three transport failures in ten minutes so a Platform outage cannot slow the shop down. Nothing
is queued on the shop: the next pageview, heartbeat or cart change is the retry.