Skip to content
GitHub
Get started →

Widget conflicts with site CSS/JS

The widget is designed to be immune to your site’s CSS and JS. It renders inside a Shadow DOM and mounts its event listeners directly to its own root. In practice that works 99% of the time.

The 1% where it doesn’t usually falls into one of these categories.

CSS z-index wars

The orb renders at z-index: 2147483647 (the max). If the orb is hidden behind something, that something is ALSO at max z-index — usually a modal, cookie banner, or intercom-style chat widget from another vendor.

Diagnose: DevTools → Elements → right-click the obscuring element → Show in CSS → look for z-index.

Fix:

  • The other tool probably offers a lower z-index setting — lower theirs
  • Or move the orb to a different position (bottom-left if the chat is bottom-right) — see Appearance
  • Worst case: set the other tool’s z-index below max via a !important override in your CSS

Shadow DOM rendering oddities

Some CSS frameworks try to style all elements on the page via broad selectors (* { box-sizing: border-box }, Tailwind’s preflight, Bootstrap resets). The widget’s Shadow DOM shields it, so these shouldn’t affect the widget.

If you see the orb looking wrong (weird sizes, missing glow), something is penetrating the shadow boundary — usually custom properties (CSS variables) or @font-face rules that are inherited. Inspect with DevTools → the orb’s root in the Shadow DOM — check computed styles for unexpected values.

Fix: the widget handles most of this automatically. If you find a specific conflict, file an issue.

Fixed-position containers that cover the orb

Fullscreen video players, modal overlays, and some hero components use position: fixed with a z-index above the orb. These intentionally take over the viewport and you probably want the orb hidden while they’re up.

Fix: Use disabled pages on routes where fullscreen modes dominate, or toggle the orb’s visibility via CSS:

body.video-fullscreen spelo-widget {
display: none !important;
}

The widget exposes itself as the <spelo-widget> custom element.

Router interference

Some routers (old Angular UI-Router, custom hash-based routers) use patterns the widget doesn’t auto-detect. If the orb doesn’t update after a route change, the widget’s pushState hook may have been bypassed.

Diagnose: Open DevTools Console, trigger a route change, and check if [Spelo] route change: appears. If not, the widget missed it.

Fix: Dispatch a spelo:route-change event manually after your custom routing:

window.dispatchEvent(new CustomEvent('spelo:route-change', {
detail: { url: window.location.pathname }
}))

The widget listens for this and re-reads the DOM.

Blocked by tracking / ad blockers

Aggressive ad blockers (uBlock with filter lists, Brave’s default shields) sometimes categorize third-party scripts as “trackers” and block spelo.ai.

Diagnose: Open the page with a private / incognito window with no extensions. If the orb appears, it’s an extension blocking.

Fix: Not much you can do about user-installed blockers. We don’t set any tracking cookies, but the heuristic-based blockers don’t know that. Some users will have to whitelist your domain.

Conflict with Intercom, Drift, Zendesk, HubSpot

Multiple chat widgets at bottom-right will overlap. Solutions:

  • Move the orb to bottom-left or bottom-center
  • Disable the orb on pages where the support chat is primary
  • Open a support ticket with the other tool to coordinate positioning

jQuery 1.x global pollution

Sites still on jQuery 1.x sometimes monkey-patch window.$ or Element.prototype.querySelector in ways that break modern code. The widget uses vanilla DOM APIs and should be immune, but if you’re on jQuery 1.x and see issues, consider upgrading to jQuery 3.x.

CSP violations

If your CSP is very strict (strict-dynamic, nonce-based), external scripts can break. See Orb not appearing → CSP.

Service workers that intercept fetch

Some PWAs intercept every fetch() via service worker and may inadvertently block requests to api.spelo.ai.

Diagnose: DevTools → ApplicationService Workers → check the active SW. In Network, requests with “(ServiceWorker)” next to them are passing through.

Fix: Your service worker should pass through Spelo requests untouched:

self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url)
if (url.hostname === 'api.spelo.ai' || url.hostname === 'spelo.ai') {
return // let the browser handle it directly
}
// ... your other caching logic
})

A/B testing tools (Optimizely, VWO)

These sometimes wrap document.body or rewrite the DOM in ways that break script tag evaluation. If the orb only fails with A/B testing on, exclude spelo.js from their rewrite logic.

Performance profilers (New Relic, Datadog RUM)

Usually fine, but some RUM tools wrap WebSocket and RTCPeerConnection for instrumentation. That can break WebRTC in rare cases. Disable their instrumentation for api.spelo.ai / api.openai.com.

Hard-case debugging

If you’ve tried the above and still see an issue:

  1. Open the site in Chrome with all extensions disabled
  2. DevTools → ConsolePreserve log on
  3. Click the orb, try to speak, observe what fails
  4. Copy the full console output
  5. Email support@spelo.ai with the output + a URL to reproduce

For enterprise plans, we’ll schedule a screen-share debug.

See also