For the complete documentation index, see llms.txt. This page is also available as Markdown.

JavaScript API

Drive the widget from your own code β€” open it, start a call, read its state, listen for events.

Once the widget is installed it exposes a global, window.LimeCall, so your own code can control it.

Everything here runs in the browser and needs no API key β€” the widget is already authenticated by the data-key in your snippet.

Waiting until it is ready

window.LimeCall does not exist until the script has loaded, and the widget keeps initialising for a moment after that. Use the ready event:

(function poll() {
  if (!window.LimeCall) return setTimeout(poll, 100);
  window.LimeCall.on("ready", function (state) {
    // safe to do anything here
  });
})();

Subscribing to ready after the widget is already ready still fires your handler, so there is no race to lose.

Method calls made before the widget finishes initialising are queued and replayed once it is β€” up to 8 of them. Beyond that they are dropped. The catch is that a queued call returns false immediately, so never treat the return value as "it failed".

Methods

Method
Does

open()

Opens the widget panel.

close()

Closes it.

toggle()

Opens if closed, closes if open.

openTab(tab)

Opens the panel on a tab: "call", "message" or "chat".

showLauncher()

Shows the floating launcher button.

hideLauncher()

Hides it β€” the widget still works through the API.

call(phoneNumber)

Requests a callback to that number.

requestCallback(phone, fields)

Requests a callback and returns a promise with the result.

schedule()

Opens the scheduling view.

startWebCall()

Starts a browser call.

endWebCall()

Ends it.

hasAvailableAgents()

Promise resolving to whether anyone can actually take a call right now.

setDepartment(label)

Routes subsequent requests to a department.

getDepartments()

The departments configured on this widget.

getState()

Returns the widget's current state.

getVisitorId()

This visitor's attribution id.

on(event, handler)

Subscribes to an event.

off(event, handler)

Unsubscribes.

version

The loaded widget version.

openTab(tab)

Only "call", "message" and "chat" are accepted. Anything else returns false and does nothing.

call(phoneNumber)

Trimmed and truncated to 32 characters; an empty value returns false without submitting.

It does not tell you whether the callback was accepted. Either listen for callback:requested and callback:failed, or use requestCallback() below, which returns a promise.

requestCallback(phone, fields)

The same request, but you get the answer back:

Resolves to { ok, id, message }. It never rejects β€” a network failure resolves as { ok: false, id: null, message: "network error" }, so you do not need a try/catch around it.

The phone number is validated before any network call. It must be E.164 β€” a leading +, country code, 7–15 digits β€” and anything else resolves immediately with ok: false and a message saying so. Spaces, dashes and brackets are stripped for you, so +44 7700 900123 is fine; 07700900123 is not, because there is no country code.

name is capped at 80 characters and email at 120. The department set through setDepartment() and the visitor's attribution id are attached automatically β€” you do not pass either.

id is the same id the widget uses internally, so you can reconcile it against the callback:requested event or against calls in the REST API.

hasAvailableAgents()

Resolves to true or false: can a call actually be taken right now?

The answer depends on how the widget routes:

Routing
Answers from

To a person or team

Working hours, and whether the people it routes to still resolve. Someone who has left the account makes it false, not a silent dead end.

To the AI receptionist

Your remaining AI minutes. If you are out but have an overflow person configured, it is still true β€” a human answers.

Use it to decide whether to offer a call at all. Offering one that nobody picks up costs more goodwill than not offering it.

The result is cached for 20 seconds, so a page that checks it repeatedly does not generate a request each time. Calling setDepartment() clears the cache, because availability can differ per department.

setDepartment(label) and getDepartments()

If your widget has departments, you can route from code instead of making the visitor choose:

getDepartments() returns the department names as plain strings. It reads them from the widget's loaded configuration, so call it inside ready β€” before that it returns an empty array.

setDepartment(label) applies to every request afterwards: the form, call(), requestCallback() and browser calls. It also moves the visible department picker, if one is rendered. Pass "" or null to clear it.

If the visitor picks a department themselves, their choice wins. setDepartment() sets the default, not an override β€” which is what you want, since they know why they are calling better than the page does.

A label that does not match a configured department resets the visible picker to "Any department", and routing falls back to your default. Match the names exactly as they appear in getDepartments().

getVisitorId()

Returns the attribution id the widget assigns this visitor, or null before it is ready:

It is the same id carried on callback requests, so it is how you stitch a widget conversion to a session in your own analytics.

getState()

Key
Meaning

ready

The widget has finished initialising.

open

The panel is open.

mode

Display style: inline, bubble, side or popup.

inWebCall

A browser call is in progress.

tab

The tab currently shown, or null.

visible

The widget is rendered on this page β€” respects your display rules.

visible is the one to check before wiring your own button to open(): a display rule may have hidden the widget on this page entirely.

Events

Subscribe with on(event, handler), unsubscribe with off(event, handler).

Event
Fires when
Payload

ready

The widget has initialised.

{ visible, mode }

open

The panel opens.

{ mode }

close

The panel closes.

{ mode }

tab

The visitor switches tab.

{ tab }

teaser

The teaser prompt is shown.

{ text }

score

The visitor's lead score changes.

{ points, total, threshold, rule }

callback:requested

A callback was accepted.

{ phone, mode, id } β€” mode is "now" or "schedule"; scheduledAt present when scheduled

callback:failed

A request was rejected or failed.

{ reason, phone, message } β€” reason is "rejected" or "network"

message:sent

The visitor sent a message.

β€”

webcall:started

A browser call began.

β€”

webcall:ended

A browser call ended.

β€”

Unknown event names are rejected: on() returns false rather than silently registering a handler that never fires.

Tracking a conversion

callback:requested fires only once the request was accepted, so it does not over-count:

Wire callback:failed too. A silent rejection β€” closed hours, a blocked number, an unsupported country β€” otherwise looks exactly like a visitor who changed their mind.

The score event

The widget scores visitor engagement and fires score as it changes, with the running total and the threshold it is working toward. Use it to trigger your own behaviour β€” reveal an offer, or open the widget β€” when someone is clearly engaged:

Opening from your own button

Any link to #limecall opens the widget when the page loads:

#lc-open and #lc-widget do the same thing. They work across pages too, which is the useful part β€” put https://example.com/pricing#limecall in an email, an ad or a QR code and the widget opens on arrival, with nothing to install on the page beyond the usual snippet.

The link opens the widget on load and whenever the address changes. If a visitor closes the widget and clicks the same link again, the address has not changed, so nothing happens β€” the browser fires no event. For a button the visitor may use more than once, call open() in a click handler instead.

Next

Was this helpful?