UserHero Docs
Embedded Portal

Troubleshooting

Common Embedded Portal issues and how to fix them.

Troubleshooting

auth_failed fired immediately

The HMAC handshake was rejected. Common causes:

  • The HMAC was computed over a different string than the one sent. The same exact JSON string used for the digest must be the one passed to the SDK. Re-use the serialized output from JSON.stringify directly.
  • Wrong secret. If you rotated the secret recently, your server may still be using the old one.
  • Clock skew. expiresAt must be in the future. If your server clock is behind, generate Math.floor(Date.now() / 1000) + 300 to give a 5-minute window.
  • Origin not allowlisted. Check Settings → Embedded Portal → Allowed origins.

The portal panel is blank

  • Check the browser console for CSP errors — your site may be blocking userhero.co in frame-src or connect-src. See Allowed origins.
  • Confirm the script tag points to https://userhero.co/portal.js and is loaded with async.

"This site cannot be embedded" error

The browser is enforcing frame-ancestors. Make sure the page where you mount the portal is loaded over HTTPS, and that the parent origin is in your allowlist.

Customers see another customer's tickets

This should never happen. Every API call inside the portal is scoped by the signed identity. If you can reproduce it:

  1. Confirm you're not reusing the same HMAC across users (re-sign per request).
  2. Make sure the user payload contains a unique identifier (externalUserId, email, or phone).
  3. Contact support immediately at hello@userhero.co with reproduction steps.

Theme or CSS variables don't apply

  • Check that the variable name is in the supported allowlist (see Theming).
  • Values containing semicolons, url(), expression(), or @import are silently dropped for security.

"Session expired" message

The signed expiresAt has passed. Listen for the auth_expiring event and re-sign before the timer runs out:

UserHero.on('auth_expiring', async () => {
    const { user, userHmac } = await fetch('/api/userhero-token').then(r => r.json());
    UserHero.setUser(user, userHmac);
});

Still stuck?

Email hello@userhero.co with the public key, the customer's externalUserId, the timestamp of the failure, and any browser console errors.

On this page