Skip to main content

Documentation

Deploy your Gamaro Agent on your site. Script tag or NPM, your choice.

What is a Gamaro Agent?

A Gamaro Agent is a conversational entity you configure in the portal: its business vertical, brand, conversion objectives and data sources. The widget is just how that Agent shows up on your site — a single line of code embeds it.
Gamaro portal
configure your Agent
Agent
vertical · brand · objectives
widget
embed on your site
Visitor

Your data (knowledge base, imported documents) → Agent

Agent → events → Your site · your analytics

The Agent lives in the portal

You configure it once (vertical, brand, objectives). The widget is its display channel, not the Agent itself.

Your data grounds the answers

Import your documents (PDF, TXT, Markdown) into the knowledge base: the Agent refers to them when answering, rather than to an LLM's public training data. Qualification rules and offers are configured in the portal.

The publishable key ties it together

A pk_* key binds the embedded widget to an Agent and its configuration, resolved at load time.

Choose your approach

No build
Quick Integration
CDN script tag, no build required

Ideal for: Static sites, CMSs that accept a script tag (WordPress, Shopify…)

See
NPM build
Framework Integration
NPM package + TypeScript, full control

Ideal for: React, Next.js, Vue

See
No install
Try First
Try the demo without installing

Ideal for: Discovery, evaluation

Try

Your first Agent

From portal to first conversation, no build step.
  1. 1. Create the Agent in the portal

    In /app/portal, create an Agent: give it a name and pick its vertical (real estate, B2B…).

  2. 2. Grab a test key

    Generate a pk_test_* key from /app/portal/api-keys. It works on localhost with no domain configuration.

  3. 3. Embed the widget

    Paste the script tag (below) with your key into a locally-served page. No build step.

  4. 4. Converse

    Open the page: the Agent starts the conversation. Hook the ready or qualified event to react on your side.

Script Tag (CDN)

Add a single line of code to integrate the widget.
<!-- Add this script to your page -->
<!-- Production tip: pin a version + SRI, e.g. @0.2.0 + integrity="sha384-..." -->
<script
  src="https://unpkg.com/@gamaro.io/widget@latest/dist/widget.umd.js"
  data-api-key="pk_your_key"
></script>

Environments: dev → staging → prod

How to test the widget locally then roll it out to production without surprises. Each environment uses a different key and a dedicated domain declaration.

The widget intentionally splits two kinds of publishable keys. A test key (pk_test_*) is designed for local development: it always works on localhost, 127.0.0.1 and *.localtest.me, with zero domain configuration. A live key (pk_live_*) is designed for public environments: it refuses localhost and requires an explicit domain whitelist.

1. Local development

  • Key: pk_test_*
  • Domain: no declaration required — test keys always allow localhost, 127.0.0.1 and *.localtest.me.

Create a test key from /app/portal/api-keys, embed the widget on http://localhost:3000 (or your dev server port), and exercise every feature without touching the Domains page.

2. Staging / preview

  • Key: pk_live_* (dedicated to staging)
  • Domain to declare: https://staging.mysite.com (exact URL of your preview environment)

Create a live key dedicated to staging — never reuse the production key. Add the exact URL of your preview environment in /app/portal/domains. If your staging runs on a custom port (e.g. preview-42.mysite.com:8443), add the full URL with port.

3. Production

  • Key: pk_live_*
  • Domain to declare: https://mysite.com (or wildcard *.mysite.com to cover several subdomains at once)

For a site that serves several subdomains (app, www, checkout…), a *.mysite.com wildcard is more maintainable than multiple exact entries. Note: the wildcard only covers direct subdomains — add mysite.com as an extra entry if the apex domain also serves the widget.

Why split test and live?

A pk_live_* live key refuses localhost even in dev and requires a domain whitelist. This is intentional: if a live key is stolen (leak in a public GitHub repo, compromised browser extension, accidental screenshot), it cannot be used from a local HTML file or from any undeclared third-party site. An attacker who gets the key cannot do anything with it without also controlling one of the domains you explicitly allowed. This is the seat belt that compensates for the key being publicly exposed in your pages' HTML.

Wildcard syntax

