How to Configure ViciDial Closer Campaigns & In-Groups

Master the complete process of setting up closer campaigns and in-groups in ViciDial, from database configuration through agent assignment and real-time monitoring.

Prerequisites

Before proceeding with closer campaign and in-group configuration, ensure you have:

  • ViciDial installation (3.14+ recommended) with working Asterisk (16+)
  • Database access: Direct MySQL/MariaDB access to the asterisk database
  • Admin credentials: Access to /vicidial/admin.php with administrator role
  • Asterisk CLI access: Ability to run asterisk -rx commands
  • Existing dialplans: At least one active dialer campaign configured
  • User accounts: Multiple agents already created in ViciDial system
  • In-group defined: A primary in-group created before closer assignment
  • SSH/Shell access to ViciDial server with sudo privileges

Understanding Closer Campaigns vs In-Groups

What Are Closer Campaigns?

Closer campaigns are ViciDial's mechanism for transferring live inbound calls or callbacks to specific agents who specialize in closing sales. Unlike dialer campaigns that push calls outbound, closer campaigns pull inbound calls into a queue for assignment to available agents.

Key characteristics:

  • Receive transferred calls from dialer campaigns or direct phone numbers
  • Queue calls until agent availability
  • Track transfer times and call dispositions separately
  • Support multiple in-groups within one closer campaign
  • Integrate with DNC (Do Not Call) lists and custom call rules

What Are In-Groups?

In-groups are the actual agent queues where calls wait for assignment. A closer campaign may have multiple in-groups (e.g., "Sales", "Support", "Escalations"), each with distinct:

  • Member agents with individual priorities
  • Call handling rules and routing logic
  • Recording preferences
  • Custom CID masking
  • Hold music and announcements

The relationship: Closer Campaign contains In-Groups containing Agents

Part 1: Create the Closer Campaign via Web UI

Step 1.1: Access Campaign Configuration

  1. Log into /vicidial/admin.php with administrator account
  2. Navigate: Admin → Campaigns → Add New Campaign
  3. Select Campaign Type: "Closer"
  4. Fill in campaign details:
Field Example Value Notes
Campaign ID CLOSER_SALES Uppercase, no spaces, 2-20 chars
Campaign Name Sales Closer Campaign Human-readable name
Active YES Enable immediately
Outbound CID 18005551234 Caller ID for transfers
Outbound CID Name Sales Dept Display name (optional)
Phone Number 18005551000 DID for external transfers
Call Time Zone America/Chicago Agent's timezone
Use Asterisk YES Required for call routing

Step 1.2: Configure Callback and Transfer Settings

In the same campaign creation form:

Callback Auto Hold Minutes: 5 Callback Auto Dial: YES Campaigns to receive from: DIALER_SALES,DIALER_LEADS Transfer Timeout Seconds: 45 Voicemail Extension: 9999 Call Recording: ALWAYS Recording Call Display Name: CLOSER_SALES Lead ID Prefix: CS- 

Critical setting: Leave "Closer Dial Campaign" BLANK (this is for callbacks originated from closer agents, not for receiving transfers)

Step 1.3: Save and Verify

Click SUBMIT. ViciDial will:

  1. Create campaign record in vicidial_campaigns table
  2. Create campaign contexts in /etc/asterisk/extensions-vicidial.conf
  3. Generate default dialplan extensions

Verify creation:

mysql -u root -p asterisk -e "SELECT campaign_id, campaign_name, campaign_type, active FROM vicidial_campaigns WHERE campaign_id='CLOSER_SALES';" 

Expected output:

| CLOSER_SALES | Sales Closer Campaign | CLOSER | Y | 

Part 2: Create In-Groups Within the Closer Campaign

Step 2.1: In-Group Fundamentals

In-groups are the actual call queues. You must create at least one in-group per closer campaign. Most production environments have 2-4 in-groups:

  • Primary in-group: Handles all standard transfers
  • Overflow in-group: Secondary queue when primary is full
  • VIP in-group: Dedicated high-value customer queue
  • Escalation in-group: Complex issues requiring senior agents

