Skip to content
Vicidial Predictive Dialer Tuning: Maximizing Agent Productivity
Dialer

Vicidial Predictive Dialer Tuning: Maximizing Agent Productivity

Tune Vicidial's predictive dialer for maximum agent productivity: dial ratio math, abandon rate compliance, MySQL query optimization, and Asterisk AGI integration patterns.

Tumarm Engineering9 min read

Vicidial Predictive Dialer Tuning: Maximizing Agent Productivity

Vicidial is the most widely deployed open-source predictive dialer. A default installation works. A tuned installation delivers 45–55 minutes of talk time per agent hour instead of the 30–35 minutes most teams see out of the box. The difference comes down to dial ratio math, database query performance, and understanding how Vicidial's adaptive algorithm responds to your specific lead list and agent pool characteristics.

How the Predictive Algorithm Works

Vicidial's predictive dialer uses an adaptive algorithm that continuously adjusts the dial ratio (calls dialed per available agent) based on recent outcome statistics. The core formula:

dial_ratio = available_agents × (1 / (1 - target_abandon_rate)) × safety_margin

Where:

  • target_abandon_rate is typically 3% (FTC limit in the US) or 5% (Ofcom limit in the UK)
  • safety_margin is 0.85–0.95 (accounts for prediction error)

At 3% target abandon rate: dial_ratio = agents × 1.031 × 0.9 ≈ agents × 0.928

This means with 10 available agents, Vicidial should be dialing roughly 9–10 simultaneous calls. Many installations are tuned too conservatively (ratio 1.2:1) or too aggressively (ratio 3:1), both of which hurt productivity.

Key Vicidial Campaign Settings

Navigate to Admin > Campaigns > Edit Campaign for each campaign you want to tune:

SettingDefaultRecommendedEffect
dial_ratio1.0AdaptiveCalls per available agent
auto_dial_levelMANUALADAPT_TANHUse adaptive algorithm
adaptive_dropped_percentage33FTC compliance target
dial_timeout3020–25Seconds before AMD / abandon
drop_call_seconds32Seconds before drop if no agent
dead_seconds10Delay before drop (set 0)
available_only_ratioNYOnly count truly available agents
calls_waiting_size_limit02Calls waiting buffer

Setting auto_dial_level=ADAPT_TANH activates Vicidial's built-in adaptive mode. The TANH variant uses a hyperbolic tangent function to smooth ratio adjustments, preventing the oscillation you see with ADAPT_AVERAGE when agent availability spikes or drops suddenly.

Answering Machine Detection (AMD) Tuning

AMD is the biggest lever for talk-time productivity. Vicidial uses Asterisk's AMD application, which analyzes audio energy and silence patterns to classify calls as human or machine. Poor AMD configuration causes two problems:

  • False positives (humans classified as machines) — agents never hear the call
  • False negatives (machines passed to agents) — agents hear voicemail, waste time

Tune these parameters in /etc/asterisk/amd.conf:

[general]
initial_silence = 2500      ; Max silence before first word (ms)
greeting = 1500             ; Max length of greeting (ms)
after_greeting_silence = 800 ; Silence after greeting = machine
total_analysis_time = 5000  ; Max time to analyze
min_word_length = 100       ; Min word length (ms) — below this is noise
between_words_silence = 50  ; Silence between words = word boundary
maximum_number_of_words = 3 ; If > 3 words, probably machine
silence_threshold = 256     ; Energy threshold for silence detection
maximum_word_length = 5000  ; Single word longer than this = machine

Measure your AMD accuracy weekly. In a well-tuned system:

  • Human detection rate: >90%
  • Machine detection rate: >70%
  • False positive rate (human called machine): <5%

Log AMD results via Vicidial's call_log table and query accuracy:

SELECT
    call_date::date AS day,
    SUM(CASE WHEN status = 'AMD' THEN 1 ELSE 0 END) AS machine_detected,
    SUM(CASE WHEN status IN ('SALE', 'NI', 'NA', 'DNC') THEN 1 ELSE 0 END) AS human_connected,
    SUM(CASE WHEN status = 'DROP' THEN 1 ELSE 0 END) AS dropped,
    COUNT(*) AS total_calls,
    ROUND(
        100.0 * SUM(CASE WHEN status IN ('SALE','NI','NA','DNC') THEN 1 ELSE 0 END) / COUNT(*),
        1
    ) AS connect_rate_pct
FROM vicidial_log
WHERE call_date > NOW() - INTERVAL '7 days'
GROUP BY call_date::date
ORDER BY day DESC;

MySQL Performance Optimization

Vicidial is heavily database-driven. The predictive algorithm queries the vicidial_list table every second to select leads. On large campaigns (1M+ records), this query becomes the bottleneck.