A *.mysite.com wildcard matches app.mysite.com, www.mysite.com, checkout.mysite.com — but not mysite.com itself. To cover the apex domain, add it as a separate entry. Wildcards only support one level (*.mysite.com ≠ **.mysite.com): a.b.mysite.com is not matched, you need to add *.b.mysite.com as well.

What happens if the domain is not allowed?

The Gamaro server returns a 403 ORIGIN_NOT_ALLOWED error and the widget stays silent (no chat window opens). Enable the widget's debug option during integration to see the response in the console — it is usually the first thing to check when the widget fails to appear in staging.

NPM + TypeScript

NPM package + TypeScript, full control
npm install @gamaro.io/widget
import { createWidget } from "@gamaro.io/widget";

const widget = createWidget({ apiKey: "pk_your_key" });

// Control the widget
widget.open();
widget.close();
widget.reset();

Configuration

Customize widget behavior with data-attributes. Theme, position and language are now configured from the Gamaro portal and resolved at load time via the publishable key.
OptionTypeDefaultDescription
data-api-keystringrequiredPublishable API key (pk_*) — required, identifies your Agent
data-containerstring-CSS selector for the inline mode container (e.g., '#chat'). The programmatic SDK also accepts a raw HTMLElement.
data-base-urlstringProduction URLBase URL for the embed
data-debugbooleanfalseEnable debug logging
data-emailstring-Pre-identified visitor email (HMAC verification)
data-user-idstring-Host-side unique user identifier (HMAC verification)
data-user-hashstring-HMAC-SHA256 of the userId (or email as fallback), signed with the identity secret

Real-world Examples

Discover integration scenarios adapted to your context.
Real estate showcase site
Floating widget + events → qualified lead by email
ApproachScript tag
ResultLead shown in the portal's lead list, and notified by email when a notification address is configured
Next.js B2B Application
NPM + TypeScript + events
ApproachNPM Package
ResultType-safe integration, app-side reactions to events
E-commerce Marketplace
Inline mode + custom styling
ApproachInline
ResultWidget embedded in your existing design

Display Modes

Choose between a floating or embedded widget.

Floating

The widget appears as a floating button in a corner of the page. This is the default mode — no HTML option required, position is set in /app/portal/widget.

Inline

The widget is embedded directly into a container on your page. Ideal for a contact page or dedicated landing page. Pass a CSS selector via data-container, or an HTMLElement via the programmatic SDK.

import { createWidget } from "@gamaro.io/widget";

// container accepts a CSS selector OR an HTMLElement
const widget = createWidget({
  apiKey: "pk_your_key",
  container: "#chat-container",
});

Multiple Agents on one page

Run multiple widgets on the same page — each one tied to a distinct Agent, with its own vertical.

Script Tags

<!-- B2B qualification widget -->
<script
  src="https://unpkg.com/@gamaro.io/widget@latest/dist/widget.umd.js"
  data-api-key="pk_your_b2b_key"
></script>

<!-- Real estate widget (same page) -->
<script
  src="https://unpkg.com/@gamaro.io/widget@latest/dist/widget.umd.js"
  data-api-key="pk_your_immo_key"
></script>

Programmatic API

import { createWidget } from "@gamaro.io/widget";

// Each API key maps to an Agent with its own vertical, theme, and
// position — all configured from the admin portal.
const b2bWidget = createWidget({ apiKey: "pk_your_b2b_key" });
const immoWidget = createWidget({
  apiKey: "pk_your_immo_key",
  // container pins the widget to a specific DOM node (inline mode).
  container: document.getElementById("demo-immo"),
});

// Access instances after they're ready
b2bWidget.on("ready", () => {
  // window.GamaroApps.get(b2bWidget.applicationId) → GamaroAPI
  console.log("B2B widget ready:", b2bWidget.applicationId);
});

Theming

Match the widget appearance to your brand.

Theming is configured in the portal

Since release 2024.11, theming (colors, typography, border radius, light/dark scheme, position) is managed from /app/portal/widget. The widget resolves these settings at load time via the publishable key — no HTML changes required.

Open portal →

Toggle light/dark at runtime

To sync the widget's color scheme with your host site (user toggle, system preference), use the JavaScript API window.Gamaro.setColorScheme('light' | 'dark' | 'auto').

