Widget reference
<script src="https://cdn.app.eshasan.com/airfone/widget/widget.js" data-key="af_pk_..." async></script>The widget renders in a shadow root, so your page’s CSS does not affect it. It is about 8 KB gzipped. Voice code loads only when a visitor presses Talk.
Attributes
Section titled “Attributes”| Attribute | Values | Default |
|---|---|---|
data-key |
Your publishable key. Required. | |
data-language |
en or ne |
The language set in the console |
data-position |
right or left |
right |
data-color |
Any CSS color, for the launcher and your visitor’s messages | Theme color from the console |
data-open |
true opens the panel on load |
false |
data-launcher |
false hides the bubble, so you can open it from your own button |
true |
data-api |
API base, only for testing against another environment | https://api.airfone.app |
You can also set window.AirFoneSettings = { key, language, api } before the script loads.
JavaScript API
Section titled “JavaScript API”After the script loads, window.AirFone has:
| Method | What it does |
|---|---|
AirFone.open() |
Opens the panel and starts a session. |
AirFone.close() |
Closes the panel. |
AirFone.toggle() |
Opens or closes. |
AirFone.identify({ userId, userHash, name, phone, email }) |
Links the visitor to a known customer. |
AirFone.setLanguage('ne') |
Switches the widget’s language. |
AirFone.on(event, handler) |
Listens for an event. Returns a function that stops listening. |
AirFone.shutdown() |
Removes the widget and closes its connections. |
Before the script loads, push calls onto an array and they run in order once it does:
<script> window.AirFone = window.AirFone || []; window.AirFone.push(['setLanguage', ['ne']]);</script>Identity verification
Section titled “Identity verification”Without verification, anyone could claim to be any customer. So identify needs userHash: the hex HMAC-SHA256 of userId, keyed with your identity secret from the console. Compute it on your server, never in the browser.
import hmac, hashlibuser_hash = hmac.new(IDENTITY_SECRET.encode(), user_id.encode(), hashlib.sha256).hexdigest()$userHash = hash_hmac('sha256', $userId, getenv('AIRFONE_IDENTITY_SECRET'));A visitor with a valid hash is linked to the AirFone contact with that external id, and the assistant can use their records. A wrong hash is ignored: the visitor continues as a guest.
Theming
Section titled “Theming”Set color, position, corner radius, greeting and the assistant’s display name in the console under Widget. The preview there uses the real widget. data-color and data-position on the tag win over the console. The panel follows the visitor’s light or dark setting.
Events
Section titled “Events”| Event | Detail |
|---|---|
ready |
The widget is on the page. |
open, close |
The panel opened or closed. |
message |
A message was sent or received. Detail is the message. |
call.start, call.end |
A voice call started or ended. |
error |
Something failed. Detail is the error. |
AirFone.on('call.end', () => analytics.track('assistant_call'));Accessibility and mobile
Section titled “Accessibility and mobile”The panel is a labelled dialog. Focus moves into it when it opens, Tab stays inside it, and Escape closes it and returns focus. New messages are announced to screen readers. On screens narrower than 520 px the panel fills the screen.
Headless
Section titled “Headless”To build your own interface, use @airfone/web, the client the widget is built on:
import { AirFoneClient } from '@airfone/web';const client = new AirFoneClient({ publishableKey: 'af_pk_...' });client.on((event) => console.log(event));await client.send('Do you have rooms on Friday?');const call = await client.startVoice((state) => console.log(state));