Step 2.2: Create In-Group via Database

While ViciDial admin UI has in-group creation, direct database insertion is faster for bulk setup:

INSERT INTO vicidial_ingroups ( ingroup_id, campaign_id, ingroup_name, description, active, callback_grp, phone_number, voicemail_ext, hold_music, recording_call_display_name, call_timeout, call_priority, full_set_queue_exten, customer_greeting, agent_greeting, in_group_digits ) VALUES ( 'CLOSER_SALES_MAIN', 'CLOSER_SALES', 'Sales Main Queue', 'Primary in-group for sales closer campaign', 'Y', 'Y', '18005551000', '9999', 'default', 'CLOSER_SALES_MAIN', '120', '1', '1', 'Thanks for calling. A representative will be with you shortly.', 'Thank you for calling. Please give me one moment while I retrieve your information.', '' ); 

Key fields explanation:

  • ingroup_id: Unique identifier across system (24 chars max)
  • callback_grp: Allow agents to callback? Set 'Y' for closer queues
  • call_timeout: Seconds before call abandons from queue (120-300 typical)
  • call_priority: Lower number = higher priority (1-5 range)
  • full_set_queue_exten: Extension when queue full (usually extension 1)
  • recording_call_display_name: Identifies recording in playback system

Step 2.3: Create Secondary In-Group (Overflow)

INSERT INTO vicidial_ingroups ( ingroup_id, campaign_id, ingroup_name, description, active, callback_grp, phone_number, voicemail_ext, hold_music, call_timeout, call_priority, full_set_queue_exten ) VALUES ( 'CLOSER_SALES_OVERFLOW', 'CLOSER_SALES', 'Sales Overflow Queue', 'Overflow for sales closer campaign', 'Y', 'Y', '18005551001', '9999', 'default', '150', '2', '1' ); 

Step 2.4: Verify In-Group Creation

mysql -u root -p asterisk -e "SELECT ingroup_id, campaign_id, ingroup_name, active, call_timeout FROM vicidial_ingroups WHERE campaign_id='CLOSER_SALES';" 

Expected:

| CLOSER_SALES_MAIN | CLOSER_SALES | Sales Main Queue | Y | 120 | | CLOSER_SALES_OVERFLOW | CLOSER_SALES | Sales Overflow Queue| Y | 150 | 

Part 3: Assign Agents to In-Groups

Step 3.1: Add Agent Memberships

Agents must be explicitly assigned to in-groups via the vicidial_ingroup_agents table. Each agent can belong to multiple in-groups with different priorities and statuses:

INSERT INTO vicidial_ingroup_agents ( ingroup_id, user_id, agent_priority, lead_id, agent_status, closer_flag ) VALUES ('CLOSER_SALES_MAIN', 'agent001', 1, '0', 'ACTIVE', 'Y'), ('CLOSER_SALES_MAIN', 'agent002', 2, '0', 'ACTIVE', 'Y'), ('CLOSER_SALES_MAIN', 'agent003', 3, '0', 'ACTIVE', 'Y'), ('CLOSER_SALES_OVERFLOW', 'agent004', 1, '0', 'ACTIVE', 'Y'), ('CLOSER_SALES_OVERFLOW', 'agent002', 2, '0', 'ACTIVE', 'Y'); 

Field explanations:

  • agent_priority: 1=highest priority, 9=lowest. Lower number gets called first
  • closer_flag: 'Y' = this agent handles closer calls (must be 'Y')
  • agent_status: 'ACTIVE'='available', 'INACTIVE'='unavailable', 'DELETED'='removed'
  • lead_id: Usually '0' for in-group assignments; can specify a particular lead

Step 3.2: Configure Individual Agent Closer Permissions

Each agent needs ViciDial user account flags enabled. Update the vicidial_users table:

