<!-- Source: https://docs.squirro.com/en/latest/technical/neo/dev-guide/embedding-chat/connect-chat.html -->
# Connecting the Chat to Your Page

Once the chat runs on your page, it can answer about the page that the reader is on, treat links to your site differently, take questions from your own buttons, open documents, and report what happens. For adding the chat, see the [Add the Chat to Your Page](add-chat.md#neo-extensions-embedding-chat-page) page.

## Answer about the Page the Reader Is On

`context` tells the chat what the reader is looking at. The simplest option is to let the chat read the page itself, with `context: 'auto'` in `initNeoSdk()`, or on the element:

```html
<neo-chat base-url="/api/chat" project-id="YOUR_PROJECT_ID" auth="anonymous" context="auto"></neo-chat>
```

With `auto`, each question carries the following:

- The title of the page.
- Its URL, without the query string or `#` part, which often carry tokens or search terms.
- Its description and main text: the first of `[data-neo-context]`, `#main-content`, `main`, `[role=main]`, and `article` on the page that has text in it, else the whole page body.

The chat never reads navigation, headers, footers, forms, form fields, hidden content, text in the shadow root of another web component, or the chat itself. It does read text that is rendered but out of sight, such as `visibility: hidden` or off screen. To keep anything else out, mark it with `data-neo-exclude`:

```html
<div class="account-balance" data-neo-exclude>CHF 12 400</div>
```

A page can opt out entirely with `<meta name="neo-context" content="none">`, or send only its title and URL with `content="title"`. Any other value also sends nothing. To tune what is read, pass options instead of `'auto'`:

```javascript
context: {
  root: '#main-content',
  exclude: ['.cookie-banner'],
  maxLength: 2000,
  url: 'path', // 'canonical' (the default), 'path' or 'full'
},
```

Or write the function yourself. The chat calls it for each question:

```javascript
context: () => ({
  title: document.title,
  url: location.origin + location.pathname,
  text: document.querySelector('main')?.innerText ?? '',
}),
```

The page context goes out with the first question of a conversation, and again only when the reader has moved to another page, a route change in a single-page app included. It becomes part of the conversation stored on your Squirro instance. See the Where Conversations Are Kept section of the [What Readers Share](what-readers-share.md#neo-extensions-embedding-chat-sharing) page.

## Links in Answers

The chat checks every link in an answer before it shows it:

- Only `http`, `https`, `mailto`, and `tel` links are links. Anything else, such as a `javascript:` link that a manipulated document could make the agent write, shows as plain text, and so does a link with a user name or password in it.
- A link is internal when it points at your site: the origin of the page by default, or the origins and URL prefixes in `links.site`, which is `link-site` on the tag. A prefix matches whole path segments only, so `https://example.com/help/` covers `/help/webhooks` but not `/helpdesk`.
- Internal links open in a new tab by default, because a page load ends the conversation. `link-internal="same-tab"` changes that.
- External `http` and `https` links open in a new tab, with a small icon that says so. `link-external="block"` shows them as text instead, for a deployment that must never send readers elsewhere.
- `mailto` and `tel` links open in the same tab, without the icon.

A single-page app routes internal links in place by giving the chat its router, which the chat calls for links on the origin of the page:

```javascript
initNeoSdk({
  // ...
  links: {
    site: ['https://docs.example.com'],
    navigate: ({ path }) => router.navigate(path),
  },
});
```

On a script-tag page, listen for the `neo-chat-link` event on the element, and call `preventDefault()` to take the link over:

```html
<script>
  document.querySelector('neo-chat').addEventListener('neo-chat-link', (event) => {
    if (event.detail.internal) {
      event.preventDefault();
      myRouter.go(event.detail.path);
    }
  });
</script>
```

`callbacks.onLinkClick(link)` is the same hook as a function: return `false` to take the link over. It also suits analytics, since it receives every click except middle clicks.

## Ask from Your Own Buttons

`sdk.ask(text)` sends a question as if the reader had typed it. It resolves when that answer completes, and rejects if the answer fails or the reader stops it. While the chat waits for the reader to approve an action of the agent, it rejects immediately and sends nothing.

A closed floating chat opens first, as with `sdk.open()`. For example, to ask from a button:

```javascript
document.getElementById('explain').addEventListener('click', () => {
  sdk.ask('Explain this page in three sentences').catch(() => {});
});
```

`sdk.newConversation()` starts a fresh conversation.

`sdk` is what `initNeoSdk()` or `NeoSdk.mount()` returned. On a script-tag page, it is also the `sdk` property of the `<neo-chat>` element, which is not set until the chat has started. So read it where you use it:

```javascript
const chat = document.querySelector('neo-chat');
document.getElementById('explain').addEventListener('click', () => {
  chat.sdk?.ask('Explain this page in three sentences').catch(() => {});
});
```

Every method works as soon as the property is set, except `newConversation`, which works only after the `neo-chat-ready` event on the element. That event carries the handle in `event.detail.sdk`:

```javascript
document.querySelector('neo-chat').addEventListener('neo-chat-ready', (event) => {
  event.detail.sdk.newConversation();
});
```

## Open a Document from Your Page

`sdk.openDocument({ itemId })` shows a Squirro document in a full-page overlay in front of your page, and `sdk.closeDocument()` closes it. Readers open the same overlay by clicking a source in an answer. The optional fields are the following:

- `title`, the accessible name of the overlay, announced when it opens.
- `pageNumber`, 1-based, for a PDF.
- `highlightFragments`, the text to highlight. With a `pageNumber`, every match is highlighted, but the viewer stays on that page.

For example, to open page 2 of a report from a button:

```javascript
document.getElementById('open-report').addEventListener('click', () => {
  sdk.openDocument({ itemId: 'the-squirro-item-id', title: 'Q3 report', pageNumber: 2 });
});
```

The overlay covers the whole window, above the floating chat and the fixed header of your site, whatever `z-index` your layout uses. It closes on Escape or from its close button.

The document view is read-only. Open original in its header opens a PDF, a PNG, JPEG, GIF, or WebP image, or a plain text file in a new tab, and downloads any other file, so that a stored file cannot run a script on your site.

If you pass your own `callbacks.onOpenSidePanel`, it replaces that behavior: clicking a source calls your callback, and the overlay does not open. You can still call `sdk.openDocument()` from it.

PDF documents use the Nutrient viewer, which your proxy serves together with its license key, so the page needs no key. See the Serve the PDF Viewer section of the [Set Up the Proxy](set-up-proxy.md#neo-extensions-embedding-chat-proxy) page. Use one `pdfViewer` setting per page, because the viewer keeps the first one for the whole page.

## Listen to What Happens

`events` reports what the chat does, for analytics or for your own UI. The `onConversationStarted`, `onQuestionSent`, and `onAnswerCompleted` events carry the ID of the conversation, so leave it out of what you send to analytics. See the [What Readers Share](what-readers-share.md#neo-extensions-embedding-chat-sharing) page.

For every event, see the Events section of the [Configuration Reference](configuration-reference.md#neo-extensions-embedding-chat-configuration) page.

For example, to count completed answers and their sources:

```javascript
events: {
  onAnswerCompleted: (event) => {
    if (event.reason === 'completed') {
      analytics.track('chat_answer', { sources: event.sources.length });
    }
  },
},
```
