Widgets — Hanc.AI
5 Formen1 Script-Tag14 Sprachen

Ein Sprachagent auf Ihrer Seite.
Ein Tag, kein Backend.

Fünf Web-Komponenten, mit denen Besucher mit Ihrem Agenten sprechen — laut, im Browser, ohne Installation. Das Gespräch läuft über WebRTC, die Antwort kommt in etwa einer Sekunde, und der Agent kann Seiten öffnen und lesen, was auf dem Bildschirm steht.

Diese Sphäre ist das Widget. Drücken und sprechen.

Fünf Formen

Wählen Sie die Form, die die Seite braucht

Derselbe Agent, fünf Wege zu ihm. Kombinieren Sie frei — zwei Tags mit einer agent-id sind ein ganz normaler Aufbau.

Inline-Sphäre

Inline-Sphäre

370 px standardmäßig, im Fluss der Seite. Geben Sie ihr die Breite, die Sie wollen; auf schmalem Bildschirm verkleinert sie sich selbst.

<hanc-ai-inline-call>

Ein Abschnitt auf einer Landingpage, eine Kontaktseite — überall dort, wo das Gespräch der Sinn des Blocks ist.

Schwebende Sphäre

Schwebende Sphäre

120 px, fix 32 px von der Ecke rechts unten. Drei weitere Ecken zur Wahl, oder static, um sie in den Fluss zu setzen.

<hanc-ai-floating-call>

Von jeder Seite erreichbar, ohne Platz im Layout zu belegen.

Pill

Pill

Ein horizontaler Button: links eine 48-px-Sphäre, rechts Ihre eigene Beschriftung. Steht im Fluss wie jeder andere Button.

<hanc-ai-pill-call>

In einer Button-Reihe, im Header, in einer Karte.

Schwebende Pill

Schwebende Pill

Derselbe Button, fix 32 px von der Ecke rechts unten. Dieselben vier Ecken zur Wahl.

<hanc-ai-pill-floating-call>

Wenn eine runde Sphäre zu viel Aufmerksamkeit zieht, sie aber trotzdem immer griffbereit sein soll.

Rückruf-Formular

Rückruf-Formular

Länderauswahl, eine Nummer, die beim Tippen formatiert wird, und ein Button. Wie oft es erneut versucht wird, steht am Agenten, nicht im Markup.

<hanc-ai-callback>

Für alle, die nicht über den Browser sprechen — und für jede Lage, in der ein Mikrofon unpassend ist.

Fünf Minuten

Einbinden

Ein Pflichtattribut: die Agent-ID aus Ihrem Dashboard. Ein API-Schlüssel gehört nicht ins Markup — alles im HTML ist für Besucher sichtbar.

  1. 1

    Agent-ID holen

    Eine Zeichenfolge wie 69d20781de6244c89509eb08, aus dem Dashboard.

  2. 2

    Script einbinden

    Eine Zeile im <head>. Über npm ist es ein Import — die Tags registrieren sich selbst.

  3. 3

    Tag platzieren

    Dort, wo das Gespräch hingehört. Pflicht ist nur agent-id.

  4. 4

    Über HTTPS ausliefern

    Browser geben auf http:// kein Mikrofon frei. Beim Entwickeln funktioniert localhost.

index.html
<!-- 1. the script, once, in <head> -->
<script src="https://unpkg.com/hanc-webrtc-widgets" async></script>

<!-- 2. the widget, wherever the call belongs -->
<hanc-ai-inline-call
  agent-id="69d20781de6244c89509eb08"
  size="320"
  theme="tangerine"
  button-start-text="Talk to us">
</hanc-ai-inline-call>
1 script tag 0 dependencies WebRTC

React

Unter v19 werden unbekannte Props als Strings übergeben, Objekte lassen sich so nicht durchreichen. Mit @lit/react umschließen — der offizielle Weg, inklusive Typisierung und Events.

Next.js

Das Widget braucht einen Browser: 'use client' und ein dynamischer Import mit ssr: false. Sonst bricht der Build beim Server-Rendering ab.

Vue

Funktioniert ohne Wrapper. Sagen Sie dem Bundler, dass hanc-ai- Tags Custom Elements sind.

Es steuert die Seite

Der Agent kann Seiten öffnen und lesen, was auf dem Bildschirm steht

Eine gesprochene Antwort ist oft das falsche Medium — niemand will eine Liefertabelle vorgelesen bekommen. Deshalb kann der Agent der Seite einen Befehl schicken und die Seite fragen, was der Besucher gerade ansieht. Die Kontrolle bleibt bei Ihrem Code: er entscheidet, was er ausführt.