UPDATE vicidial_users SET closer_enabled = '1', closer_campaigns = 'CLOSER_SALES', call_transfer_flag = '1', no_outbound_calls = '0', can_transfer_to_other_users = '1' WHERE user_id IN ('agent001', 'agent002', 'agent003', 'agent004'); 

Critical fields:

  • closer_enabled: Set to '1' to allow agent to receive closer calls
  • closer_campaigns: Comma-separated list of campaigns agent can handle
  • call_transfer_flag: Enables blind/attended transfers
  • can_transfer_to_other_users: Allows warm transfer to other agents

Verify settings:

mysql -u root -p asterisk -e "SELECT user_id, closer_enabled, closer_campaigns FROM vicidial_users WHERE user_id IN ('agent001','agent002','agent003','agent004');" 

Step 3.3: Set Agent Pause Codes for In-Group Work

Create pause codes specific to closer work:

INSERT INTO vicidial_pause_codes ( pause_code, pause_name, inbound_seconds, outbound_seconds, active ) VALUES ('CLOSER', 'Closer Call In Progress', 0, 0, 'Y'), ('CLOSER_BREAK', 'Closer Break', 300, 300, 'Y'), ('CLOSER_LUNCH', 'Closer Lunch', 3600, 3600, 'Y'); 

These codes appear in agent's pause dropdown in /agc/vicidial.php interface.

Part 4: Configure Asterisk Dialplan Integration

Step 4.1: Verify Auto-Generated Extensions

ViciDial automatically creates extensions when you add a closer campaign. Verify in /etc/asterisk/extensions-vicidial.conf:

grep -A 30 "exten => 8900,1" /etc/asterisk/extensions-vicidial.conf | head -40 

You should see auto-generated closer campaign context. If missing, manually trigger regeneration:

/usr/share/astguiclient/astguiclient_closer_extension_sync.pl 

Step 4.2: Create Custom Transfer Extension (Optional)

To allow dialer agents to transfer calls to closer campaign, add to /etc/asterisk/extensions-vicidial.conf:

[ViciDial-Closer-Transfer] exten => 1,1,NoOp(Closer Transfer Request to ${closer_queue}) same => n,ViciDialCloserQueue(${closer_queue}|${closer_priority}|${CALLERID(num)}) same => n,Hangup() exten => i,1,NoOp(Invalid extension) same => n,Playback(invalid) same => n,Hangup() exten => t,1,NoOp(Transfer timeout) same => n,Hangup() 

Step 4.3: Reload Asterisk Configuration

asterisk -rx "dialplan reload" 

Verify dialplan loaded:

asterisk -rx "dialplan show ViciDial-Closer-Transfer" 

Expected output:

[ ViciDial-Closer-Transfer ] '1' => 1. NoOp(Closer Transfer Request to ${closer_queue}) 2. ViciDialCloserQueue(${closer_queue}|${closer_priority}|${CALLERID(num)}) 3. Hangup() 

Part 5: Test the Closer Campaign

Step 5.1: Pre-Test Verification Checklist

Before testing, verify all components in database:

#!/bin/bash # Test script for closer campaign setup CAMPAIGN="CLOSER_SALES" DB="asterisk" echo "=== Campaign Configuration ===" mysql -u root -p "$DB" -e "SELECT campaign_id, campaign_type, active FROM vicidial_campaigns WHERE campaign_id='$CAMPAIGN';" echo -e "\n=== In-Groups ===" mysql -u root -p "$DB" -e "SELECT ingroup_id, ingroup_name, active FROM vicidial_ingroups WHERE campaign_id='$CAMPAIGN';" echo -e "\n=== Agent Assignments ===" mysql -u root -p "$DB" -e "SELECT ingroup_id, user_id, agent_priority, closer_flag FROM vicidial_ingroup_agents WHERE ingroup_id LIKE '$CAMPAIGN%';" echo -e "\n=== Agent Closer Status ===" mysql -u root -p "$DB" -e "SELECT user_id, closer_enabled, closer_campaigns FROM vicidial_users WHERE closer_enabled='1' LIMIT 5;" 

Run this script:

