How to Use ViciDial Real-Time Report for Campaign Monitoring
Master real-time call monitoring, agent performance tracking, and live campaign metrics in ViciDial to optimize your contact center operations and identify bottlenecks instantly.
Prerequisites
Before implementing real-time report monitoring in ViciDial, ensure you have:
- A fully functional ViciDial installation (version 2.10 or later recommended)
- SSH/terminal access to your ViciDial server
- MySQL/MariaDB administrative access
- Understanding of basic ViciDial campaign structure (campaigns, user accounts, inbound/outbound queues)
- Web browser access to the ViciDial admin interface (
http://your-server/vicidial/admin.php) - Asterisk running with proper CDR logging enabled
- Write permissions to
/var/log/asterisk/directory - At least one active campaign configured with agents
Understanding ViciDial Real-Time Reporting Architecture
How Real-Time Reports Work
ViciDial real-time reports pull data directly from the Asterisk database (asterisk schema) rather than relying on pre-calculated reports. The system queries active tables like vicidial_log, vicidial_closer_log, vicidial_list, and vicidial_users to display live metrics.
The key difference between real-time reports and historical reports:
- Real-time reports: Query current call activity, agent status, and campaign state every few seconds
- Historical reports: Aggregate completed data from
vicidial_logafter calls disconnect
Real-time reports use three primary data sources:
- vicidial_log - Individual call records with timestamps, results, and agent assignments
- vicidial_closer_log - Detailed call outcomes (sale, no-sale, callback, etc.)
- vicidial_users - Agent status and live availability
Database Table Structure
Understanding the relevant tables ensures you query the right data:
-- Check core tables for real-time data USE asterisk; DESCRIBE vicidial_log; DESCRIBE vicidial_closer_log; DESCRIBE vicidial_users; DESCRIBE vicidial_campaigns; Key columns in vicidial_log:
-
call_id- Unique call identifier -
campaign_id- Campaign this call belongs to -
user- Agent username -
call_date- Call timestamp -
call_type- INBOUND, OUTBOUND, etc. -
call_result- Final disposition -
call_length- Duration in seconds -
status- Current state (LIVE, COMPLETED, etc.)
Accessing the Real-Time Report Interface
Web-Based Real-Time Reports
The primary method to view real-time reports is through the ViciDial admin interface:
http://your-vicidial-server/vicidial/admin.php Steps to access real-time reports:
- Log in with your administrative account
- Navigate to Reports → Real-Time Reports (or Live Calls depending on version)
- Select your campaign from the dropdown
- The dashboard automatically refreshes every 5-10 seconds
Command-Line Real-Time Queries
For server-side monitoring or custom integrations, query the database directly:
# SSH into your ViciDial server ssh root@your-vicidial-server # Connect to MySQL mysql -u root -p # Select the asterisk database USE asterisk; Practical Real-Time Monitoring Queries
Query 1: Active Calls by Campaign (Last 5 Minutes)
SELECT c.campaign_name, COUNT(*) as active_calls, AVG(TIMESTAMPDIFF(SECOND, vl.call_date, NOW())) as avg_call_duration_sec, SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) as sales, ROUND(100.0 * SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) / COUNT(*), 2) as conversion_rate FROM vicidial_log vl INNER JOIN vicidial_campaigns c ON vl.campaign_id = c.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) AND vl.status IN ('LIVE', 'COMPLETED') GROUP BY c.campaign_name ORDER BY active_calls DESC; Output example:
+-----------------------+--------------+------------------------+-------+-----------------+ | campaign_name | active_calls | avg_call_duration_sec | sales | conversion_rate | +-----------------------+--------------+------------------------+-------+-----------------+ | Sales Campaign Q4 | 23 | 87 | 5 | 21.74| | Lead Qualification | 18 | 124 | 2 | 11.11| | Customer Retention | 7 | 45 | 1 | 14.29| +-----------------------+--------------+------------------------+-------+-----------------+ Query 2: Agent Performance Real-Time Snapshot
SELECT u.user, u.user_level, u.status, COUNT(vl.call_id) as calls_today, ROUND(AVG(vl.call_length), 1) as avg_call_length_sec, SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) as sales, ROUND(100.0 * SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) / COUNT(vl.call_id), 2) as sales_rate, MAX(vl.call_date) as last_call_time FROM vicidial_users u LEFT JOIN vicidial_log vl ON u.user = vl.user AND vl.call_date >= DATE_SUB(NOW(), INTERVAL 1 DAY) WHERE u.user_level > 0 AND u.active = 'Y' GROUP BY u.user, u.user_level, u.status ORDER BY sales DESC, calls_today DESC; Query 3: Queue Depth and Wait Times
SELECT vc.campaign_id, vc.campaign_name, vc.dial_method, COUNT(DISTINCT vl.call_id) as current_queue_depth, ROUND(AVG(TIMESTAMPDIFF(SECOND, vl.call_date, NOW())), 0) as avg_queue_wait_sec, COUNT(DISTINCT vl.user) as available_agents FROM vicidial_log vl INNER JOIN vicidial_campaigns vc ON vl.campaign_id = vc.campaign_id WHERE vl.status = 'LIVE' AND vl.call_date >= DATE_SUB(NOW(), INTERVAL 10 MINUTE) GROUP BY vc.campaign_id, vc.campaign_name, vc.dial_method; Query 4: Real-Time Call Result Distribution
SELECT vc.campaign_id, vc.campaign_name, vl.call_result, COUNT(*) as result_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM vicidial_log WHERE campaign_id = vc.campaign_id AND call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR)), 2) as percentage FROM vicidial_log vl INNER JOIN vicidial_campaigns vc ON vl.campaign_id = vc.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) GROUP BY vc.campaign_id, vc.campaign_name, vl.call_result ORDER BY result_count DESC; Building Custom Real-Time Monitoring Dashboards
Creating a Shell Script for Continuous Monitoring
Create a bash script that polls real-time data and displays it in the terminal:
#!/bin/bash # File: /usr/local/bin/vicidial-monitor.sh # Real-time ViciDial monitoring script MYSQL_USER="root" MYSQL_PASS="your_mysql_password" DB_NAME="asterisk" REFRESH_INTERVAL=10 function get_active_calls() { mysql -u $MYSQL_USER -p$MYSQL_PASS $DB_NAME -e " SELECT c.campaign_name, COUNT(*) as active_calls, SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) as sales FROM vicidial_log vl INNER JOIN vicidial_campaigns c ON vl.campaign_id = c.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) AND vl.status IN ('LIVE', 'COMPLETED') GROUP BY c.campaign_name ORDER BY active_calls DESC; " } function get_agent_status() { mysql -u $MYSQL_USER -p$MYSQL_PASS $DB_NAME -e " SELECT user, status, COUNT(*) as count FROM vicidial_users WHERE user_level > 0 GROUP BY user, status; " } # Main loop while true; do clear echo "====== VICIDIAL REAL-TIME MONITOR ======" echo "Refresh Time: $(date '+%Y-%m-%d %H:%M:%S')" echo "" echo "--- ACTIVE CALLS BY CAMPAIGN ---" get_active_calls echo "" echo "--- AGENT STATUS SUMMARY ---" get_agent_status echo "" echo "Next refresh in $REFRESH_INTERVAL seconds..." sleep $REFRESH_INTERVAL done Make it executable:
chmod +x /usr/local/bin/vicidial-monitor.sh # Run it /usr/local/bin/vicidial-monitor.sh PHP-Based Real-Time Dashboard
Create a lightweight PHP dashboard for web access:
<?php // File: /var/www/html/vicidial/real-time-dashboard.php // Simple real-time dashboard header('Content-Type: text/html; charset=utf-8'); $db_host = 'localhost'; $db_user = 'root'; $db_pass = 'password'; $db_name = 'asterisk'; $conn = new mysqli($db_host, $db_user, $db_pass, $db_name); if ($conn->connect_error) { die("Database connection failed: " . $conn->connect_error); } // Query active calls $query = " SELECT c.campaign_name, COUNT(*) as active_calls, SUM(CASE WHEN vl.call_result = 'SALE' THEN 1 ELSE 0 END) as sales, AVG(vl.call_length) as avg_duration FROM vicidial_log vl INNER JOIN vicidial_campaigns c ON vl.campaign_id = c.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) AND vl.status IN ('LIVE', 'COMPLETED') GROUP BY c.campaign_name ORDER BY active_calls DESC "; $result = $conn->query($query); ?> <!DOCTYPE html> <html> <head> <title>ViciDial Real-Time Monitor</title> <meta http-equiv="refresh" content="10"> <style> body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; } table { border-collapse: collapse; width: 100%; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #4CAF50; color: white; } tr:hover { background-color: #f5f5f5; } .metric { font-weight: bold; color: #2196F3; } .sales { color: #4CAF50; } .timestamp { color: #999; font-size: 0.9em; } </style> </head> <body> <h1>ViciDial Real-Time Report - Campaign Monitor</h1> <p class="timestamp">Last Updated: <?php echo date('Y-m-d H:i:s'); ?></p> <table> <tr> <th>Campaign Name</th> <th class="metric">Active Calls</th> <th class="sales">Sales</th> <th>Avg Duration (sec)</th> </tr> <?php if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { echo "<tr>"; echo "<td>" . htmlspecialchars($row['campaign_name']) . "</td>"; echo "<td class='metric'>" . $row['active_calls'] . "</td>"; echo "<td class='sales'>" . $row['sales'] . "</td>"; echo "<td>" . round($row['avg_duration'], 1) . "</td>"; echo "</tr>"; } } else { echo "<tr><td colspan='4'>No active calls</td></tr>"; } ?> </table> </body> </html> <?php $conn->close(); ?> Access it at: http://your-server/vicidial/real-time-dashboard.php
Monitoring Specific Metrics for Campaign Health
Call Abandonment Rate
SELECT vc.campaign_name, COUNT(*) as total_calls, SUM(CASE WHEN vl.call_result = 'ABANDON' THEN 1 ELSE 0 END) as abandoned, ROUND(100.0 * SUM(CASE WHEN vl.call_result = 'ABANDON' THEN 1 ELSE 0 END) / COUNT(*), 2) as abandon_rate FROM vicidial_log vl INNER JOIN vicidial_campaigns vc ON vl.campaign_id = vc.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR) AND vl.call_type = 'INBOUND' GROUP BY vc.campaign_name HAVING abandon_rate > 10.0 ORDER BY abandon_rate DESC; Average Handle Time (AHT) by Agent
SELECT u.user, COUNT(*) as calls, ROUND(AVG(vl.call_length), 0) as aht_seconds, ROUND(AVG(vl.call_length) / 60, 2) as aht_minutes, ROUND(SUM(vl.call_length) / 3600, 1) as total_talk_hours FROM vicidial_log vl INNER JOIN vicidial_users u ON vl.user = u.user WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 8 HOUR) AND vl.call_type = 'OUTBOUND' GROUP BY u.user ORDER BY aht_seconds DESC; Dial-Through Rate (Predictive/Progressive Dialing)
SELECT vc.campaign_name, vc.dial_method, COUNT(*) as total_dials, SUM(CASE WHEN vl.call_result NOT IN ('NO ANSWER', 'BUSY') THEN 1 ELSE 0 END) as connections, ROUND(100.0 * SUM(CASE WHEN vl.call_result NOT IN ('NO ANSWER', 'BUSY') THEN 1 ELSE 0 END) / COUNT(*), 2) as connect_rate FROM vicidial_log vl INNER JOIN vicidial_campaigns vc ON vl.campaign_id = vc.campaign_id WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) AND vl.call_type = 'OUTBOUND' GROUP BY vc.campaign_name, vc.dial_method; Configuring Alerts for Campaign Issues
Setting Up Threshold-Based Alerts
Create a monitoring script that sends alerts when metrics exceed thresholds:
#!/bin/bash # File: /usr/local/bin/vicidial-alert-monitor.sh # Alert when metrics exceed thresholds MYSQL_USER="root" MYSQL_PASS="password" DB_NAME="asterisk" EMAIL_TO="admin@company.com" # Check abandon rate ABANDON_RATE=$(mysql -u $MYSQL_USER -p$MYSQL_PASS $DB_NAME -N -e " SELECT MAX(abandon_pct) FROM ( SELECT ROUND(100.0 * SUM(CASE WHEN call_result = 'ABANDON' THEN 1 ELSE 0 END) / COUNT(*), 2) as abandon_pct FROM vicidial_log WHERE call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) AND call_type = 'INBOUND' GROUP BY campaign_id ) subquery; ") ABANDON_THRESHOLD=15 if (( $(echo "$ABANDON_RATE > $ABANDON_THRESHOLD" | bc -l) )); then echo "ALERT: Abandon rate is ${ABANDON_RATE}% (threshold: ${ABANDON_THRESHOLD}%)" | \ mail -s "ViciDial Alert: High Abandon Rate" $EMAIL_TO fi # Check active agent availability AVAILABLE_AGENTS=$(mysql -u $MYSQL_USER -p$MYSQL_PASS $DB_NAME -N -e " SELECT COUNT(*) FROM vicidial_users WHERE user_level > 0 AND status IN ('READY', 'PAUSED') AND active = 'Y' ") QUEUE_DEPTH=$(mysql -u $MYSQL_USER -p$MYSQL_PASS $DB_NAME -N -e " SELECT COUNT(*) FROM vicidial_log WHERE status = 'LIVE' AND call_date >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ") if [ "$AVAILABLE_AGENTS" -lt 5 ] && [ "$QUEUE_DEPTH" -gt 20 ]; then echo "ALERT: Low agent availability ($AVAILABLE_AGENTS agents) with queue depth at $QUEUE_DEPTH calls" | \ mail -s "ViciDial Alert: Understaffing Risk" $EMAIL_TO fi Add to crontab to run every minute:
crontab -e # Add this line: * * * * * /usr/local/bin/vicidial-alert-monitor.sh Performance Optimization for Real-Time Reports
Database Indexing for Faster Queries
Large ViciDial installations can experience slow real-time reports without proper indexing:
-- Add indexes if they don't exist ALTER TABLE vicidial_log ADD INDEX idx_call_date (call_date); ALTER TABLE vicidial_log ADD INDEX idx_campaign_status (campaign_id, status); ALTER TABLE vicidial_log ADD INDEX idx_user_date (user, call_date); ALTER TABLE vicidial_closer_log ADD INDEX idx_call_date (call_date); -- Verify indexes exist SHOW INDEX FROM vicidial_log; Limiting Query Scope
Never query unbounded date ranges in production:
-- GOOD: Limited to last hour WHERE vl.call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) -- BAD: No date filter - scans entire table WHERE vl.user = 'john.smith' Using READ REPLICAS for Reporting
For high-volume operations, query a read replica instead of the production database:
# Example: Redirect reporting queries to replica REPLICA_HOST="vicidial-replica.internal" REPLICA_USER="report_user" REPLICA_PASS="replica_password"<...