Verify and troubleshoot
Do this in a real browser on a real basket page.
Before you install: a dry run (optional)
Section titled “Before you install: a dry run (optional)”You can test the whole path with no code change at all: open your basket page, open DevTools → Console, and paste this. It loads the real production bundle with verbose logging on.
(() => { window.GWP_DEBUG = true; // verbose boot logging const s = document.createElement("script"); s.async = true; s.src = "https://cdn.gwpingenuity.com/w.js"; s.setAttribute("data-site", "YOUR_SITE_KEY"); document.body.appendChild(s);})();Every line is prefixed [GWP debug]. This only works on a page where the tag is not already installed. The loader boots once per document, so a second copy is a no-op.
With the tag installed
Section titled “With the tag installed”-
The bundle loads. DevTools → Network, filter
w.js. Expect200fromcdn.gwpingenuity.com. A CSP violation in the Console instead means Content Security Policy. -
Config resolves. Filter
v1/config. Expect200and a body whoseconfig.pageTypeis"basket"and whoseconfig.offersis non-empty."config": null→ wrong, unknown or paused site key, or a kill switch.pageTypeabsent → your basket URL is not in the patterns (page registration).offers: []→ nothing live is assigned to you yet; talk to us.
-
The widget mounted. In the Console:
document.querySelectorAll("[data-gwp-widget]").length // → 1That element is our shadow host. In the Elements panel it shows a
#shadow-root (closed). One is correct on any page; more than one is a bug. Tell us. -
The accessor exists.
typeof window.GWP.selection // → "function"window.GWP.selection() // → { gifts: [] } before you pick anythingObject.keys(window.GWP) // → ["selection"] and nothing else -
Watch a selection happen.
document.addEventListener("gwp:selection", (e) => console.log("GWP", e.detail));Pick a gift in the widget. Expect one log with a
giftsarray of length 1, and aPOST /v1/selectreturning200with aclid. A403on/v1/selectmeans the hostname in your browser's address bar is not on your registered-domains list: the widget still renders, nothing is recorded. On a production hostname, send us the domain. Onlocalhostor a dev machine, that 403 is expected and local development tells you how to work around it. -
It persists.
document.cookienow containsgwp_sesandgwp_sel, andlocalStoragehas the same keys. These are first-party on your own domain. -
Cart rules apply. Drop the basket below your configured minimum: the widget unmounts and the selection is dropped. Raise it again: it returns. If it does not unmount, your adapter is probably not reading. See cart adapters.
-
The confirmation leg. Complete a test order. On the confirmation page expect the redemption card, a
POST /v1/associatereturning200with your real order id, and, on clicking Claim, aPOST /v1/clickoutfollowed by a redirect to the partner carrying the click id in the query string. -
The dashboard agrees. Your GWP dashboard → Install shows "Detected & healthy" once both a basket and a confirmation load have been seen. "Detected on basket only" means the confirmation leg has not reported yet.
Prove the no-op case too. Load a product page and a category page with the tag present and confirm the widget renders nothing, logs nothing to your error tracker, and adds no console noise.
Troubleshooting
Section titled “Troubleshooting”Turn on window.GWP_DEBUG = true before the tag executes (add <script>window.GWP_DEBUG=true</script> immediately above the tag on a staging build) and read the [GWP debug] lines. They are written to say exactly which gate refused.
| Symptom / debug line | Cause | Fix |
|---|---|---|
No [GWP debug] lines at all | The bundle never executed. | Check Network for w.js; check for a CSP violation (Content Security Policy); check the tag is actually in the rendered HTML. |
missing site-key or API base → not booting | No data-site on the tag, or the src origin is wrong. | The attribute is data-site, on the same <script> element as src. |
no config returned — unknown/paused/kill-switched site-key, or non-eligible page → render nothing | Wrong, unknown or paused site key (or a kill switch). | Confirm the key from your dashboard. This line is not the URL-pattern case (see the next row for that). |
page type "(other)" is not basket/confirmation (check page-type URL patterns) → nothing | The pathname does not match your basket/confirmation patterns, or an exclusion (!*/pages/*) caught it. | Add an anchored pattern for your real path (page registration). Remember matching ignores query and hash. |
cart read: FAILED (adapter couldn't read the cart) | The adapter cannot see your cart. | Cart adapters. Common causes: value sent as a string to the window adapter; the dom selector matching nothing; a dataLayer created after boot so the push wrap was never installed. |
not eligible → nothing (no offers, cart below min, or frequency cap hit) | Cart under minCartValue, no live offers, or perSessionCap/perDayCap already spent. | Raise the basket; check offers are assigned; clear gwp_shows from both localStorage and cookies to reset caps while testing. |
all offers below their minimum cart value → nothing | Every offer has its own minimum above the current cart. | Raise the basket. |
no explicit slot and no fallback anchor found → fail closed (will retry on DOM changes) | The configured selector matched nothing and no fallback anchor was found. | Add <div data-gwp-slot></div> to the template. That is the reliable fix. |
confirmation page but no persisted selection to redeem → nothing | Correct behaviour: this shopper never picked a gift. | If a selection was made, check the basket and confirmation pages share a registrable domain and that cookies are not blocked. |
consent denied (CMP) → nothing (no storage written) / …has not answered the banner yet / strict consent mode: no explicit CMP grant → fail closed | The CMP gate. | Accept the banner, or review consentMode with us. |
config fetch transiently failed (429/5xx/network) — keeping current state, will retry | Transient. | No action; it retries. Persistent → tell us. |
| Widget renders, but nothing appears in reporting | /v1/events and /v1/select are origin-checked and returning 403. | Register the exact domain(s) you serve from: the hostname only, no scheme or port. If you are on localhost or a preview host, see local development. |
| Widget appears twice | Two mount points matched, or a stale container from an old bundle. | Make the selector match exactly one element. If it persists, tell us. |
| Widget appears inside a hidden/closed drawer | The openWhen selector is true while closed. | Re-verify root.matches(openWhen) in both states (cart drawers). |
| Gifts shown on a basket below your minimum | The cart read is failing, and the minimum gate is skipped on an unreadable cart (fail-open). | Check cart read: in the debug log and fix the adapter (cart adapters). |
If none of these fit, capture the [GWP debug] output, the /v1/config response body, and the URL, and send them to us at support@gwpingenuity.com, with [INTEGRATION] in the subject. The widget also reports its own uncaught errors to /v1/error with the message, stack, and the page's origin + pathname (no cart contents, no DOM, no personal data), so we may already be looking at it.
Where next
Section titled “Where next”- Local and staging development: why a dev hostname gives you a half-working install, and the two ways round it.
- Config, CSP and device storage: the response body you are reading in step 2, and the storage keys in step 6.