Skip to main content
Skip to main content

Reacting to what the widget does

The widget tells your page when something happens inside it. You listen for a normal DOM event and do whatever your site needs — close a panel, route with your own framework, record an analytics hit.

You don’t need any of this. The widget works untouched. These are for the cases where the widget can’t know what your page wants.

How to listen

Every widget event is bubbling and composed, which means it crosses the Shadow DOM boundary and reaches your page. Listen on the element, or on window if the element isn’t in the DOM yet:

<ask-pod-widget id="ask" feed-id="..." api-key="pk_live_..."></ask-pod-widget>

<script>
  document.getElementById('ask').addEventListener('podsaid:navigate', (e) => {
    console.log(e.detail);
  });
</script>

Events are namespaced with podsaid: so they can’t collide with your own.

podsaid:navigate

Fires when a visitor clicks something in the widget that leads to a page — a citation card, the source link on a card, or an inline [1] chip in an answer. It fires before the widget navigates.

e.detail = {
  feedId: 'mdumc-web',
  href: 'https://example.org/worship#:~:text=Communion',
  target: 'same' | 'cross',
  source: 'card' | 'card-link' | 'answer-chip',
  citationIndex: 1
}

target is the field most recipes branch on.

  • same — the href is on your origin. The widget clicks a real link so your router can intercept it. This tab is about to move.
  • cross — the href is somewhere else. The widget opens a new tab, because replacing this page would take the visitor’s conversation with it. This tab stays where it is.

Audio and video citations never fire this. They play inside their card, so nothing navigates.

Recipe: close your panel

If you mount the widget in a slide-out drawer or a modal, a same-origin citation leaves it sitting on top of the page the visitor just asked to see — your router keeps the page alive, and the panel with it. That’s usually what you want for a conversation; it isn’t what you want here.

widget.addEventListener('podsaid:navigate', (e) => {
  if (e.detail.target === 'same') closeDrawer();
});

Check target. On cross the visitor got a new tab and never left your page, so closing the panel would throw away a conversation they’re still in.

Recipe: use your own router

The widget navigates by creating a link and clicking it, because that is what a document-level router listens for. If your framework wants an explicit call instead, cancel the event and make it:

widget.addEventListener('podsaid:navigate', (e) => {
  if (e.detail.target !== 'same') return;   // let new tabs happen normally
  e.preventDefault();                        // we'll handle it
  router.push(e.detail.href);                // Next.js, React Router, etc.
});

preventDefault() stops the widget navigating. Nothing else changes — if you cancel and then don’t navigate, the visitor stays put.

Recipe: send it to analytics

widget.addEventListener('podsaid:navigate', (e) => {
  gtag('event', 'citation_click', {
    feed_id: e.detail.feedId,
    destination: e.detail.href,
    position: e.detail.citationIndex
  });
});

podsaid:chip_click

Fires when a visitor clicks a suggested follow-up question. The widget submits it as a new question either way; this is for measuring how often the suggestions get used.

e.detail = {
  feedId: 'mdumc-web',
  suggestedRewrite: 'What time are Sunday services?',
  variantResolved: 'no_results'
}

Not cancelable.

Notes

These events are additive and stay that way. New fields may appear in detail; existing ones keep their meaning. Read the fields you need and ignore the rest.

A listener that throws won’t break the widget. Dispatch is wrapped, so a bug in your handler can’t strand a click. It can still stop your own recipe from running, so check your console.

Every event also logs to the console with a [podsaid-widget] prefix, which is usually the fastest way to confirm a listener is attached to the right element.