VICIdial Agent Screen Customization Guide
Your agents spend 8 hours a day staring at the VICIdial agent screen. If it’s cluttered with fields they don’t need, missing the data they do need, and forces them to click through three tabs to enter a disposition, you’re burning 10-15 minutes per agent per hour on interface friction alone. Multiply that across your floor and the cost is staggering.
VICIdial’s agent screen is more customizable than most operators realize. The problem isn’t capability — it’s documentation. This guide fixes that.
The VICIdial agent interface is a PHP-generated web application that runs in the browser. It’s not a modern single-page application. There’s no React, no Vue, no component library. It’s server-rendered HTML with inline JavaScript, and it looks like it was designed in 2006 — because it was. But what it lacks in visual polish, it makes up for in flexibility. You can embed custom forms, inject JavaScript, load external applications via IFRAME, relabel every field, configure hotkeys, and completely reshape the agent experience without touching VICIdial’s source code.
This guide covers every customization method available in VICIdial: web forms, script tabs, screen labels, IFRAME integration, hotkey configuration, layout options, ViciPhone panel management, button visibility, custom transfer lists, and JavaScript injection. We include working code examples and document the limitations you’ll hit so you don’t waste time on approaches that can’t work.
Understanding the Agent Screen Architecture
Before customizing anything, you need to understand how the agent screen works technically.
How It’s Built
The agent screen is generated by vicidial.php (for the primary agent interface) or agc/vicidial.php in the web root. When an agent logs in, the server generates a single HTML page containing:
- The complete interface layout (header, call info panel, script tab, form tab, etc.)
- Inline JavaScript for all client-side interactions (call controls, disposition, transfers)
- AJAX calls to update call data, agent state, and campaign information in real-time
- IFRAMEs for web forms and custom content
The page does not reload during a shift. Once loaded, everything happens via JavaScript and AJAX calls to VICIdial’s API endpoints. This is important because it means:
- Custom CSS and JavaScript injected at load time persist for the entire session
- DOM modifications via JavaScript work, but page reloads reset everything
- Web forms in IFRAMEs can communicate with the parent frame via JavaScript (with caveats)
The Three Customization Layers
VICIdial gives you three distinct layers for customization:
- Admin-level configuration — Settings in the admin GUI that control what agents see (screen labels, button visibility, layout options). No code required.
- Web forms and script tabs — HTML/PHP/JavaScript content embedded in the agent screen via IFRAMEs. Moderate technical skill needed.
- JavaScript injection — Custom JS loaded via screen labels or web forms that modifies the agent screen DOM directly. Advanced technical skill needed.
Each layer has different capabilities and limitations. We’ll cover all three.
Screen Labels: The Easiest Customization
Screen Labels is VICIdial’s built-in mechanism for renaming fields, hiding elements, and injecting small amounts of custom code into the agent screen. It’s accessible from Admin → Screen Labels.
What Screen Labels Can Do
- Rename any field label visible to agents (e.g., change “Address 1” to “Service Address”)
- Hide fields that aren’t relevant to your campaign
- Inject custom CSS to restyle the interface
- Inject custom JavaScript that runs when the agent screen loads
- Add custom header/footer content
Creating a Screen Label Set
- Navigate to Admin → Screen Labels
- Click “ADD A NEW SCREEN LABELS ENTRY”
- Give it a descriptive name (e.g., “Insurance Campaign Labels”)
- Modify the fields you want to change
Each label field has a corresponding agent screen element. The most commonly customized:
| Screen Label Field | Default Text | Common Customization |
|---|---|---|
| agent_screen_title | Agent Screen | Your Company Name |
| first_name_label | First Name | Client First Name |
| last_name_label | Last Name | Client Last Name |
| address1_label | Address 1 | Property Address |
| phone_number_label | Phone | Primary Phone |
| alt_phone_label | Alt Phone | Cell Phone |
| email_label | Client Email | |
| comments_label | Comments | Qualification Notes |
| vendor_lead_code_label | Vendor Lead Code | Policy Number |
Hiding Unnecessary Fields
To hide a field entirely, set its label to a single space ( ) and the field will still exist in the DOM but won’t be visible. For more aggressive hiding, use the CSS injection capability:
In the label_header or a custom header field, inject:
<style>
/* Hide the address fields */
#address1Label, #address1Field { display: none !important; }
#address2Label, #address2Field { display: none !important; }
#address3Label, #address3Field { display: none !important; }
/* Hide the date of birth field */
#date_of_birthLabel, #date_of_birthField { display: none !important; }
</style>
Caveat: The exact element IDs vary slightly between VICIdial versions and layouts. Use your browser’s developer tools (F12 → Inspect Element) to find the correct IDs for your version.
Assigning Screen Labels to Campaigns
Once created, assign a Screen Label set to a campaign:
- Go to Admin → Campaigns → [your campaign]
- Find the “Screen Labels” dropdown
- Select your custom label set
- Save
Different campaigns can use different screen label sets. A health insurance campaign might relabel “Comments” to “Medical History Notes” while a solar campaign relabels it to “Roof Type / Panel Interest.”
Your Agents Shouldn’t Have to Decode Field Names. ViciStack configures custom screen labels for every campaign type — insurance, solar, home services, debt — so agents see exactly the data they need in language they understand. See Our Optimization Process →
Custom Web Forms: The Primary Customization Method
Web forms are VICIdial’s most powerful customization mechanism. They allow you to embed any HTML/PHP/JavaScript application directly within the agent screen interface, giving agents access to custom forms, external data, calculations, and integrations without leaving the dialer.
How Web Forms Work
VICIdial loads web forms in an IFRAME within the agent screen. When a call connects, VICIdial passes lead data to the web form URL as query parameters. The web form can then:
- Display the data in any format you choose
- Collect additional information from the agent
- Submit data to external systems (CRM, order management, etc.)
- Communicate back to the parent VICIdial frame via JavaScript
Configuring Web Forms
Web forms are configured at the campaign level:
- Go to Admin → Campaigns → [your campaign] → Detail
- Find the Web Form field
- Enter the URL of your web form
VICIdial supports up to three web forms per campaign (Web Form, Web Form 2, Web Form 3). Each can have different content.
Variable Substitution in Web Form URLs
VICIdial replaces special variables in the web form URL with live call data. This is how your web form receives lead information:
https://your-crm.example.com/lead-form.php?first=--A--first_name--B--&last=--A--last_name--B--&phone=--A--phone_number--B--&lead_id=--A--lead_id--B--
The --A--fieldname--B-- syntax gets replaced with actual values when the call connects. Available variables include:
| Variable | Description |
|---|---|
--A--first_name--B-- | Lead first name |
--A--last_name--B-- | Lead last name |
--A--phone_number--B-- | Phone being dialed |
--A--lead_id--B-- | VICIdial lead ID |
--A--vendor_lead_code--B-- | Vendor lead code |
--A--list_id--B-- | List ID |
--A--address1--B-- | Address line 1 |
--A--city--B-- | City |
--A--state--B-- | State |
--A--postal_code--B-- | ZIP/postal code |
--A--email--B-- | Email address |
--A--campaign--B-- | Campaign ID |
--A--user--B-- | Agent username |
--A--uniqueid--B-- | Call unique ID |
--A--call_id--B-- | VICIdial call ID |
--A--recording_filename--B-- | Recording file name |
--A--agent_log_id--B-- | Agent log entry ID |
--A--did_id--B-- | DID ID for inbound |
--A--did_extension--B-- | DID extension |
Custom fields (added via Admin → Custom Fields) are also available using their field name.
Example: Custom Lead Qualification Form
Here’s a complete example of a custom web form for an insurance lead qualification campaign:
<!DOCTYPE html>
<html>
<head>
<title>Lead Qualification</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 12px;
font-size: 13px;
background: #f8f9fa;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 12px;
}
.form-group { margin-bottom: 6px; }
label {
display: block;
font-weight: 600;
margin-bottom: 2px;
color: #333;
font-size: 11px;
text-transform: uppercase;
}
input, select, textarea {
width: 100%;
padding: 6px 8px;
border: 1px solid #ccc;
border-radius: 3px;
font-size: 13px;
}
select { height: 32px; }
.lead-info {
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
margin-bottom: 12px;
}
.lead-info h3 { font-size: 14px; margin-bottom: 8px; color: #1a73e8; }
.lead-name { font-size: 18px; font-weight: 700; color: #111; }
.lead-phone { font-size: 14px; color: #666; }
.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
font-weight: 600;
}
.btn-primary { background: #1a73e8; color: #fff; }
.btn-success { background: #0d8a4e; color: #fff; }
.btn-danger { background: #dc3545; color: #fff; }
.status-bar {
padding: 6px;
text-align: center;
border-radius: 3px;
margin-top: 10px;
display: none;
}
.status-success { background: #d4edda; color: #155724; display: block; }
.full-width { grid-column: 1 / -1; }
</style>
</head>
<body>
<div class="lead-info">
<h3>Current Lead</h3>
<div class="lead-name" id="leadName">Loading...</div>
<div class="lead-phone" id="leadPhone"></div>
<div style="margin-top: 6px;">
<span id="leadCity"></span> <span id="leadState"></span> <span id="leadZip"></span>
</div>
</div>
<form id="qualForm">
<input type="hidden" name="lead_id" id="lead_id">
<input type="hidden" name="agent" id="agent">
<input type="hidden" name="call_id" id="call_id">
<div class="form-grid">
<div class="form-group">
<label>Insurance Type</label>
<select name="insurance_type" required>
<option value="">-- Select --</option>
<option value="medicare_advantage">Medicare Advantage</option>
<option value="medicare_supplement">Medicare Supplement</option>
<option value="prescription_drug">Prescription Drug Plan</option>
<option value="dental_vision">Dental/Vision</option>
</select>
</div>
<div class="form-group">
<label>Current Coverage</label>
<select name="current_coverage">
<option value="">-- Select --</option>
<option value="original_medicare">Original Medicare Only</option>
<option value="medicare_advantage">Has Medicare Advantage</option>
<option value="medigap">Has Medigap/Supplement</option>
<option value="employer">Employer Coverage</option>
<option value="none">No Current Coverage</option>
</select>
</div>
<div class="form-group">
<label>Date of Birth</label>
<input type="date" name="dob">
</div>
<div class="form-group">
<label>Medicare Effective Date</label>
<input type="date" name="medicare_effective">
</div>
<div class="form-group">
<label>Primary Doctor</label>
<input type="text" name="primary_doctor" placeholder="Doctor name">
</div>
<div class="form-group">
<label>Monthly Budget</label>
<select name="monthly_budget">
<option value="">-- Select --</option>
<option value="0">$0 - Looking for $0 premium</option>
<option value="50">Up to $50/month</option>
<option value="100">Up to $100/month</option>
<option value="200">Up to $200/month</option>
<option value="200+">Over $200/month</option>
</select>
</div>
<div class="form-group full-width">
<label>Agent Notes</label>
<textarea name="notes" rows="3" placeholder="Qualification notes..."></textarea>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Save Qualification</button>
<button type="button" class="btn btn-success" onclick="submitAndTransfer()">Save & Transfer</button>
</div>
<div id="statusBar" class="status-bar"></div>
</form>
<script>
// Parse URL parameters (VICIdial passes lead data as query params)
const params = new URLSearchParams(window.location.search);
// Populate lead info display
document.getElementById('leadName').textContent =
(params.get('first') || '') + ' ' + (params.get('last') || '');
document.getElementById('leadPhone').textContent = params.get('phone') || '';
document.getElementById('leadCity').textContent = params.get('city') || '';
document.getElementById('leadState').textContent = params.get('state') || '';
document.getElementById('leadZip').textContent = params.get('zip') || '';
// Set hidden fields
document.getElementById('lead_id').value = params.get('lead_id') || '';
document.getElementById('agent').value = params.get('user') || '';
document.getElementById('call_id').value = params.get('call_id') || '';
// Form submission
document.getElementById('qualForm').addEventListener('submit', function(e) {
e.preventDefault();
saveQualification();
});
function saveQualification() {
const formData = new FormData(document.getElementById('qualForm'));
fetch('/custom/save_qualification.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
const bar = document.getElementById('statusBar');
bar.textContent = 'Qualification saved successfully';
bar.className = 'status-bar status-success';
setTimeout(() => { bar.style.display = 'none'; }, 3000);
})
.catch(error => {
console.error('Save failed:', error);
});
}
function submitAndTransfer() {
saveQualification();
// Trigger transfer in parent VICIdial frame
try {
parent.document.getElementById('MainXfeRButtoN').click();
} catch(e) {
console.log('Transfer trigger failed — different origin or element not found');
}
}
</script>
</body>
</html>
Save this as a PHP or HTML file on your web server (e.g., /var/www/html/custom/insurance_qual.html), then set the campaign Web Form URL to:
/custom/insurance_qual.html?first=--A--first_name--B--&last=--A--last_name--B--&phone=--A--phone_number--B--&lead_id=--A--lead_id--B--&user=--A--user--B--&call_id=--A--call_id--B--&city=--A--city--B--&state=--A--state--B--&zip=--A--postal_code--B--
Web Form Display Options
Control when and how the web form appears:
| Setting | Location | Options |
|---|---|---|
| Web Form Target | Campaign Detail | IFRAME (embedded), _blank (new tab) |
| Web Form Popup | Campaign Detail | Disabled, On Connect, On Disposition |
| Auto-Open Web Form | Campaign Detail | Y/N — automatically open on call connect |
For most operations, set Web Form Target to IFRAME (embedded in the agent screen) and enable auto-open on connect. This ensures agents see the web form data immediately without clicking.
Script Tab Configuration
The Script tab is a built-in IFRAME within the agent screen designed for call scripts — the text agents read or reference during calls. Unlike web forms, the script tab is always visible (when the Script tab is selected) and supports the same variable substitution.
Creating Scripts
- Go to Admin → Scripts
- Click “ADD A NEW SCRIPT”
- Enter the script content as HTML
Scripts support the same --A--fieldname--B-- variable substitution as web forms. Here’s an example:
<div style="font-family: Arial, sans-serif; padding: 15px; line-height: 1.6;">
<h2 style="color: #333;">Medicare Advantage Enrollment Script</h2>
<p><strong>Opening:</strong></p>
<p>"Hi, is this <span style="color: #1a73e8; font-weight: bold;">--A--first_name--B--</span>?
Great! My name is [your name] and I'm calling from [company].
I'm reaching out because you may qualify for additional Medicare benefits
in <span style="color: #1a73e8; font-weight: bold;">--A--state--B--</span>
that could save you money on your healthcare costs.
Do you have about 2 minutes?"</p>
<p><strong>Qualification Questions:</strong></p>
<ol>
<li>Are you currently enrolled in Medicare Parts A and B?</li>
<li>Are you happy with your current Medicare coverage?</li>
<li>Would you be open to learning about plans with $0 premiums that include dental, vision, and hearing?</li>
<li>Do you have a preferred doctor you'd like to keep?</li>
</ol>
<p><strong>Objection: "I'm happy with what I have"</strong></p>
<p>"I completely understand, --A--first_name--B--. Most of the people I help felt the same way before
they realized they were paying more than they needed to. Can I just ask — are you currently paying
a monthly premium for your Medicare coverage?"</p>
<p><strong>Transfer Script:</strong></p>
<p>"--A--first_name--B--, based on what you've told me, I think one of our licensed
benefits specialists can find you a better plan. I'm going to connect you right now.
Please hold for just a moment."</p>
</div>
Assigning Scripts to Campaigns
Campaign Detail → Script → select your script from the dropdown.
You can also assign different scripts to different inbound groups, which is useful for blended campaigns where agents handle both outbound and inbound calls.
IFRAME Integration for External CRM/Tools
One of VICIdial’s most underutilized features is the ability to embed external applications directly within the agent screen via IFRAMEs. This allows agents to interact with your CRM, order management system, knowledge base, or any web-based tool without switching windows.
Methods of IFRAME Integration
Method 1: Web Form as CRM IFRAME
Set your campaign’s Web Form URL to your CRM’s lead detail page, passing the lead ID:
https://your-crm.example.com/lead/view?id=--A--vendor_lead_code--B--&agent=--A--user--B--
The CRM opens in the web form IFRAME with the correct lead loaded. When the call ends and a new call connects, VICIdial refreshes the IFRAME with the new lead’s data.
Method 2: Custom Tab via Screen Labels
Using the label header injection, you can create additional tabs in the agent interface that load external content:
<script>
// Add a custom "CRM" tab to the agent screen
document.addEventListener('DOMContentLoaded', function() {
// Find the tab bar
var tabBar = document.getElementById('agent_tab_bar');
if (tabBar) {
var newTab = document.createElement('span');
newTab.innerHTML = '<a href="#" onclick="showCustomTab(); return false;" style="padding: 5px 15px; background: #eee; border: 1px solid #ccc; margin-left: 5px; text-decoration: none; color: #333;">CRM</a>';
tabBar.appendChild(newTab);
}
});
function showCustomTab() {
// Hide other tab content
var panels = document.querySelectorAll('.tab-panel');
panels.forEach(function(p) { p.style.display = 'none'; });
// Show or create our custom iframe
var crmFrame = document.getElementById('custom_crm_frame');
if (!crmFrame) {
crmFrame = document.createElement('iframe');
crmFrame.id = 'custom_crm_frame';
crmFrame.src = 'https://your-crm.example.com';
crmFrame.style.width = '100%';
crmFrame.style.height = '400px';
crmFrame.style.border = 'none';
document.getElementById('agent_main_content').appendChild(crmFrame);
}
crmFrame.style.display = 'block';
}
</script>
Method 3: Persistent CRM panel alongside agent controls
For operations where agents need the CRM visible at all times (not in a tab):
<style>
/* Resize the agent screen to make room for CRM panel */
#agent_main_container { width: 60% !important; float: left; }
</style>
<div id="persistent_crm" style="width: 38%; float: right; position: fixed; right: 10px; top: 60px; bottom: 10px;">
<iframe src="https://your-crm.example.com" style="width: 100%; height: 100%; border: 1px solid #ccc;"></iframe>
</div>
Cross-Origin Limitations
If your CRM is on a different domain than your VICIdial server, browser same-origin policy prevents JavaScript communication between the IFRAME and the parent VICIdial frame. This means:
- The CRM can’t programmatically click VICIdial buttons (disposition, transfer, etc.)
- VICIdial can’t read data from the CRM IFRAME
- You can’t inject VICIdial call data into the CRM via DOM manipulation
Workarounds:
- postMessage API: Both the CRM and VICIdial frame can use
window.postMessage()for cross-origin communication. Your CRM needs to implement a message listener. - Host the CRM on the same domain as VICIdial (or use a reverse proxy to make it appear same-origin).
- Use VICIdial’s API instead of DOM manipulation: your CRM can call VICIdial’s non-agent API to trigger dispositions, transfers, etc.
Hotkey Configuration for Dispositions
Hotkeys let agents disposition calls with a single keypress instead of clicking through dropdown menus. For high-volume campaigns, this saves 3-5 seconds per call — which adds up to 15-25 minutes per shift per agent.
Setting Up Hotkeys
- Go to Admin → Campaigns → [your campaign] → Statuses
- For each disposition status, assign a hotkey (1-9, 0)
Example hotkey mapping for a lead generation campaign:
| Key | Disposition | Description |
|---|---|---|
| 1 | SALE | Qualified lead / appointment set |
| 2 | NI | Not Interested |
| 3 | CALLBK | Callback requested |
| 4 | DNC | Do Not Call |
| 5 | NA | No Answer (manual disposition) |
| 6 | WRONG | Wrong Number |
| 7 | DEAD | Dead Lead / Disconnected |
| 8 | XFER | Live Transfer (dispositioned after transfer) |
| 9 | NQ | Not Qualified |
Hotkey Behavior Settings
| Setting | Location | Purpose |
|---|---|---|
| HotKey Active | Campaign Detail | Enables/disables hotkey functionality |
| HotKey Disposition | Campaign Detail | Agent can use hotkeys during/after call |
Best practice: Enable hotkeys for all high-volume outbound campaigns. Train agents on the mappings. Print a hotkey reference card they can keep at their desk. The productivity gain is immediate and measurable.
Agent Screen Layout Options
VICIdial offers three agent screen layouts that control the overall structure of the interface.
Layout 1: Standard (Default)
The classic VICIdial layout with call information at the top, a tabbed panel in the middle (Script, Web Form, lead data), and call controls at the bottom. This is what most VICIdial installations use and what most documentation assumes.
Layout 2: Slim
A more compact layout designed for operations where screen real estate is limited (single monitor agents, smaller displays). The call info and controls are compressed, and the IFRAME/script area gets more vertical space.
Layout 3: Wide
A horizontal layout that puts call information on the left and the script/web form panel on the right side-by-side instead of stacked. Useful for dual-monitor setups or wide-screen displays where agents have horizontal space to spare.
Changing layouts: Campaign Detail → Agent Screen Layout
Per-campaign layouts: Different campaigns can use different layouts. A simple callback campaign might use the Slim layout, while a complex insurance qualification campaign uses Wide to give agents more room for the custom form.
Controlling Agent Interface Elements
VICIdial provides granular control over which buttons, tabs, and features agents can see and use.
Button Visibility Settings
These settings are scattered across Campaign Detail, In-Group settings, and System Settings:
| Element | Setting Location | Controls |
|---|---|---|
| Transfer button | Campaign Detail → Allow Transfer | Show/hide the transfer button |
| Manual dial | Campaign Detail → Manual Dial | Allow agents to dial manually |
| Pause codes | Campaign Detail → Agent Pause Codes Active | Require agents to select a reason when pausing |
| Callback button | Campaign Detail → Scheduled Callbacks | Allow agents to schedule callbacks |
| Script tab | Campaign Detail → Script | Only shows if a script is assigned |
| Web Form button | Campaign Detail → Web Form | Only shows if a web form URL is set |
| Park/Hold | Campaign Detail → Park Extension | Show/hide park/hold functionality |
| 3-way call | Campaign Detail → Concurrent Transfers | Allow 3-way calling |
| Recording control | Campaign Detail → Campaign Recording | Show recording start/stop buttons (if set to ALLFORCE, agents can’t control recording) |
Restricting Agent Actions
For compliance-sensitive campaigns, restrict agents to only the actions they need:
Lock down a TCPA-compliant campaign:
- Manual Dial: N (agents can’t choose who to call)
- Allow Transfer: Y (for live transfers to closers)
- Callback: Y (for scheduled callbacks only)
- Web Form: Y (for qualification form)
- Park Extension: N (no need for hold)
- Recording: ALLFORCE (all calls recorded, agents can’t stop it)
Lock down a collections campaign:
- Manual Dial: Y (agents may need to call specific accounts)
- Allow Transfer: Y
- Callback: Y
- Script: Y (compliance scripts with required disclosures)
- Recording: ALLFORCE
ViciPhone Panel Configuration
ViciPhone — VICIdial’s WebRTC softphone — adds a browser-based phone panel to the agent screen. When enabled, agents don’t need a separate SIP phone or softphone application.
ViciPhone Position and Sizing
The ViciPhone panel’s position is controlled in System Settings → WebRTC Settings:
| Setting | Options | Impact |
|---|---|---|
| ViciPhone Position | Top, Bottom, Left, Right | Where the phone panel appears relative to the agent screen |
| ViciPhone Width | Pixels | Width of the panel |
| ViciPhone Height | Pixels | Height of the panel |
For most deployments, Bottom position works best — it keeps the ViciPhone panel below the agent screen and doesn’t compete for horizontal space with the script/form tabs.
Hiding ViciPhone for SIP Phone Users
If some agents use hardware SIP phones and others use ViciPhone, you can control visibility at the user level. In Admin → Users → [user] → Phone Login, set the phone type. Agents with hardware phones don’t need the ViciPhone panel.
At the campaign level, you can also control whether ViciPhone is offered as an option during agent login by configuring the phone settings per campaign.
Custom JavaScript Injection
For advanced customizations that go beyond what Screen Labels, web forms, and admin settings provide, you can inject custom JavaScript that modifies the agent screen DOM at runtime.
Injection Points
Via Screen Labels:
The label_header field in Screen Labels supports arbitrary HTML, including <script> tags. Any JavaScript here executes when the agent screen loads:
<script>
// Custom JS injected via Screen Labels
(function() {
// Wait for the agent screen to fully render
setTimeout(function() {
// Example: Add a timer showing how long the current call has been active
var timerDiv = document.createElement('div');
timerDiv.id = 'custom_call_timer';
timerDiv.style.cssText = 'position:fixed; top:5px; right:10px; font-size:18px; font-weight:bold; color:#333; z-index:9999; background:#fff; padding:5px 10px; border:1px solid #ccc; border-radius:4px;';
timerDiv.textContent = '00:00';
document.body.appendChild(timerDiv);
var seconds = 0;
var timerInterval = null;
// Watch for call state changes
setInterval(function() {
var statusEl = document.getElementById('MainStatuSSpan');
if (statusEl) {
var status = statusEl.textContent.trim();
if (status === 'INCALL' && !timerInterval) {
seconds = 0;
timerInterval = setInterval(function() {
seconds++;
var m = Math.floor(seconds / 60).toString().padStart(2, '0');
var s = (seconds % 60).toString().padStart(2, '0');
timerDiv.textContent = m + ':' + s;
}, 1000);
} else if (status !== 'INCALL' && timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
timerDiv.textContent = '00:00';
}
}
}, 500);
}, 2000);
})();
</script>
Via Web Forms:
JavaScript in a web form IFRAME can communicate with the parent VICIdial frame if they’re on the same origin:
// From within a web form IFRAME (same origin)
// Read agent data from parent frame
var agentUser = parent.document.getElementById('agentUser').value;
// Trigger a disposition in the parent frame
function triggerDisposition(statusCode) {
parent.DispoSelectContent_create(statusCode);
}
// Listen for call events
parent.addEventListener('message', function(event) {
// Handle call connect/disconnect events
});
Common JavaScript Customizations
Auto-populate fields from external data:
// Fetch additional lead data from your API and display it
fetch('/api/lead-details/' + leadId)
.then(r => r.json())
.then(data => {
// Display previous call history, account balance, etc.
var infoPanel = document.createElement('div');
infoPanel.innerHTML = '<b>Account Balance:</b> $' + data.balance +
'<br><b>Last Call:</b> ' + data.last_call_date +
'<br><b>Previous Agent:</b> ' + data.previous_agent;
document.getElementById('custom_info_area').appendChild(infoPanel);
});
Color-code the agent screen based on lead data:
// Change background color based on lead priority
var state = document.getElementById('address3').value; // state field
var highValueStates = ['CA', 'TX', 'FL', 'NY'];
if (highValueStates.includes(state)) {
document.body.style.backgroundColor = '#e8f5e9'; // Light green = high value
}
Custom notification sounds:
// Play a sound when a call connects
var connectSound = new Audio('/sounds/call-connect.mp3');
setInterval(function() {
var status = document.getElementById('MainStatuSSpan');
if (status && status.textContent.trim() === 'INCALL') {
connectSound.play();
}
}, 1000);
Custom Transfer Lists
Transfer lists control which extensions/groups agents can transfer calls to. Customizing these is essential for operations with multiple departments, closers, or external transfer destinations.
Configuring Transfer Groups
- Go to Admin → In-Groups (for queue-based transfers) or Admin → Presets (for direct transfers)
- Create In-Groups for each transfer destination
- In Campaign Detail → Closer Campaigns, select which In-Groups agents can transfer to
Custom Transfer Presets
For quick-dial transfers (direct to a phone number or extension):
- Admin → System Presets or Campaign Presets
- Create presets with descriptive names and destination numbers
Example for an insurance operation:
| Preset Name | Destination | Purpose |
|---|---|---|
| Medicare Closer | 8501 (In-Group extension) | Transfer qualified Medicare leads |
| Supervisor | SIP/1001 | Escalation to floor supervisor |
| Spanish Queue | 8502 | Transfer to Spanish-speaking closer |
| Compliance | SIP/1005 | Compliance department transfer |
| Warm Transfer | 8503 | Warm transfer queue (agent stays on line) |
Agents see these as buttons in the transfer dialog, eliminating the need to remember extension numbers.
Limitations and Workarounds
The VICIdial agent screen has real limitations that you should understand before investing significant development effort.
The Fundamental Architecture Constraint
The agent interface is a single PHP-generated page that loads once per session. It’s not a modern SPA with a component architecture, reactive data binding, or a design system. You cannot:
- Replace the interface wholesale with a React/Vue/Angular application (without forking VICIdial)
- Use CSS frameworks like Tailwind or Bootstrap without conflicts with VICIdial’s existing styles
- Guarantee that DOM modifications via JavaScript will persist across all state transitions
CSS Injection Limitations
VICIdial’s agent screen uses inline styles heavily. Your CSS overrides need !important on almost everything. Some elements are dynamically regenerated during call state transitions, resetting your CSS modifications. For persistent styling, use MutationObserver:
var observer = new MutationObserver(function(mutations) {
// Re-apply custom styles when the DOM changes
var elements = document.querySelectorAll('.your-target');
elements.forEach(function(el) {
el.style.backgroundColor = '#f0f0f0';
});
});
observer.observe(document.body, { childList: true, subtree: true });
IFRAME Communication Constraints
Web forms in IFRAMEs have full JavaScript access to the parent frame only if they’re on the same origin. If your web form is hosted on a different domain, you’re limited to postMessage. This means most external CRM integrations require either:
- Hosting the CRM interface on the same domain (via reverse proxy)
- Building a lightweight proxy page on the VICIdial domain that communicates with the CRM via API
- Using VICIdial’s own API endpoints from the CRM side
Mobile Responsiveness
The VICIdial agent screen is not responsive. It’s designed for desktop browsers at 1024px+ width. Remote agents on tablets or small laptops will have a degraded experience. The Wide layout helps on wide screens, but there’s no mobile layout. If you have remote agents on small screens, consider building a custom web form that is responsive and handles the data collection portion of the agent workflow.
Where ViciStack Fits In
Custom agent screen configurations are part of every ViciStack deployment. We build campaign-specific web forms, configure screen labels, set up hotkeys, integrate CRM systems via IFRAMEs, and ensure agents see exactly the data they need — nothing more, nothing less.
The agent interface is where your staff lives. Every unnecessary click, every confusing label, every missing piece of data costs you talk time and conversion rate. We’ve optimized agent screens for insurance, solar, home services, debt settlement, and B2B lead gen operations. We know which customizations matter for each vertical because we’ve deployed them across hundreds of centers.
ViciStack handles the customization so your agents can handle the calls.
Get a free agent experience audit →
This guide is maintained by the ViciStack team and updated as VICIdial releases add new customization capabilities. Last updated: March 2026.
Frequently Asked Questions
Can I completely replace the VICIdial agent interface with a custom UI?
Not without forking VICIdial’s code — which creates a maintenance nightmare on every SVN update. The supported approach is to customize within the existing framework using web forms, screen labels, and JavaScript injection. A common compromise: build an elaborate custom web form that handles 90% of what agents interact with, and use the native VICIdial interface only for call controls (answer, transfer, disposition, hangup). The web form IFRAME can be sized to dominate the screen while the VICIdial controls remain available.
How do I pass custom field data to a web form?
Custom fields created in Admin → Custom Fields are available using the same --A--fieldname--B-- syntax. If you created a custom field called policy_number, use --A--policy_number--B-- in your web form URL. The field name in the variable must match exactly what you entered in the Custom Fields configuration. Test with a simple web form that displays all received parameters before building your full form.
Can agents use keyboard shortcuts beyond hotkeys?
VICIdial’s built-in hotkey system is limited to disposition codes. For broader keyboard shortcuts (transfer, pause, callback), you’ll need JavaScript injection. The challenge is that VICIdial’s JavaScript already captures some key events, so your custom shortcuts need to be bound carefully to avoid conflicts. Use key combinations (Ctrl+Shift+T for transfer, etc.) rather than single keys to minimize conflicts.
How do I make the web form auto-update when a new call connects?
VICIdial automatically refreshes the web form IFRAME URL with new lead data when a call connects — as long as the Web Form URL contains --A-- variable placeholders. If your web form isn’t updating, check that: (1) the URL contains at least one --A--..--B-- variable, (2) the Web Form Target is set to IFRAME (not _blank), and (3) Auto-Open Web Form is enabled on the campaign.
Can I integrate Salesforce/HubSpot/Zoho directly into the agent screen?
Yes, via IFRAME. Set your Web Form URL to the CRM’s record page URL, passing the lead identifier. For Salesforce: https://yourorg.salesforce.com/lightning/r/Lead/--A--vendor_lead_code--B--/view. For HubSpot: https://app.hubspot.com/contacts/your-account/contact/--A--vendor_lead_code--B--. The CRM loads inside the agent screen IFRAME. Cross-origin restrictions prevent JavaScript communication between the CRM and VICIdial, but most CRM integrations only need one-directional data display. For bidirectional integration (CRM triggering VICIdial actions), use VICIdial’s non-agent API.
How do I test agent screen customizations without affecting production?
Create a test campaign with your custom screen labels, web forms, and scripts. Only assign test agents to it. This lets you iterate on customizations without impacting production campaigns. For JavaScript injection testing, use your browser’s developer console (F12) to test DOM manipulations before committing them to a Screen Labels entry. Once verified, apply the same configuration to your production campaign.
What’s the performance impact of heavy JavaScript customization?
Minimal for most customizations. The agent screen is a single long-lived page, so JavaScript initialization overhead happens once per session. However, aggressive use of setInterval for polling (like the call timer example) can add up. Each setInterval running at 500ms or less adds a small CPU cost. On modern browsers and hardware, 5-10 simultaneous intervals are fine. If you notice the agent screen becoming sluggish, check for runaway intervals or memory leaks in custom JavaScript.
Can I customize the manager/admin interface the same way?
The admin interface has different (more limited) customization options. Screen Labels only affect the agent screen. The admin interface can be modified via direct PHP file editing, but this breaks on VICIdial SVN updates. For admin customizations, the best approach is building separate custom admin pages that query VICIdial’s database directly and embedding them as links in the admin sidebar. This keeps your customizations independent of VICIdial’s update cycle.
Related Articles
The Complete VICIdial Setup Guide (2026): From Bare Metal to First Dial in Under 2 Hours
VICIdial New Features: Everything You Need to Know
VICIdial Predictive Dialer Settings: The 15 Configuration Changes That Actually Matter
Related Status Codes
Want These Results for Your Center?
Get a free performance audit from our VICIdial optimization experts. We'll identify the highest-impact changes for your specific setup.