Data Sources

Connect your product or service data to power the AI conversation. Without a data source, your Gamaro Agent performs conversational profiling.

Gamaro connects to your data via a generic interface. Each source declares its capabilities, and AI tools adapt automatically.

DataSource Interface

The TypeScript interface a data source implements. The implementation is built with the Gamaro team, then deployed server-side.

interface CoverageZone {
  readonly label: string;
  readonly departmentCodes: readonly string[];
  readonly countryCode?: string;
}

interface DataSource {
  readonly id: string;
  readonly configKey?: string;
  readonly displayName: string;
  readonly coverageDescription: string;
  readonly coverage?: CoverageZone;

  getCapabilities(): ReadonlySet<DataSourceCapability>;

  search?(params: Record<string, unknown>): Promise<unknown[]>;
  getStats?(zone: string): Promise<Record<string, unknown>>;
  getAreaMetrics?(zone: string, filters: Record<string, unknown>): Promise<Record<string, unknown>>;
  estimate?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
  count?(areas: string[], filters: Record<string, unknown>): Promise<number>;
  checkCoverage?(zone: string, coverage?: CoverageZone): Promise<{ covered: boolean; message?: string }>;
  listTopCitiesByInventory?(limit: number): Promise<
    Array<{ city: string; count: number; minPrice: number; maxPrice: number }>
  >;
}

Capabilities

Each capability enables one or more AI tools in the conversation.

CapabilityMethodToolsDescription
searchsearch()searchPropertiesSearch items/products with filters
statsgetStats()getCityStatsAggregated statistics by zone
areaMetricsgetAreaMetrics()getAreasOverviewDetailed metrics by zone (overview)
estimateestimate()estimateProperty, estimateRentPrice or value estimation
countcount()getPropertyCountCount with filters
coveragecheckCoverage()checkZoneCoverageZone coverage verification
topInventorylistTopCitiesByInventory()suggestCityCandidatesCities ranked by inventory volume (fallback suggestion)

Implementation example: REST API

An implementation example connected to a REST API, as the Gamaro team would build it with you.

class MyApiDataSource implements DataSource {
  readonly id = "my-api";
  readonly displayName = "Mon API Produits";
  readonly coverageDescription = "Catalogue produit via API REST";

  getCapabilities() {
    return new Set(["search", "count"]);
  }

  async search(params) {
    const res = await fetch(`https://api.example.com/products?${qs(params)}`);
    return res.json();
  }

  async count(areas, filters) {
    const res = await fetch("https://api.example.com/products/count", {
      method: "POST",
      body: JSON.stringify({ areas, filters }),
    });
    const data = await res.json();
    return data.count;
  }
}

Graceful Degradation

When a source only supports certain capabilities, unsupported tools are automatically hidden. Partners don't need to configure anything on the tools side.

search
stats
areaMetrics
estimate
count
coverage
topInventory

Access modes

Gamaro adapts to your infrastructure. The custom mode (DataSource) is offered on request: it is implemented with the Gamaro team, then deployed. Native connectors and standard protocols are being explored.

Native Integrations: connectors to your existing toolsSoon
Custom Mode (DataSource): TypeScript interface, implemented with the Gamaro teamOn request
MCP (Model Context Protocol): expose your data via an MCP serverSoon
A2A (Agent-to-Agent): inter-agent communication for third-party systemsSoon

Identity Verification

When visitors are already logged in on your site, silently verify their identity via HMAC-SHA256 — zero friction, verified leads.

When to use

Identity verification is designed for authenticated areas where visitors are already logged in — SaaS dashboards, client portals, member areas. It is not intended for public marketing pages where visitors are anonymous.

Identity Levels

OptionTypeDefaultDescription
AnonymousCookie / session ID-Default for all visitors — no setup required
IdentifiedEmail shared in chat-Visitor shares their email during conversation
VerifiedHMAC attested by host-Host site cryptographically attests the visitor's identity — zero friction

Step 1: Compute HMAC server-side

The HMAC must be computed on your backend. Never expose the secret in client-side code.

Node.js

import crypto from "node:crypto";