Hanc.AI
navigate
page_context
cart_state
Das Widget
navigate

Der Agent öffnet eine Seite bei Ihnen — ein Produkt, einen Abschnitt, ein bereits ausgefülltes Formular.

page_context

Die Seite antwortet, wo der Besucher ist und was gezeigt wird, damit der Agent über dieses Produkt spricht statt allgemein.

cart_state

Die Seite antwortet, was im Warenkorb liegt und was es kostet, damit der Agent die Summe laut nennen kann.

Jeder Befehl kommt als abbrechbares agent-command DOM-Event an. preventDefault() bedeutet „erledigt“; respond(data) schickt eine Antwort zurück an den Agenten. Wird ein Event ignoriert, erfährt der Agent, dass es nicht bearbeitet wurde, und weicht auf Sprache aus.

Befehle sind Bitten, keine Anweisungen — prüfen Sie jeden Pfad, bevor Sie ihm folgen. Das Beispiel verweigert alles, was kein seiteninterner Pfad ist.

widget.js
widget.addEventListener('agent-command', (event) => {
  const command = event.detail;

  if (command.type === 'navigate') {
    const path = command.payload?.path;
    // Only same-site paths. Never follow an absolute URL.
    if (!path?.startsWith('/') || path.includes('://')) return;
    event.preventDefault();          // "handled" — the ACK protocol
    router.push(path);
  }

  if (command.type === 'cart_state') {
    event.preventDefault();
    command.respond({                // answer travels back to the agent
      items: cart.map(i => ({ name: i.name, price: i.price })),
      total: cart.total,
      currency: 'UAH',
    });
  }
});

Live auf

milotec.com.ua

Der Agent führt Besucher zu einem Produkt, erzählt, was auf der aktuellen Seite steht, und liest den Warenkorb vor.

Mobile Apps

Dasselbe Widget in Ihrer App

iOS und Android zeigen es beide in einer Web-View. Bauen Sie eine kleine HTML-Seite im Code und laden Sie sie mit HTTPS-Basis — ohne sicheren Ursprung gibt die Engine der Seite kein Mikrofon.

Der Agent ist nicht zu hören

Eine Web-View gibt kein WebRTC-Audio aus, solange die Audio-Session der App auf Playback steht. Schalten Sie sie für die Dauer des Gesprächs auf einen Gesprächsmodus mit Lautsprecher und danach zurück.

Der Agent antwortet in der falschen Sprache

Das Widget nimmt die Sprache aus navigator.language, und das ist in einer Web-View die Systemsprache, nicht die in Ihrer App gewählte. Überschreiben Sie sie beim Dokumentstart — und patchen Sie fetch, um browser_language an die Raum-Anfrage anzuhängen, was das eingebettete Widget von sich aus nicht sendet.

Das Mikrofon braucht beide Hälften

Die Systemberechtigung für die App und die Berechtigung für die Seite in der Web-View. Auf Android vor dem Öffnen des Bildschirms anfragen, auf iOS die Anfrage der Seite im Delegate freigeben.

Dasselbe Widget in Ihrer App
Live in der RunOrJog-App
SupportView.swift
let html = """
<hanc-ai-inline-call
    agent-id="\(agentId)"
    support-session-token="\(sessionToken)"></hanc-ai-inline-call>
<script src="https://unpkg.com/hanc-webrtc-widgets" async></script>
"""

// An HTTPS base is required — without a secure origin
// the engine will not hand the page a microphone.
webView.loadHTMLString(html, baseURL: URL(string: "https://hanc.ai"))
Wer am Gespräch teilnimmt

Lassen Sie den Agenten den angemeldeten Nutzer sehen — und nur ihn

Übergeben Sie ein Token in support-session-token. Das Widget hängt es unverändert an das Gespräch, wir reichen es im Header X-Hanc-Support-Token an Ihr System weiter, und Ihr MCP-Server entscheidet, wer das ist. Für uns ist das Token undurchsichtig: wir zerlegen, prüfen und speichern es nicht.

Ihre App
Das Widget
Hanc.AI
Ihr MCP
Ihre Daten

Vertrauen Sie niemals einer Kennung, die als Behauptung im Token ankommt. Fragen Sie den Aussteller des Tokens, wer das ist, und arbeiten Sie mit der Antwort.

AnsatzFälschbarBewertung
Offene Nutzer-IDTrivialNicht akzeptabel
Verschlüsselte Nutzer-IDNein — aber wiederverwendbarHalbe Lösung
Token Ihres Login-AnbietersNein: der Anbieter signiertFunktioniert
Einmal-Ticket vom ServerNein, und auch nicht wiederverwendbarAm besten