chmod +x test_closer_config.sh ./test_closer_config.sh 

Step 5.2: Manual Agent Availability Test

Log in agents to the system and verify they appear available for closer calls:

# Check current agent statuses mysql -u root -p asterisk -e "SELECT user_id, status, campaign_id, on_call FROM vicidial_users WHERE user_id IN ('agent001','agent002','agent003');" 

Step 5.3: Simulate Incoming Call to In-Group

Use Asterisk CLI to originate test call:

asterisk -rx "channel originate SIP/2000 extension 8900@CLOSER_SALES_MAIN-inbound" 

Monitor Asterisk logs in real-time:

tail -f /var/log/asterisk/messages | grep -i "closer\|ingroup\|queue" 

Step 5.4: Monitor Call Routing

Check Asterisk queue status:

asterisk -rx "queue show CLOSER_SALES_MAIN" 

Expected output:

CLOSER_SALES_MAIN has 0 calls (max unlimited) in 'rrordered' strategy agent001 (SIP/2000) (paused) (Not in call, paused 0m 45s) agent002 (SIP/2001) (ready) (Penalty: 2) agent003 (SIP/2002) (ready) (Penalty: 3) 

Step 5.5: Verify Call Logging

After test call completes, verify logs:

mysql -u root -p asterisk -e " SELECT call_id, caller_id, customer_id, campaign_id, start_time, call_duration, status FROM vicidial_closer_log WHERE campaign_id='CLOSER_SALES' ORDER BY start_time DESC LIMIT 5; " 

Part 6: Advanced Configuration

Step 6.1: Implement Call Distribution Strategy

Closer in-groups support multiple distribution strategies. Configure in vicidial_ingroups:

UPDATE vicidial_ingroups SET call_distribution_method = 'rrordered', max_concurrent_calls = '5', force_return_to_hold = 'N' WHERE ingroup_id = 'CLOSER_SALES_MAIN'; 

Distribution methods:

  • rrordered: Round-robin by agent priority (default, recommended)
  • leastrecent: Agent with oldest last call
  • fewestcalls: Agent with fewest total calls today
  • random: Random agent selection

Step 6.2: Configure Callback Rules

Allow agents in closer campaign to schedule callbacks:

UPDATE vicidial_campaigns SET closer_dial_campaign = 'CLOSER_SALES_CB', callback_dial_method = 'MANUAL', callback_hours_start = '08:00:00', callback_hours_end = '20:00:00' WHERE campaign_id = 'CLOSER_SALES'; 

This requires a separate dialer campaign (CLOSER_SALES_CB) created for callback origination.

Step 6.3: Implement DNC (Do Not Call) Filtering

Link in-group to DNC lists:

INSERT INTO vicidial_ingroup_dnc_filters ( ingroup_id, dnc_filter_id, active ) VALUES ('CLOSER_SALES_MAIN', 'FEDERAL_DNC', 'Y'), ('CLOSER_SALES_MAIN', 'COMPANY_DNC', 'Y'), ('CLOSER_SALES_MAIN', 'INTERNAL_DNC', 'Y'); 

Step 6.4: Set Up Custom CID Masking

Force specific outbound CID for transfers from this in-group:

UPDATE vicidial_ingroups SET outbound_cid = '18005551234', outbound_cid_name = 'Sales Department', cid_mask_method = 'FORCED' WHERE ingroup_id = 'CLOSER_SALES_MAIN'; 

Step 6.5: Configure Call Recording Exceptions

Set custom recording preferences:

UPDATE vicidial_ingroups SET recording_call_display_name = 'CLOSER_SALES_MAIN_REC', call_recording_compression = '32', call_recording_quality = 'gsm', recording_enabled = 'Y' WHERE ingroup_id = 'CLOSER_SALES_MAIN'; 

Part 7: Performance Tuning

Step 7.1: Optimize Queue Timeout Settings

Based on team size and call volume, adjust timeouts:

