> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nextintent.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# The card and the event

> How a sentence reaches the page: the card route, the poll, the ack, the nextintent:moment event for your own rendering, and the popup-tool hooks.

When the engine decides to speak, it places one card in a short-lived queue for that visitor. The page collects it with a small poll and reports what happened. You can let NextIntent's card snippet render it, render it yourself from a browser event, or hand it to a popup tool.

## The card route

```
GET  https://sdk.nextintent.ai/SITE_ID/card?user_id=VISITOR_ID
POST https://sdk.nextintent.ai/SITE_ID/card/ack
```

`GET /card` answers `200 { card }` exactly once while a card is waiting, then `204` until another is placed. The card is read with a single atomic take, so a refresh cannot show it twice. A card waits three minutes; a visitor who left never sees a stale one. Both routes are origin-gated.

The card object:

```json theme={null}
{
  "card": {
    "id": "c_8f1e...",
    "decision_id": "d_2b7c...",
    "text": "Add the Camp Mug ($18) and shipping is free.",
    "cta_label": "See the Camp Mug",
    "cta_path": "/products/camp-mug"
  }
}
```

`cta_path` is always a same-origin path; the engine never emits an absolute URL. `cta_label` and `cta_path` are null when there is no link.

## The ack

```json theme={null}
POST /SITE_ID/card/ack
{ "user_id": "...", "card_id": "c_8f1e...", "decision_id": "d_2b7c...", "event": "shown", "page": "https://..." }
```

`event` is one of `shown`, `clicked`, `dismissed`. Send `shown` when the sentence is on the screen. This is the report that makes the visitor count as spoken to; without it, no order can be credited to the moment. Send `clicked` when the link is followed and `dismissed` when the visitor closes it.

## The poll

The reference snippet starts 12 seconds after the visitor id is known, polls every 6 seconds while the tab is visible, backs off, and stops after 15 minutes or once a card has been delivered. It remembers delivery in `sessionStorage` so a visitor sees one card per session. Follow the same shape if you write your own: never poll a hidden tab, never poll after delivery.

## Getting the visitor id

The SDK keeps the visitor id in the frame it opened from `iframe.nextintent.ai`. Ask the frame with `postMessage({ action: 'find', source: '<nsp>/user_id', id, channel }, ...)` where `nsp` and `channel` come from the frame's `src` query string; the reference snippets show the exact exchange. Accept replies only from `https://iframe.nextintent.ai`.

## The event

Whatever the output setting, the reference snippet fires a DOM event when a card is delivered:

```js theme={null}
window.addEventListener('nextintent:moment', function (e) {
  // e.detail = { id, text, cta_label, cta_path }
});
```

With `output` set to `event` in the facts sheet, nothing is drawn and the snippet sends `shown` as soon as the event fires; your listener owns the rendering. With `output` set to `card`, the event still fires and the card is drawn.

## Popup tools

With `output` set to `popup`, the snippet reads `window.NextIntentOutput = { provider, campaign_id, code_campaign_id }` from the page and asks the tool to show that campaign: OptiMonk (`OptiMonk.Api.campaigns.show`), Justuno (`juapp('trackFunnel', 'nextintent:' + id)`), Privy (`Privy('show', id)`), Wisepops (`wisepops('event', 'nextintent:' + id)`), Klaviyo (`_klOnsite.push(['openForm', id])`). `code_campaign_id` is used when the card is about a declined code. If the tool is absent or refuses, the snippet falls back to its own card.

## Rendering your own card

Keep three rules: put the text in with `textContent` (never HTML), accept `cta_path` only when it starts with `/`, and send the `shown` ack when the element is on the screen. The sentence must never be shown twice in a session.

## Related

* [Install the SDK](/api/install-sdk)
* [The facts sheet](/api/facts-sheet)
* [What shoppers see](/shopify/how-it-works/what-shoppers-see)