Aktivieren Sie an der Verbindung „identifizierter Anrufer erforderlich“, und bei einem anonymen Gespräch werden Ihre Tools gar nicht erst hochgefahren — der Agent kann nichts über ein fremdes Konto sagen, selbst wenn sich später ein Fehler in Ihren Code einschleicht.

Ein Gespräch ohne Token bekommt überhaupt keinen Kontozugriff. Das ist der Standard, keine Option.

your_mcp_server.py
async def verified_user_id(ctx) -> str:
    token = ctx.request.headers.get("x-hanc-support-token", "").strip()
    if not token:
        raise ValueError("No signed-in user on this call.")

    # Ask the issuer who this is. Never read the id out of the token.
    resp = await http.get(f"{AUTH_URL}/auth/v1/user",
                          headers={"Authorization": f"Bearer {token}"})
    if resp.status_code != 200:
        raise ValueError("Token invalid or expired.")

    return resp.json()["id"]        # ← the trusted identity
Erscheinungsbild

Es soll wie Ihre Seite aussehen, nicht wie unsere

Elf Themes, hell und dunkel nach Systemeinstellung oder erzwungen, und rund fünfzehn weitere Attribute für die Sphäre selbst.

default
emerald
rose
amber
cyan
purple
blue
white
black
tangerine
ember
AttributWofürStandard
agent-id Welcher Agent antwortet. Das einzige Pflichtattribut
theme Eines von elf Farbthemes default
size Größe in Pixeln; verkleinert sich auf schmalen Bildschirmen selbst 370
button-start-text Die Beschriftung des Buttons Try to call
position Ecke für die schwebenden Formen bottom-right
glow-intensity Stärke des Leuchtens, 0–2 0.8
audio-reactivity Wie stark die Sphäre auf die Stimme reagiert 3.0
terms-enabled Einwilligungsfenster vor dem Gespräch false
sound-enabled Töne am Anfang und Ende true
support-session-token Token des angemeldeten Nutzers

Events für Ihren eigenen Code

Keines der beiden Events trägt Daten: beide sind ein einfaches Event, Sie erhalten also die Tatsache und den Zeitpunkt. Gesprächsinhalte stehen in keinem von beiden — Transkripte und Aufnahmen liegen im Dashboard und in der API.

Klare Antworten

Was schützt und was nicht

Der Kanal ist verschlüsselt

Steuer-Anfragen über HTTPS, Audio über WSS und SRTP. Ohne HTTPS gibt der Browser ohnehin kein Mikrofon frei.

Der Agent wird geprüft

Ein Gespräch wird nur für eine existierende Agent-ID aufgebaut.

Zugriff ist ratenbegrenzt

Die Vergabe von Gesprächszugängen ist gedrosselt — gegen Brute Force und Missbrauch.

Das Session-Token bleibt nicht liegen

Es wird bei jedem Gespräch neu gelesen und nie in unsere Datenbank geschrieben.

Die Liste erlaubter Domains ist keine Sicherheitsgrenze

Diese Prüfung läuft im Browser. Sie ist nützlich, damit das Widget nicht versehentlich auf einer fremden Kopie Ihrer Seite startet, hindert aber niemanden daran, den Dienst direkt aufzurufen. Behandeln Sie alles, was der Agent einem anonymen Gegenüber erzählen würde, als öffentlich, und sichern Sie den Rest mit einem Session-Token.

Was wo bleibt

Im Browser

Zwei Einträge im localStorage: eine Besuchermarkierung und die erteilte Einwilligung

Audio

Als Stream. Aufgezeichnet nur, wenn die Aufnahme für den Agenten aktiviert ist

Transkript

Wird mit der Aufnahme gespeichert und ist im Dashboard einsehbar

Standort

Verarbeitung und Speicherung in der EU

Grenzen, die man vorher kennen sollte

Kein Mikrofon ohne HTTPS

Auf localhost oder einer sicheren Domain testen

Safari will eine Geste vor dem Ton

Das Gespräch muss per Klick starten

Blocker und Proxies können WebRTC abschneiden

Das Rückruf-Formular als Ausweichweg lassen

Im privaten Fenster bleibt keine Markierung

Jedes Gespräch wirkt wie das erste — das ist normal

React unter 19 kann keine Objekte als Attribut übergeben

Mit @lit/react umschließen

Server-Rendering bricht beim direkten Import ab

Dynamischer Import mit ssr: false

Ihr Telefon, das endlich
für Sie arbeitet.

In 60 Sekunden kostenlos starten. Keine Kreditkarte. Jederzeit kündbar. Das Telefon nimmt sich selbst ab.

Kostenlos starten
Termin buchen