UPDATE vicidial_ingroups SET call_timeout = '120', -- 2 min normal calls callback_timeout = '180' -- 3 min callbacks WHERE ingroup_id = 'CLOSER_SALES_MAIN'; 

Monitor actual wait times:

mysql -u root -p asterisk -e " SELECT DATE(start_time) as Date, COUNT(*) as Total_Calls, AVG(wait_time) as Avg_Wait_Sec, MAX(wait_time) as Max_Wait_Sec FROM vicidial_closer_log WHERE campaign_id='CLOSER_SALES' AND start_time > DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(start_time) ORDER BY Date DESC; " 

Step 7.2: Monitor Agent Adherence to In-Group

Track agent time allocation across in-groups:

SELECT user_id, ingroup_id, COUNT(*) as calls_handled, AVG(call_duration) as avg_duration, SUM(call_duration) as total_talk_time FROM vicidial_closer_log WHERE DATE(start_time) = CURDATE() GROUP BY user_id, ingroup_id ORDER BY total_talk_time DESC; 

Step 7.3: Set Agent Concurrent Call Limits

Prevent single agent from receiving multiple simultaneous calls:

UPDATE vicidial_users SET max_concurrent_calls = '1', force_logout_after_seconds = '0' WHERE user_id IN ('agent001', 'agent002', 'agent003', 'agent004'); 

Part 8: Troubleshooting

Issue: Calls Not Routing to In-Group

Symptom: Incoming calls to DID don't reach agent queues, instead hangup or disconnect.

Root causes & solutions:

  1. Campaign not active:
mysql -u root -p asterisk -e "SELECT campaign_id, active FROM vicidial_campaigns WHERE campaign_id='CLOSER_SALES';" 

If active is 'N', update:

UPDATE vicidial_campaigns SET active='Y' WHERE campaign_id='CLOSER_SALES'; 
  1. In-group not linked to campaign:
mysql -u root -p asterisk -e "SELECT ingroup_id, campaign_id FROM vicidial_ingroups WHERE campaign_id='CLOSER_SALES';" 
  1. Dialplan context missing:
asterisk -rx "dialplan show CLOSER_SALES | head -20" 

If no output, regenerate:

/usr/share/astguiclient/astguiclient_extension_update.pl asterisk -rx "dialplan reload" sleep 2 asterisk -rx "module reload pbx_config" 
  1. SIP routing issue - verify SIP profile includes ViciDial context:
grep -A 5 "context=" /etc/asterisk/sip-vicidial.conf | head -20 

Issue: Agents Not Receiving Calls Despite Being Available

Symptom: Agents log in, show as READY, but calls don't route to them.

Diagnosis:

# Check agent in-group membership mysql -u root -p asterisk -e " SELECT u.user_id, u.status, ia.ingroup_id, ia.closer_flag FROM vicidial_users u LEFT JOIN vicidial_ingroup_agents ia ON u.user_id = ia.user_id WHERE u.user_id='agent001'; " 

Solutions:

  1. If ingroup_id is NULL, agent not assigned to in-group. Re-run Step 3.1.

  2. Verify closer_enabled flag:

mysql -u root -p asterisk -e "SELECT user_id, closer_enabled FROM vicidial_users WHERE user_id='agent001';" 
  1. Check if agent paused:
asterisk -rx "show channels | grep agent001" 

If showing paused status, use admin panel to unpause or force status:

UPDATE vicidial_users SET status='READY' WHERE user_id='agent001'; 
  1. Check Asterisk queue membership:
asterisk -rx "queue show CLOSER_SALES_MAIN | grep agent001" 

Issue: High Call Abandonment Rate

Symptom: Calls dropping before reaching agents (>15% abandonment).

Analysis:

mysql -u root -p asterisk -e " SELECT ingroup_id, COUNT(*) as total, SUM(CASE WHEN call_status='ABANDON' THEN 1 ELSE 0 END) as abandoned, ROUND(100*SUM(CASE WHEN call_status='ABANDON' THEN 1 ELSE 0 END)/COUNT(*), 2) as abandon_pct, AVG(wait_time) as avg_wait_sec FROM vicidial_closer_log WHERE DATE(start_time) = CURDATE() AND campaign_id='CLOSER_SALES' GROUP BY ingroup_id; " 

