npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@olotalk/assistant-loader

v0.26.0

Published

Embed the [Olotalk](https://olotalk.com) AI chat assistant on any website with a single `<script>` tag, no framework required.

Downloads

1,211

Readme

@olotalk/assistant-loader

Embed the Olotalk AI chat assistant on any website with a single <script> tag, no framework required.

The loader handles config fetching, browser compatibility detection, and dynamic loading of the assistant bundle from the CDN. Your visitors get a grounded, RAG-powered chat assistant that answers questions based on your own content.


Quick start

<script
  src="https://cdn.jsdelivr.net/npm/@olotalk/assistant-loader@0/dist/loader.iife.js"
  data-olotalk-assistant-id="YOUR_ASSISTANT_ID"
  async
></script>

Paste this before </body> on any page. The assistant appears immediately as a floating launcher in the bottom-right corner. The published bundle bakes in https://api.olotalk.com as the default API origin. Self-hosters override with data-olotalk-origin.

Get your assistant ID from the Olotalk dashboard.


Configuration

Via HTML attributes

All attributes are read from the <script> tag itself.

| Attribute | Type | Description | |---|---|---| | data-olotalk-assistant-id | string | Required. Your assistant ID from the dashboard. | | data-olotalk-origin | string | Base URL of your Olotalk API. Optional for Olotalk Cloud (the published bundle defaults to https://api.olotalk.com); set this only when self-hosting the BFF. | | data-olotalk-locale | string | Force a display language. Accepts any well-formed BCP-47 tag (e.g. "en", "fr", "vi", "ja-JP"). When omitted, the loader auto-detects from the visitor's stored preference, the page's <html lang>, then navigator.language, bounded by the assistant's supportedLocales so an unsupported visitor language falls through to the operator's default. | | data-olotalk-mode | string | Which shape to mount (default bubble). One of bubble, starters, inline, drawer, commandk, expand, anchored, fullpage, sidebar, navfield, askbar, selection, corner, center. See Shapes. Read as a plain attribute so a dashboard-generated snippet can carry it. | | data-olotalk-reach | string | Additive triggers over the mounted shape (ADR 0226): comma-separated trigger-capable shape ids (selection, commandk) whose triggers open this mount. data-olotalk-mode="bubble" data-olotalk-reach="selection,commandk" = a corner bubble that also opens from a text highlight and from ⌘K. The assistant owns the vocabulary and warns on unknown ids; the loader passes the string through. | | data-olotalk-selection-answers | string | Where a selection opens the panel: beside (default) flies it to the highlighted words, in-place opens it where the assistant lives, for sites whose assistant is a fixture the visitor has already located. Only affects the selection trigger. Unrecognised values warn and fall back to beside. | | data-olotalk-version | string | Pin a specific published @olotalk/assistant npm version. | | data-olotalk-cdn-base | string | Override the assistant asset base URL (for self-hosting). | | data-olotalk-sandbox-token | string | Test an assistant from your own local/staging app before going live. Paste the sandbox token from the dashboard (Embed → "Test in your own app"). It lets the assistant run on localhost and unlisted staging hosts without allowlisting, un-billed. Never ship it on your production embed. It stops working from your registered live domains anyway. See the Sandbox testing guide. |

Via window.OlotalkConfig

Declare a global config object before the loader script for programmatic setup:

<script>
  window.OlotalkConfig = {
    assistantId: "YOUR_ASSISTANT_ID",
    locale: "fr",
    theme: "dark",
    mode: "inline",
    mount: "#chat-container",
    // origin: "https://bff.example.com", // self-hosted only
  };
</script>
<script src="https://cdn.jsdelivr.net/npm/@olotalk/assistant-loader@0/dist/loader.iife.js"></script>

Full config reference

| Option | Type | Default | Description | |---|---|---|---| | assistantId | string | — | Required. Your assistant ID. | | origin | string | https://api.olotalk.com (cloud build) | Base URL of your Olotalk API. Self-hosters override; the source-level fallback is window.location.origin. | | locale | string | Auto-detected | Force language. Any BCP-47 tag (e.g. "en", "fr", "vi", "ja-JP"). When omitted, the loader uses (in order): visitor's localStorage preference → page <html lang>navigator.language, gated by the assistant's supportedLocales. | | theme | "light" | "dark" | object | "light" | Color scheme or custom theme overrides. | | mode | AssistantMode | "bubble" | Which shape to mount. See Shapes. | | placement | "floating" | "embedded" | "floating" | Deprecated alias for mode: floatingbubble, embeddedinline. Prefer mode. | | mount | string | document.body | CSS selector for the assistant mount point (use with inline, expand, fullpage). | | version | string | matching assistant package version | Pin a specific @olotalk/assistant npm version (e.g. "1.2.3"). When omitted, the loader resolves the published assistant version that matches the loader build, then uses version.json for cache-busting when available. | | cdnBase | string | jsDelivr CDN | Override assistant asset base URL for self-hosting. | | cssUrl | string | Auto-resolved | Override the assistant CSS URL. In a future release this will be provided automatically by the assistant config from the dashboard. | | sandboxToken | string | — | Sandbox test token (dashboard → Embed → "Test in your own app"). Runs the assistant un-billed against your real content on localhost/staging before go-live. Do not ship on production. |


Shapes

One bundle, fourteen mounts, one mode apart. shape-spec.ts in @olotalk/assistant is the source of truth, and a test fails if a live shape is missing here, so this list cannot quietly fall behind the code.

| mode | Where it lands | How it opens | |---|---|---| | bubble | Corner launcher (default) | Its own launcher | | starters | Corner launcher, questions on hover | Its own launcher | | corner | The same corner panel, with nothing at rest | A trigger you place, or reach | | inline | Inside a container in your markup | Always open | | drawer | Full height, flush to an edge, modal | A button you place | | commandk | Centred over a dimmed page, modal | K / CtrlK | | center | The same centred panel, without the ⌘K claim | A trigger you place, or reach | | expand | A line in your copy that unfolds | A trigger you place | | anchored | Beside one element, never covering it | A trigger you place | | fullpage | The assistant is the page | Always open | | sidebar | A fixed rail down one edge | Always open | | navfield | Your own nav field | Your markup submits to it | | askbar | Your own bar at the foot of the page | Your markup submits to it | | selection | Nothing at rest; appears where text is highlighted | The visitor selecting text |

<button data-olotalk-open="drawer">Ask AI</button>

<script
  src="https://cdn.jsdelivr.net/npm/@olotalk/assistant-loader@0/dist/loader.iife.js"
  data-olotalk-assistant-id="ast_xxx"
  data-olotalk-mode="drawer"
  async
></script>

The open panel is a window

Visitors can resize any panel that floats over the page, and drag the anchored one. Neither is configurable: there is nothing to switch on, and nothing an embed can turn off.

| | resize | drag | |---|---|---| | bubble · starters · corner · drawer · commandk · center | ✅ | — | | anchored (select-to-ask, mode: "anchored") | ✅ | ✅ | | inline · expand · fullpage · sidebar | — |, | | any shape at phone width | — |, |

Eight handles: 10px edge bands with 20px corners. Floor 320×360, ceiling the viewport less a margin.

Drag is narrower than resize on purpose. A corner bubble keeps its launcher on screen while open (it morphs into the close control), so moving the panel away would orphan that button. The anchored panel has no such tether and deliberately covers the passage it is about, so moving it is the only way to read the original words.

The chosen size survives a close; the position never does. Press the launcher and the assistant comes back to its corner, at the size the visitor picked. Both gestures are pointer-only.

The in-flow shapes are your layout, so they are left alone entirely.

mobile is not a shape you pick. It is the presentation bubble, drawer, commandk and anchored collapse into at phone width. One embed covers both.

drawer, anchored, navfield and askbar attach to something only you can point at, so a script tag alone is not enough: call Olotalk('open') from your own trigger. Every other shape mounts from the snippet. Full contract in the docs.


JavaScript API

The loader exposes a global Olotalk() command queue. You can call it before or after the script loads.

// Open or close the panel programmatically
Olotalk('open')
Olotalk('close')

// Seed a question from your own control
Olotalk('open', { prefill: 'Do you support SSO?' })

// Change the language, keeping the conversation. Use this, not `init`,
// when your own language switcher does not reload the page: the assistant
// resolves its locale once, at mount, and cannot see a later change.
Olotalk('locale', 'fr')

// Re-initialize with a different config. Rebuilds the assistant, so the
// visitor's open conversation goes with it.
Olotalk('init', { assistantId: 'ast_oltk_…' })

// Remove the assistant from the page entirely
Olotalk('destroy')

Commands queued before the assistant loads are replayed automatically once it is ready.


Error handling

If the assistant can't install, the loader never throws and never renders anything to real visitors. Instead it logs one console.error (prefixed [Olotalk]) that states what failed, the likely cause, and the concrete fix. For programmatic monitoring it also writes the last error to window.__olotalkError and dispatches an olotalk:error CustomEvent:

window.addEventListener('olotalk:error', (e) => {
  const { code, status, hostname } = e.detail;
  // report to your own monitoring
});

detail.code is a stable identifier (the human-readable message may change); detail.status is the HTTP status when there was one.

| code | Meaning | Fix | |---|---|---| | sandbox_token_rejected | A sandboxToken was set but the request was refused (4xx) | Regenerate the token (Embed → "Test in your own app"); confirm it was minted for this assistantId. Do not add the domain to Install domains. That makes traffic live and billed. | | domain_not_allowed | 403, or the client-side allowlist check: this domain isn't in the assistant's allowed domains | Add the domain in the dashboard, or use a sandboxToken if you're testing before go-live. | | assistant_not_found | 404: wrong id, deleted, or not live yet | Verify data-olotalk-assistant-id. If the assistant exists but isn't live, go live or test it with a sandboxToken. | | assistant_unavailable | 410: the assistant was archived or deleted | Reactivate it, or remove the embed. | | config_fetch_failed | Network error or API outage (5xx / unreachable) | Check the origin and that the API is up, then retry. |


Multilingual

The assistant supports any BCP-47 locale out of the box. The operator declares which languages their site ships (supportedLocales) in the dashboard; the runtime handles the rest.

Resolution priority (chrome language)

  1. Explicit data-olotalk-locale / OlotalkConfig.locale
  2. Visitor's previously-accepted choice (localStorage, per assistant)
  3. Page's <html lang>: primary signal on multilingual sites with one URL per language
  4. navigator.language: visitor's browser preference
  5. Operator's defaultLocale from the dashboard

Steps 3 and 4 are gated by supportedLocales: if the operator declares ["fr"], an English-speaking visitor falls through to French chrome (intentional: the site has no English content to ground on).

Adaptive switching

When a visitor types their first message in a different supported language than the current chrome (e.g. a French question on an English assistant configured for both), the bot replies in that language and the assistant surfaces a small inline toast: "Continue in French? · Yes / No". On Yes, the entire chrome flips to French and the choice is persisted to localStorage so the next session opens directly in French.

Static vs LLM-translated locales

| Tier | Locales | Latency | |---|---|---| | Hand-translated | en, fr, de (+ regional aliases) | Zero, bundled | | LLM-translated | Any other BCP-47 (vi, ja, ar, sw, …) | One-time ~1–3s on first load per locale, then cached |

See ADR 0050 for the full design.


Version pinning

By default, the loader fetches the published @olotalk/assistant version that matches the loader build. To override that and lock a specific assistant version:

<!-- Pin assistant bundle to a specific version -->
<script
  src="https://cdn.jsdelivr.net/npm/@olotalk/assistant-loader@0/dist/loader.iife.js"
  data-olotalk-assistant-id="YOUR_ASSISTANT_ID"
  data-olotalk-version="1.2.3"
></script>

Or pin the loader itself by version:

<script src="https://cdn.jsdelivr.net/npm/@olotalk/assistant-loader@0/dist/loader.iife.js" ...></script>

When version is pinned, the loader skips the build-version lookup and loads that exact package version directly.


Asset versioning

When version is omitted, the loader fetches ${base}/version.json with cache: "no-cache" and appends ?v=<buildVersion> to the assistant JS, IIFE, and auto-resolved CSS URLs. This keeps same-page reloads fresh during local development and makes immutable caching safe for self-hosted or CDN-served assistant bundles.

If version.json is unavailable or cannot be fetched, the loader falls back to the unversioned asset URLs.


Self-hosting

To serve assistant assets from your own server instead of jsDelivr:

<script
  src="/path/to/loader.iife.js"
  data-olotalk-assistant-id="YOUR_ASSISTANT_ID"
  data-olotalk-cdn-base="/assets/assistant"
></script>

The loader will fetch olotalk-assistant.js, olotalk-assistant.iife.js, olotalk-assistant.css, and version.json from the provided base URL.

If data-olotalk-cdn-base points to a different origin, version.json must be fetchable with CORS enabled for automatic cache-busting. If not, the loader still works but falls back to the unversioned asset URLs.


npm install

If you are using a bundler or framework, you can import the loader directly:

npm install @olotalk/assistant-loader
import { ensureAssistant } from '@olotalk/assistant-loader'

ensureAssistant({
  assistantId: 'YOUR_ASSISTANT_ID',
  // origin: 'https://bff.example.com', // self-hosted only
})

License

MIT © Olotalk