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.
Diese Sphäre ist das Widget. Drücken und sprechen.
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.
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.
-
Inline-Sphäre
<hanc-ai-inline-call>370 px standardmäßig, im Fluss der Seite. Geben Sie ihr die Breite, die Sie wollen; auf schmalem Bildschirm verkleinert sie sich selbst.
Ein Abschnitt auf einer Landingpage, eine Kontaktseite, überall dort, wo das Gespräch der Sinn des Blocks ist.
-
Schwebende Sphäre
<hanc-ai-floating-call>120 px, fix 32 px von der Ecke rechts unten. Drei weitere Ecken zur Wahl, oder
static, um sie in den Fluss zu setzen.Von jeder Seite erreichbar, ohne Platz im Layout zu belegen.
-
Pill
<hanc-ai-pill-call>Ein horizontaler Button: links eine 48-px-Sphäre, rechts Ihre eigene Beschriftung. Steht im Fluss wie jeder andere Button.
In einer Button-Reihe, im Header, in einer Karte.
-
Schwebende Pill
<hanc-ai-pill-floating-call>Derselbe Button, fix 32 px von der Ecke rechts unten. Dieselben vier Ecken zur Wahl.
Wenn eine runde Sphäre zu viel Aufmerksamkeit zieht, sie aber trotzdem immer griffbereit sein soll.
-
Rückruf-Formular
<hanc-ai-callback>Länderauswahl, eine Nummer, die beim Tippen formatiert wird, und ein Button. Wie oft es erneut versucht wird, steht am Agenten, nicht im Markup.
Für alle, die nicht über den Browser sprechen, und für jede Lage, in der ein Mikrofon unpassend ist.
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.
- Agent-ID holen Eine Zeichenfolge wie 69d20781de6244c89509eb08, aus dem Dashboard.
- Script einbinden Eine Zeile im <head>. Über npm ist es ein Import, die Tags registrieren sich selbst.
- Tag platzieren Dort, wo das Gespräch hingehört. Pflicht ist nur agent-id.
- Über HTTPS ausliefern Browser geben auf http:// kein Mikrofon frei. Beim Entwickeln funktioniert localhost.
<!-- 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> -
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.
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.
-
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.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',
});
}
}); 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.
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"))
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.
| Ansatz | Fälschbar | Bewertung |
|---|---|---|
| Offene Nutzer-ID | Trivial | Nicht akzeptabel |
| Verschlüsselte Nutzer-ID | Nein, aber wiederverwendbar | Halbe Lösung |
| Token Ihres Login-Anbieters | Nein: der Anbieter signiert | Funktioniert |
| Einmal-Ticket vom Server | Nein, und auch nicht wiederverwendbar | Am besten |
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 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.
Es soll wie Ihre Seite aussehen, nicht wie unsere
11 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
| Attribut | Wofür | Standard |
|---|---|---|
agent-id | Welcher Agent antwortet. Das einzige Pflichtattribut | |
theme | Eines von 11 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.
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.