Critical indexes:

-- vicidial_list: compound index for lead selection query
ALTER TABLE vicidial_list
ADD INDEX status_order_idx (status, list_id, gmt_offset_now, called_count, lead_id);

-- vicidial_log: index for recent performance queries
ALTER TABLE vicidial_log
ADD INDEX campaign_date_idx (campaign_id, call_date, status);

-- vicidial_agent_log: index for real-time agent stats
ALTER TABLE vicidial_agent_log
ADD INDEX agent_campaign_idx (campaign_id, event_time, user);

MySQL configuration for a dedicated Vicidial database server (32 GB RAM):

[mysqld]
innodb_buffer_pool_size = 24G        # 75% of RAM
innodb_buffer_pool_instances = 8
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2   # Faster writes, minimal data loss risk
innodb_flush_method = O_DIRECT
query_cache_type = 0                  # Disable — Vicidial invalidates it constantly
max_connections = 500
thread_cache_size = 64
table_open_cache = 4000

innodb_flush_log_at_trx_commit=2 flushes the log buffer to OS every second rather than every transaction. On Vicidial's write-heavy workload, this typically doubles write throughput with negligible durability risk (you lose at most 1 second of data on crash, and CDRs are also in Asterisk).

Real-Time Agent Monitoring via ESL

Vicidial's built-in monitoring dashboard polls the database, which adds 1–3 second lag. For real-time dashboards, connect directly to Asterisk's Event Socket Layer:

import socket

def monitor_active_calls():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('127.0.0.1', 8021))
    
    # Authenticate
    sock.sendall(b'auth ClueCon\r\n\r\n')
    response = sock.recv(1024)
    
    # Subscribe to channel events
    sock.sendall(b'event plain CHANNEL_CREATE CHANNEL_HANGUP CHANNEL_BRIDGE\r\n\r\n')
    
    while True:
        data = sock.recv(4096).decode()
        if 'CHANNEL_CREATE' in data:
            process_new_call(data)
        elif 'CHANNEL_HANGUP' in data:
            process_hangup(data)
        elif 'CHANNEL_BRIDGE' in data:
            process_agent_connected(data)

ESL events arrive within 50ms of the actual channel event — fast enough to update a real-time dashboard without database polling.

Compliance: Abandon Rate Enforcement

US FTC regulations require abandon rates below 3% per campaign per 30-day period. Vicidial's adaptive mode tracks this internally, but you should also verify from the database:

-- Monthly abandon rate by campaign (FTC calculation)
SELECT
    campaign_id,
    COUNT(*) AS total_connected,
    SUM(CASE WHEN status = 'DROP' THEN 1 ELSE 0 END) AS abandoned,
    ROUND(
        100.0 * SUM(CASE WHEN status = 'DROP' THEN 1 ELSE 0 END) / COUNT(*),
        2
    ) AS abandon_rate_pct
FROM vicidial_log
WHERE call_date >= DATE_TRUNC('month', NOW())
  AND status NOT IN ('AMD', 'CBHOLD', 'CFAIL')  -- Exclude non-connected
GROUP BY campaign_id
HAVING abandon_rate_pct > 2.5  -- Alert before hitting 3% limit
ORDER BY abandon_rate_pct DESC;

Run this query from a cron job every hour and alert when any campaign approaches 2.5%. At 2.5% you have margin to reduce the dial ratio before crossing the compliance threshold.

Lead List Hygiene

A clean lead list has a larger impact on agent productivity than any algorithm tuning. Before loading a list:

  1. Scrub against the National Do Not Call Registry (required by law)
  2. Remove duplicates by phone number within the last 30 days
  3. Filter disconnected numbers using carrier lookup APIs (Twilio Lookup, Numverify)
  4. Set time zone based on area code — never dial outside 8 AM–9 PM local time

A list with 20% bad numbers means 20% of your dial capacity is wasted on disconnects. Carrier lookup APIs cost $0.005–$0.01 per number. On a 100,000-number list, $500–$1,000 of cleanup saves significant agent idle time over the campaign lifetime.

Expected Results After Tuning

MetricBefore tuningAfter tuning
Agent talk time per hour32 min48 min
Connect rate18%28%
AMD accuracy65%88%
Abandon rate8%2.5%
DB query time (lead select)800ms45ms

These numbers come from a 50-agent campaign on a list of 500,000 records after applying the indexes, AMD tuning, and adaptive dial level changes described above.

vicidialpredictive-dialerasteriskcall-centerdialer-tuningagi
Benchmark
BALI Pvt.Ltd
Brave BPO
Wave
SmartBrains BPO

Ready to build on carrier-grade voice?

Talk to a VoIP engineer — not a salesperson.