# Web Campaigns (Reference: https://docs.iqra.bot/build/campaigns/web)
**Web Campaigns** allow you to embed Voice AI directly into your websites, mobile applications, or custom hardware.
Unlike Telephony campaigns (which rely on old phone networks), Web Campaigns use **WebRTC** or **WebSockets**. This results in:
* **Higher Audio Quality:** HD Voice (44.1kHz) instead of phone quality (8kHz).
* **Lower Latency:** Direct internet connection without carrier routing.
* **Zero Telephony Costs:** No per-minute fees to Twilio/Telnyx.
Creating a Campaign [#creating-a-campaign]
Navigate to **Business Dashboard** -> **Routing & Campaigns** -> **Web Campaigns**.
Agent & Script [#agent--script]
Select the [**Agent**](/build/agent) and the [**Opening Script**](/build/script).
Configuration [#configuration]
* **Max Duration:** Limit the session length to control compute costs.
* **Silence Detection:** Configure how the agent handles user silence (usually more lenient in web sessions than phone calls).
Dynamic Variables [#dynamic-variables]
Define what data you expect the frontend to pass to the agent.
* **Example:** If your website has a logged-in user, you can pass their `name` and `account_id` as metadata when the session starts.
* **Usage:** The Agent can then greet them personally: *"Welcome back, \{\{ name }}."*
Client Integration [#client-integration]
Once saved, the campaign generates a **Web Campaign ID** (e.g., `camp_web_123...`).
Use this ID with our client libraries. Check the **[Web Widget SDK](/developers/sdks/web-widget)** and **[.NET Middleware](/developers/sdks/middleware)** guides for implementation details.
***
Post-Analysis [#post-analysis]
Configure how the system analyzes the conversation after the session closes.
1. Navigate to the **Post Analysis** tab.
2. Select a **Template** defined in the [Post Analysis Module](/build/operations/analysis).
3. **Context Variables:** The LLM will receive the following data:
| Variable | Type | Description |
| :------------------------------ | :------- | :------------------------------------------- |
| `web_session_id` | String | Unique ID for the web session. |
| `web_session_created_at` | Datetime | When the connection was established. |
| `web_session_status` | String | Status (e.g., `completed`). |
| `web_session_web_campaign_id` | String | The Campaign ID. |
| `web_session_client_identifier` | String | The unique user ID passed from the frontend. |
| `web_session_dynamic_variables` | Object | JSON of variables passed from frontend. |
| `web_session_metadata` | Object | JSON of metadata passed from frontend. |
| `conversation_id` | String | Unique UUID for the conversation logic. |
| `conversation_start_time` | Datetime | Start of audio stream. |
| `conversation_end_time` | Datetime | End of audio stream. |
| `conversation_end_type` | String | `agent_hangup`, `user_hangup`, `timeout`. |
| `conversation_turns` | Object | Raw JSON array of speaker turns. |
| `conversation_turns_simplified` | String | Human-readable transcript. |
***
Actions (Webhooks) [#actions-webhooks]
Sync digital conversation events to your backend.
1. Create a [Custom Tool](/build/tools/custom-tools) first.
2. Select that tool in the Action dropdown.
3. Map the **Available Variables** (below) to the Tool's Input Schema.
1. On Conversation Initiation Failure [#1-on-conversation-initiation-failure]
Triggered if the connection is rejected (e.g., Invalid Token, Geo-blocked, or Concurrency Limit reached).
| Variable | Type | Description |
| :------------------------------ | :------- | :----------------------------------------- |
| `web_session_id` | String | Unique ID for the attempted session. |
| `web_session_created_at` | Datetime | Time of attempt. |
| `web_session_status` | String | `failed`. |
| `web_session_web_campaign_id` | String | The Campaign ID. |
| `web_session_client_identifier` | String | The unique user ID passed. |
| `web_session_dynamic_variables` | Object | JSON variables. |
| `web_session_metadata` | Object | JSON metadata. |
| `web_session_initiation_error` | String | Error details (e.g., `concurrency_limit`). |
2. On Conversation Initiated [#2-on-conversation-initiated]
Triggered when the WebSocket/WebRTC connection is established and audio is ready.
| Variable | Type | Description |
| :------------------------------ | :------- | :-------------------------------------- |
| `web_session_id` | String | Unique ID for the active session. |
| `web_session_created_at` | Datetime | Connection time. |
| `web_session_status` | String | `active`. |
| `web_session_web_campaign_id` | String | The Campaign ID. |
| `web_session_client_identifier` | String | The unique user ID passed. |
| `web_session_dynamic_variables` | Object | JSON variables. |
| `web_session_metadata` | Object | JSON metadata. |
| `conversation_id` | String | Unique UUID for the conversation logic. |
| `conversation_start_time` | Datetime | Start of audio stream. |
3. On Conversation Ended [#3-on-conversation-ended]
Triggered when the user closes the tab or clicks "End Call".
| Variable | Type | Description |
| :------------------------------ | :------- | :-------------------------------------- |
| `web_session_id` | String | Unique ID for the session. |
| `web_session_created_at` | Datetime | Connection time. |
| `web_session_status` | String | `completed`. |
| `web_session_web_campaign_id` | String | The Campaign ID. |
| `web_session_client_identifier` | String | The unique user ID passed. |
| `web_session_dynamic_variables` | Object | JSON variables. |
| `web_session_metadata` | Object | JSON metadata. |
| `conversation_id` | String | Unique UUID for the conversation logic. |
| `conversation_start_time` | Datetime | Start of audio stream. |
| `conversation_end_type` | String | Reason for termination. |
| `conversation_end_time` | Datetime | End of audio stream. |
| `conversation_turns` | Object | Raw JSON array of speaker turns. |
| `conversation_turns_simplified` | String | Human-readable transcript. |