// Sign the stable userId when you have one (recommended), else the email.
// Send data-email and data-user-hash (plus data-user-id when you sign it):
// verification is skipped without data-email.
const signedValue = user.id ?? user.email;
const hmac = crypto
  .createHmac("sha256", process.env.GAMARO_IDENTITY_SECRET)
  .update(signedValue)
  .digest("hex");

Python

import hmac
import hashlib
import os

# Sign the stable user id when you have one (recommended), else the email.
# Send data-email and data-user-hash (plus data-user-id when you sign it):
# verification is skipped without data-email.
signed_value = user.id or user.email
user_hash = hmac.new(
    os.environ["GAMARO_IDENTITY_SECRET"].encode(),
    signed_value.encode(),
    hashlib.sha256,
).hexdigest()

Step 2: Pass identity to the widget

Add the identity attributes to your widget script tag, or use the programmatic API after login.

Script tag

<script
  src="https://unpkg.com/@gamaro.io/widget@latest/dist/widget.umd.js"
  data-api-key="pk_live_..."
  data-email="${user.email}"
  data-user-id="${user.id}"
  data-user-hash="${hmac}"
></script>

Dynamic (post-login)

For single-page apps, identify the visitor after login without reloading the page.

// After user logs in, identify them dynamically
window.Gamaro.identify({
  email: "user@example.com",
  userId: "usr_123",
  userHash: "<computed_hmac>",
});

HMAC Input

The HMAC is computed on userId if provided (stable identifier, recommended), or email as fallback. Using userId means the HMAC stays valid even if the user changes their email.

Security

The identity secret must never appear in client-side code. Generate it in your Gamaro admin dashboard under Settings > Identity Verification.

Events

React to user interactions with events.
OptionTypeDefaultDescription
ready--Widget is loaded and ready
open--Widget was opened
close--Widget was closed
messageWidgetMessage-New message in the conversation
profile-update--User profile was updated (signal only, no profile: the lead shows up in the portal's lead list)
qualified--Lead qualified (signal only, no profile: the lead shows up in the portal's lead list)
funnel-stage-change{ stage, previousStage }-The visitor moved to a new conversion funnel stage
cta-shown{ ctaType, objectiveId? }-The objective's call-to-action button is displayed (once per objective per conversation)
cta-clicked{ ctaType, objectiveId? }-The visitor clicked the objective's call-to-action button
lead-captured{ hasEmail, hasPhone }-A contact was saved (only tells whether an email and/or a phone was given, never the value). Not emitted if the agent's reply fails
quota-warning{ remaining, limit }-API quota is running low
quota-exceeded--API quota has been exceeded
error{ code, message }-An error occurred
identity-verified{ email, userId? }-Visitor identity was verified via HMAC

Usage example

// Subscribe to events
window.Gamaro.on("ready", () => {
  console.log("Agent is ready");
});

window.Gamaro.on("profile-update", () => {
  console.log("Profile was updated"); // signal only, no data
});

window.Gamaro.on("qualified", () => {
  console.log("Lead qualified"); // signal only, no data
  // Lead details: see the Leads page of the Gamaro portal
});

window.Gamaro.on("identity-verified", (data) => {
  console.log("Identity verified:", data.email);
});

window.Gamaro.on("quota-warning", (data) => {
  console.warn("Quota low:", data.remaining, "/", data.limit);
});

window.Gamaro.on("error", (data) => {
  console.error("Error:", data.code, data.message);
});

JavaScript API

Control the widget programmatically via window.Gamaro.
OptionTypeDefaultDescription
open()void-Open the widget
close()void-Close the widget
reset()void-Reset the conversation
setTheme(theme)void-Change theme dynamically
setColorScheme(scheme)void-Toggle the color scheme ('light' | 'dark' | 'auto') — handy for wiring the host site's own theme switch
on(event, handler)void-Subscribe to an event
off(event, handler)void-Unsubscribe from an event
destroy()void-Remove widget and cleanup resources
identify(params)void-Identify a visitor with HMAC verification
versionstring-Current SDK version (read-only)
applicationIdstring""Agent ID (applicationId) resolved after load (empty until ready is emitted)
window.GamaroAppsMap<string, GamaroAPI>-Global map of widget instances — key: applicationId, value: GamaroAPI