We’ve migrated our documentation to a new site, which means some URLs have changed.
Subscriptions

How do I troubleshoot content recommendation widgets in Composer?

How the Widget Renders (and Why It Sometimes Hides)

On page load, the recommendation widget requests data from Piano. In most implementations you'll see an XHR/Fetch request similar to:

/public/widget/data?...moduleId=

Common behaviors:

  • If the JSON payload returns an empty array (for example, "items":[]), the module typically suppresses itself (often by applying display:none).

  • If the request fails (40x/50x), the module also won't render.

  • If required scripts don't load or are blocked, the widget container/iframe may remain empty.

Check the Widget Data Request in the Browser

  1. Open the affected page.

  2. Open Developer Tools → Network.

  3. Filter by Fetch/XHR and reload.

  4. Find the request ending in /public/widget/data.

Interpret what you see:

What You See

What It Usually Means

Next Step

200 OK with "items":[]

No eligible content returned (indexing, filters, targeting variables, consent)

Continue to this section

40x/50x error

Request is failing (integration, script, environment, or blocking)

Continue to this section

No /public/widget/data call at all

Widget never initialized or scripts/experience didn't execute

Continue to this and this section

Verify Content Supply

If "items":[], first confirm the underlying content exists and is indexed.

Confirm the Article Is Indexed

Use the document search endpoint to check a specific URL:

/document/search?url=

If you get 0 results, the crawler likely did not index the page correctly (or indexed the wrong content).

Common Indexing Blockers

  • CMP/cookie banner blocking the crawler: The crawler may fetch the consent layer instead of the article body. Whitelist the Piano crawler in your CMP and any relevant firewall policies.

  • Missing or incomplete publish time metadata: Ensure is present and includes a complete time value (date plus hour/minute).

  • Canonical/URL conflicts or duplicates: Missing or inconsistent canonical information can cause duplicate filtering or mismatches. Ensure canonical URL signals are consistent (for example, , og:url, and cXenseParse:url if used).

  • Domain not live or not properly configured: If the domain isn't live or correctly configured in Piano, content may not be available for modules.

Required/Commonly Used Metadata

Ensure these are accurate and stable across templates:

XML
<meta name="cXenseParse:url" content="https://www.example.com/path/to/article"/>
<link rel="canonical" href="https://www.example.com/path/to/article"/>
<meta property="article:published_time" content="2026-02-12T08:30:00+00:00"/>

After fixing metadata or CMP blocking, republish affected articles or request a recrawl. Some changes appear quickly, but broader crawling updates can take longer (up to approximately a day in some cases).

Confirm the Core Recommendation Scripts Load

Recommendations are delivered via cx.cce.js (which loads/uses cx.js). If those scripts don't load, widgets can't render.

What to Check

  • In the Network tab, confirm cx.cce.js and cx.js are requested and return 200.

  • Look for blocked requests (for example, (blocked) or net::ERR_BLOCKED_BY_CLIENT), which often indicates an ad blocker or CMP policy.

Ensure Site ID Is Set

Your Piano snippet should include the Site ID call before recommendations execute:

tp.push(["setCxenseSiteId", "YOUR_SITE_ID"]);

Testing Script Loading Directly

In some debugging scenarios you can explicitly include the script:

HTML
<script type="text/javascript" async="async" src="https://cdn.cxense.com/cx.cce.js"></script>

If explicitly including it "fixes" the issue, investigate script loading order or conflicts that prevented Piano from loading it automatically.

Consent can block recommendations in two ways:

  • The CMP can block loading of recommendation scripts/domains.

  • Consent state can suppress recommendation delivery.

Key points:

  • If the recs consent class is rejected, personalized recommendations are suppressed.

  • If the pv consent class is rejected, it can implicitly reject other classes (including recs) and prevent recommendations from loading.

To verify consent state, run the following in the browser console:

tp.consent.getState()

Confirm pv and recs are accepted for the sessions where the widget fails (including after login, if applicable).

Check Widget/Collection Configuration

If the widget request succeeds but returns no items, validate the content source and filters:

  • Confirm the widget is linked to a non-empty collection.

  • Confirm a template is assigned to the widget (where applicable).

  • Temporarily relax or remove filters to test:

    • Max publish age (commonly too strict)

    • Segment/visitor filters

    • Any required field constraints (for example, image-required logic, tags, etc.)

  • If using slot/override logic, ensure at least one slot points to the intended non-override/normal collection.

Confirm your site actually has enough eligible published content within the configured age window (often "last ~90 days" is used as a quick sanity check).

Ensure Targeting Variables Are Available Before Piano Initializes

Inconsistent display can be caused by timing/race conditions: variables used for targeting are not defined when Piano evaluates the experience/widget.

Typical symptoms:

  • Works on refresh but not on first load

  • Works for some users but not others

  • "items":[] intermittently

What to do:

  • Ensure variables (for example, logged-in flags or other custom targeting values) are defined synchronously before the Piano bootstrap runs.

  • Place required meta tags and tp.push(...) calls in the HTML (not after an AJAX call).

Diagnose Composer Execution

If there's no widget data request — or the widget is present in HTML but never executes — verify the experience is actually evaluated and allowed to run.

Use Composer Debug Mode

Append to the URL:

?xpdebug=true

Then:

  • Look for experience evaluation/execution logs.

  • Check network calls (for example, experience execution responses) to see whether targeting rules excluded the visitor/page.

Action Exclusivity Manager

If you use Action Exclusivity, confirm it isn't preventing the widget action from running. Adjust exclusivity rules or priority to allow the recommendation action to execute.

Check for JavaScript Errors and Template Robustness

Console errors can prevent rendering even when data is available.

Common causes:

  • Custom rendering template errors (for example, "Error executing custom rendering template code"):

    • Example: calling .trim() on a value that is sometimes not a string.

    • Fix: add type/exists checks before using fields.

  • Third-party library conflicts:

    • For example, some sites have seen conflicts where a third-party script interfered with cx.js.

    • Isolation test: temporarily disable recent/optional scripts (or load them only where needed) and re-test.

Special Cases

10.1 Signed-In Users Only

If recommendations fail only after login:

  • Re-check consent after authentication (ensure pv and recs remain accepted).

  • Check for post-login JavaScript errors or scripts that only load for authenticated sessions.

  • Confirm targeting variables specific to logged-in users exist before Piano initializes.

Empty Iframes

If you see recommendation iframes but they're empty:

  • Confirm cx.cce.js is not blocked by the browser/CMP/ad blocker.

  • Check for console exceptions related to widget rendering/template execution.

  • If many widgets load at once, test reducing concurrency and consider lazy-loading.

Missing DOM Targets

If using multi-widget rendering (for example, showPianoMultiRecos), ensure all targetElementIds exist in the DOM at the time the function runs—missing target elements will result in no visible widget.

After You Apply Fixes

  1. Re-test the page and confirm /public/widget/data returns a non-empty "items" array.

  2. Confirm cx.cce.js / cx.js load successfully.

  3. If indexing/crawler-related changes were made, republish a representative article or request a recrawl and re-check /document/search .

If problems persist, capture the following and contact Piano Support:

  • The /public/widget/data request/response (status + payload)

  • Console errors

  • Consent state from tp.consent.getState()

  • A sample affected article URL and its /document/search?url=... result

Last updated: