> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revenueable.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Embedding Web Call Assistant

> This tutorial will guide you through the process of embedding a Revenueable AI voice assistant on your website

## Prerequisites

Before you begin, make sure you have:

* An active Revenueable AI account

* Your API key (X-API-KEY)

* An assistant configured for web calls

* Access to modify your website's HTML

## Execution

***Step 1: Configure Your Assistant for Web Calls***

* Open your assistant in the Revenueable AI dashboard

* Navigate to the assistant settings

* Configure the WebCall Settings section

* Add your website domain to the Whitelist Domains list

***Step 2: Get the Embed Code***

* Open your assistant in the Revenueable AI dashboard

* Click the Embed button in the top right corner

* Copy the provided code snippet

The embed code will look similar to this:

```
<script>
	 function loadAgentsCdn(e, t) {
		 let n = document.createElement("link");
		 n.rel = "stylesheet", n.type = "text/css", n.href = `https://cdn.jsdelivr.net/npm/@desivocal/agents-cdn@${e}/dist/style.css`;
		 var a = document.createElement("script");
		 a.type = "text/javascript", a.readyState ? a.onreadystatechange = function() {
			 "loaded" !== a.readyState && "complete" !== a.readyState || (a.onreadystatechange = null, t())
		 } : a.onload = function() {
			 t()
		 }, a.src = `https://cdn.jsdelivr.net/npm/@desivocal/agents-cdn@${e}/dist/dv-agent.es.js`, document.getElementsByTagName("head")[0].appendChild(n), document.getElementsByTagName("head")[0].appendChild(a)
	 }
</script>
```

```
<script>
	 loadAgentsCdn("latest", function() {
		 loadAgent({
			 agentId: "your-agent-id",
			 xApiKey: "your-api-key",
			 variables: {},
			 buttons: {},
		 });
	 });
</script>
```

***Step 3: Customize the Embed Code***

Modify the configuration object to customize the appearance and behavior of the Web Call assistant:

```javascript theme={null}
loadAgent({
  agentId: "your-agent-id",
  xApiKey: "your-api-key",

  variables: {
    custom_variable_1: "value1",
    custom_variable_2: "value2",
  },

  buttons: {
    modalTrigger: {
      styles: {
        backgroundColor: "#4CAF50",
        color: "white",
        borderRadius: "50%",
      },
      icon: {
        url: "https://example.com/custom-icon.svg",
        size: 24,
      },
    },
    mic: {
      styles: {
        backgroundColor: "#f44336",
        borderRadius: "50%",
      },
    },
    call: {
      textBeforeCall: "Start Call",
      textDuringCall: "End Call",
      styles: {
        backgroundColor: "#2196F3",
        color: "white",
        borderRadius: "4px",
      },
    },
  },

  widgetPosition?: {
    triggerPlacement?: "fixed" | "absolute",
    /**
     * Widget positioning mode.
     * "fixed" - floats over the page, fixed to viewport (default)
     * "absolute" - embeds inside a container with id="revenueable_ai_container"
     * Supported from v1.0.19+
     */

    triggerAlignment?: "bottom-right" | "bottom-left" | "top-right" | "top-left" | "center",
    /**
     * Position of the trigger button.
     * Supported from v1.0.19+
     * @default "bottom-right"
     */

    hideTriggerOnExpand?: boolean,
    /**
     * Hide the trigger button when widget is open.
     * Supported from v1.0.19+
     * @default true
     */

    widgetAlignment?: "bottom-right" | "bottom-center" | "bottom-left",
    /**
     * Position of the expanded widget.
     * Supported from v1.0.19+
     * @default "bottom-right"
     */
  },

  defaultTab?: "audio" | "text",
  /**
   * The tab shown by default when the component loads.
   * Supported from v1.0.8+
   * @default "audio"
   */

  hideTabSelector?: boolean,
  /**
   * Whether to hide the tab selector UI.
   * Supported from v1.0.8+
   * @default false
   */

  innerWindowProps?: {
    /**
     * Inner window dimensions when a call is connected.
     * Accepts a number (px) or any valid CSS size string.
     * Supported from v1.0.8+
     */
    width?: number | string,
    height?: number | string,
    borderRadius?: number | string,
  },

  title?: string,
  /** Custom title displayed in the header. */

  description?: string,
  /** Custom description displayed below the title. */

  logoUrl?: string,
  /**
   * Custom logo URL displayed in the header.
   * Supported from v1.0.10+
   */

  logoStyles?: Partial<React.CSSProperties>,
  /**
   * Custom CSS styles for the logo container.
   * Supported from v1.0.10+
   */

  legalDisclaimer?: {
    text: string,
    links?: Record<string, string>
  },
  /**
   * Custom legal disclaimer with clickable links.
   * Supported from v1.0.10+
   */

  feedbackScreen?: {
    title?: string,               // Default: "How was your call/chat?"
    description?: string,         // Default: "Your feedback helps us improve!"
    starsCount?: number,          // Default: 5
    placeholder?: string,         // Default: "We'd love to hear more..."
    submitBtnCTA?: string,        // Default: "Submit Feedback"
    submitBtnStyles?: Partial<React.CSSProperties>,
    starsStyles?: {
      filledColor?: string,       // Default: #FBBF24 (yellow)
      emptyColor?: string         // Default: #D1D5DB (gray)
    }
  },
  /**
   * Optional feedback UI props
   * Supported from v1.0.11+
   */
});

```

***Step 4: Add the Code to Your Website***

Paste the embed code into your website's HTML, preferably just before the closing `</body>` tag.

***Step 5: Configure CDN Permissions***

If your website uses Content Security Policy (CSP), add the following CDN links to your security policies:

```text theme={null}
style-src: https://cdn.jsdelivr.net/npm/@desivocal/agents-cdn@latest/dist/style.css
script-src: https://cdn.jsdelivr.net/npm/@desivocal/agents-cdn@latest/dist/dv-agent.es.js
```

***Step 6: Test the Integration***

* Visit your website

* Look for the Web Call button (typically in the bottom right corner)

* Click the button to start a call

* Speak to test the voice interaction

## Widget Positioning

Control where the widget appears on your page. Supported from v1.0.19+.

## Fixed Mode (Default)

The widget floats over your page, fixed to the browser viewport. No additional setup required.

## Absolute Mode

Embed the widget inside a specific container on your page.

***Step 1: Add a container with the required ID***

```html theme={null}
<div id="revenueable_ai_container" style="position: relative; width: 100%; height: 500px;">
</div>
```

***Step 2: Enable absolute positioning***

```javascript theme={null}
loadAgent({
  agentId: "your-agent-id",
  xApiKey: "your-api-key",
  widgetPosition: {
    triggerPlacement: "absolute",
    triggerAlignment: "center"
  }
});
```

<Card>
  | Option                | Type      | Default          | Description                                        |
  | --------------------- | --------- | ---------------- | -------------------------------------------------- |
  | `triggerPlacement`    | `string`  | `"fixed"`        | `"fixed"` for viewport, `"absolute"` for container |
  | `triggerAlignment`    | `string`  | `"bottom-right"` | Trigger button position                            |
  | `hideTriggerOnExpand` | `boolean` | `true`           | Hide trigger when widget is open                   |
  | `widgetAlignment`     | `string`  | `"bottom-right"` | Expanded widget position                           |
</Card>

## Trigger Button Customization

Customize the floating action button that opens the widget. Supported from v1.0.19+.

## Button Styles

```javascript theme={null}
buttons: {
  modalTrigger: {
    styles: {
      backgroundColor: "#4F46E5",
      width: 64,
      height: 64
    }
  }
}
```

## Custom Icon

```javascript theme={null}
buttons: {
  modalTrigger: {
    icon: {
      url: "https://example.com/my-icon.svg",
      size: 24
    }
  }
}
```

<Card>
  | Option      | Type            | Default                | Description                                              |
  | ----------- | --------------- | ---------------------- | -------------------------------------------------------- |
  | `styles`    | `CSSProperties` | —                      | Button CSS styles (width, height, backgroundColor, etc.) |
  | `icon.url`  | `string`        | Revenueable phone icon | Custom icon URL                                          |
  | `icon.size` | `number`        | `20`                   | Icon size in pixels                                      |
</Card>

## Widget Events

Subscribe to widget events and perform your custom actions based on them. Supported from v1.0.17.

<Card>
  | Event                             | Payload                                                                                       |
  | --------------------------------- | --------------------------------------------------------------------------------------------- |
  | `revenueable:widget_status`       | `status`: `"maximised"` \| `"minimised"`<br />`mode`: `"audio"` \| `"text"`                   |
  | `revenueable:conversation_status` | `status`: `"started"` \| `"ended"`<br />`mode`: `"audio"` \| `"text"`<br />`callId`: `string` |
  | `revenueable:feedback_status`     | `status`: `"submitted"` \| `"skipped"`<br />`callId`: `string`<br />`rating?`: `number`       |
</Card>

## Usage

```javascript theme={null}
window.addEventListener("revenueable:widget_status", (e) => {
  console.log(e.detail); // { status: "maximised", mode: "audio" }
});

window.addEventListener("revenueable:conversation_status", (e) => {
  console.log(e.detail); // { status: "started", mode: "audio", callId: "abc123" }
});

window.addEventListener("revenueable:feedback_status", (e) => {
  console.log(e.detail); // { status: "submitted", callId: "abc123", rating: 5 }
});
```