Solutions:

  1. Increase agents assigned: Add more agents to in-group or create overflow in-group.

  2. Reduce timeout: Lower call_timeout value (but not below 60 seconds):

UPDATE vicidial_ingroups SET call_timeout='90' WHERE ingroup_id='CLOSER_SALES_MAIN'; 
  1. Add voicemail option: Ensure voicemail_ext is configured:
UPDATE vicidial_ingroups SET voicemail_ext='9999' WHERE ingroup_id='CLOSER_SALES_MAIN'; 
  1. Implement callbacks: Enable callback option when queue full.

Issue: Calls Queuing But Not Distributed

Symptom: Queue shows calls waiting but agents not getting delivered calls.

Debug:

# Monitor queue in real-time watch -n 1 'asterisk -rx "queue show CLOSER_SALES_MAIN"' 

Check agent member penalties:

mysql -u root -p asterisk -e "SELECT ingroup_id, user_id, agent_priority FROM vicidial_ingroup_agents WHERE ingroup_id='CLOSER_SALES_MAIN';" 

Solution: Agent priority (penalty in queue) must be ascending (1, 2, 3, etc.). If reversed, queue won't distribute:

UPDATE vicidial_ingroup_agents SET agent_priority = 1 WHERE ingroup_id='CLOSER_SALES_MAIN' AND user_id='agent001'; UPDATE vicidial_ingroup_agents SET agent_priority = 2 WHERE ingroup_id='CLOSER_SALES_MAIN' AND user_id='agent002'; 

Reload queue:

asterisk -rx "queue reload" 

Issue: Calls Recording Not Working

Symptom: Closer calls complete but no recordings saved.

Check recording path:

ls -lah /var/spool/asterisk/monitor/ | tail -20 

Verify recording_enabled flag:

mysql -u root -p asterisk -e "SELECT ingroup_id, recording_enabled, recording_call_display_name FROM vicidial_ingroups WHERE ingroup_id='CLOSER_SALES_MAIN';" 

Enable recordings:

UPDATE vicidial_ingroups SET recording_enabled='Y' WHERE ingroup_id='CLOSER_SALES_MAIN'; 

Check Asterisk logging:

grep -i "monitor\|record" /var/log/asterisk/messages | tail -30 

Disk space issue - common cause:

df -h /var/spool/asterisk/ 

If full, archive old recordings:

find /var/spool/asterisk/monitor/ -mtime +30 -exec gzip {} \; 

Issue: Agent Can't Transfer Calls

Symptom: Closer agent attempts blind/attended transfer but fails.

Verify transfer permissions:

mysql -u root -p asterisk -e "SELECT user_id, call_transfer_flag, can_transfer_to_other_users FROM vicidial_users WHERE user_id='agent001';" 

Enable transfers:

UPDATE vicidial_users SET call_transfer_flag='1', can_transfer_to_other_users='1' WHERE user_id='agent001'; 

Check Asterisk DTMF configuration - verify feature codes in /etc/asterisk/features.conf:

[featuremap] blindxfer => #1 ; Blind transfer atxfer => *2 ; Attended transfer 

Test with CLI:

asterisk -rx "core show hints | grep agent001" 

Part 9: Monitoring & Reporting

Dashboard Query: Real-Time In-Group Status

SELECT ig.ingroup_id, ig.ingroup_name, COUNT(DISTINCT CASE WHEN u.status='READY' THEN u.user_id END) as available_agents, COUNT(DISTINCT CASE WHEN u.status='IN_CALL' THEN u.user_id END) as busy_agents, COUNT(DISTINCT CASE WHEN u.status='PAUSED' THEN uSource:https://dev.to/moisi_trungu_31647b7ac300/how-to-configure-vicidial-closer-campaigns-in-groups-2759

Related posts