Master per-campaign Caller ID configuration in ViciDial/Asterisk to control outbound number presentation, dynamic CID routing, and compliance-driven number assignment across multiple campaigns.
Prerequisites
Before you begin configuring ViciDial Caller ID settings per campaign, ensure the following:
- ViciDial 2.14+ installed and running (this tutorial covers 2.14-2.17)
- Asterisk 11+ compiled with ViciDial patches
- Direct database access (MySQL/MariaDB) to the asterisk database
- SSH access to the ViciDial server with sudo privileges
- Carrier/trunk configuration already established with available DID numbers
- Understanding of basic ViciDial campaign structure and dialplan concepts
- PHP web admin access (
/vicidial/admin.php)
Verify your ViciDial version:
sudo -u asterisk cat /etc/asterisk/vici_domains.conf | head -20
Check Asterisk is running:
sudo asterisk -rx "core show version"
Understanding ViciDial Caller ID Architecture
ViciDial handles Caller ID assignment through a hierarchical system with multiple fallback points. Understanding this chain is critical for proper configuration.
The CID Assignment Priority Chain
When an agent dials a lead in ViciDial, the system determines which number to present in this order:
- Campaign-level CID (if configured in campaign settings)
- User/Agent-level CID (if assigned to the specific agent)
- Carrier CID (numbers assigned to the outbound carrier/trunk)
- Server default CID (fallback number configured at server level)
- Trunk/Channel default (last resort from Asterisk trunk config)
This hierarchy allows fine-grained control. A campaign can override agent settings, but agents can still have their own CID if the campaign isn't strict.
Key Database Tables
Three primary tables govern CID behavior:
- vicidial_campaigns — campaign-wide CID settings
- vicidial_users — agent-specific CID overrides
- vicidial_carrier_log — outbound carrier trunk configurations
Accessing Campaign CID Settings via Web Admin
The quickest method for most ViciDial administrators is through the web interface.
Step 1: Navigate to Campaign Configuration
- Log in to
/vicidial/admin.phpas a user with campaign edit permissions - Click Campaigns → Modify Campaign
- Select your target campaign from the dropdown
- Look for Caller ID Number field near the top of the form
Step 2: Set Campaign-Level CID
The Caller ID Number field accepts:
- Static number:
15551234567— all calls from this campaign present this number - Carrier default: Leave blank — use the trunk/carrier's assigned DID
- Variable assignment: See dynamic section below
Example configuration:
Campaign Name: Sales_Outbound_US
Caller ID Number: 15551234567
Caller ID Name: Acme Sales
Step 3: Save and Verify
Click SUBMIT to save. The web interface commits directly to the vicidial_campaigns table.
Verify in MySQL:
SELECT campaign_id, campaign_name, outbound_cid, cid_name FROM vicidial_campaigns
WHERE campaign_name='Sales_Outbound_US'\G
Expected output:
campaign_id: 1
campaign_name: Sales_Outbound_US
outbound_cid: 15551234567
cid_name: Acme Sales
Database-Level CID Configuration
For advanced scenarios or bulk updates, modify the database directly.
Direct Campaign CID Update
Update a single campaign:
UPDATE vicidial_campaigns
SET outbound_cid='15551234567', cid_name='Acme Sales'
WHERE campaign_id=1;
Verify the change immediately:
SELECT campaign_id, campaign_name, outbound_cid, cid_name
FROM vicidial_campaigns WHERE campaign_id=1;
Bulk Update Multiple Campaigns
Update all campaigns with a specific status or prefix:
UPDATE vicidial_campaigns
SET outbound_cid='16175550123', cid_name='Boston Office'
WHERE campaign_name LIKE 'Boston_%' AND active='Y';
Check how many rows were affected:
SELECT COUNT(*) FROM vicidial_campaigns
WHERE campaign_name LIKE 'Boston_%' AND active='Y';
Agent-Level CID Override
Override campaign CID for specific agents:
UPDATE vicidial_users
SET outbound_cid='15559876543', cid_name='John Smith'
WHERE user='john.smith' AND user_level >= 1;
Verify:
SELECT user, user_name, outbound_cid, cid_name
FROM vicidial_users WHERE user='john.smith';
Important: Agent-level CID only applies if the campaign doesn't have a strict CID policy. Check the campaign's outbound_cid field—if set, it overrides agents.
View Current CID Configuration Across Campaigns
Generate a report of all campaign CID settings:
SELECT
campaign_id,
campaign_name,
outbound_cid,
cid_name,
active,
campaign_type
FROM vicidial_campaigns
WHERE active='Y'
ORDER BY campaign_name;
Asterisk Dialplan Integration
The actual CID presentation happens in Asterisk dialplan. ViciDial uses extension contexts generated from database records.
Reviewing Generated Dialplan
ViciDial writes dialplan on each service restart. The outbound campaign dialplan is in:
cat /etc/asterisk/extensions-vicidial.conf | grep -A 20 "exten => 8,1"
Look for Set(CALLERID(num)= statements:
exten => 8,1,Set(CALLERID(num)=15551234567)
exten => 8,2,Set(CALLERID(name)=Acme Sales)
exten => 8,3,Dial(...)
Manual Dialplan Override (Advanced)
For custom CID logic, edit /etc/asterisk/extensions-custom.conf:
[from-internal-custom]
exten => _91XXXXXXXXX,1,NoOp(Custom CID for campaign)
exten => _91XXXXXXXXX,n,Set(CALLERID(num)=15551234567)
exten => _91XXXXXXXXX,n,Set(CALLERID(name)=Acme Sales)
exten => _91XXXXXXXXX,n,Goto(from-internal,${EXTEN},1)
Reload the dialplan after edits:
sudo asterisk -rx "dialplan reload"
Warning: Custom dialplan changes will be overwritten on next ViciDial service restart. Use only for testing or if you can regenerate extensions programmatically.
Dynamic CID Assignment per Campaign
For scenarios requiring different CID numbers based on area codes, time of day, or lead data, use Asterisk AstDB or a custom script.
Method 1: Using Asterisk AstDB
Store CID mappings in AstDB (Asterisk internal database):
sudo asterisk -rx "database put CAMPAIGN_CID campaign_1 15551234567"
sudo asterisk -rx "database put CAMPAIGN_CID campaign_2 16175550123"
sudo asterisk -rx "database put CAMPAIGN_CID campaign_3 12125559999"
Verify storage:
sudo asterisk -rx "database show CAMPAIGN_CID"
Expected output:
/CAMPAIGN_CID/campaign_1 : 15551234567
/CAMPAIGN_CID/campaign_2 : 16175550123
/CAMPAIGN_CID/campaign_3 : 12125559999
Add to /etc/asterisk/extensions-custom.conf:
[from-internal-custom]
exten => _91XXXXXXXXX,1,NoOp(Dynamic CID lookup for ${CAMPAIGN_ID})
exten => _91XXXXXXXXX,n,Set(CID_NUM=${DB(CAMPAIGN_CID/${CAMPAIGN_ID})})
exten => _91XXXXXXXXX,n,ExecIf($["${CID_NUM}" != ""]?Set(CALLERID(num)=${CID_NUM}))
exten => _91XXXXXXXXX,n,Goto(from-internal,${EXTEN},1)
Reload dialplan:
sudo asterisk -rx "dialplan reload"
Method 2: Area Code-Based CID Routing
Route outbound CID based on the lead's area code:
-- Create a lookup table
CREATE TABLE IF NOT EXISTS vicidial_cid_routing (
cid_route_id INT AUTO_INCREMENT PRIMARY KEY,
campaign_id INT,
area_code VARCHAR(3),
outbound_cid VARCHAR(20),
active CHAR(1) DEFAULT 'Y'
);
-- Populate with examples
INSERT INTO vicidial_cid_routing (campaign_id, area_code, outbound_cid, active)
VALUES
(1, '617', '16175551234', 'Y'),
(1, '212', '12125559876', 'Y'),
(1, '310', '13105554321', 'Y');
Add Asterisk logic:
[from-internal-custom]
exten => _91XXXXXXXXX,1,NoOp(Area-code-based CID for ${EXTEN:2:3})
exten => _91XXXXXXXXX,n,Set(AREA_CODE=${EXTEN:2:3})
exten => _91XXXXXXXXX,n,Set(CID_NUM=${ODBC_LOOKUP(cid_lookup,${CAMPAIGN_ID},${AREA_CODE})})
exten => _91XXXXXXXXX,n,ExecIf($["${CID_NUM}" != ""]?Set(CALLERID(num)=${CID_NUM}))
exten => _91XXXXXXXXX,n,Goto(from-internal,${EXTEN},1)
Carrier/Trunk CID Configuration
ViciDial campaigns route through carriers (trunks). Each carrier can have specific DID pools or CID ranges.
Viewing Carrier Configuration
SELECT
carrier_id,
carrier_name,
outbound_cid,
outbound_cid_override,
active
FROM vicidial_carrier_log
LIMIT 10;
Assigning DIDs to Carriers
ViciDial manages DIDs through vicidial_did_log:
SELECT
did_id,
did_number,
carrier_id,
active,
did_route
FROM vicidial_did_log
WHERE active='Y'
ORDER BY carrier_id;
Linking Campaign to Specific Carrier
Some ViciDial installations require explicit carrier assignment per campaign:
-- Check if your ViciDial version tracks carrier_id in campaigns
DESCRIBE vicidial_campaigns | grep carrier;
-- If present, assign campaign to carrier
UPDATE vicidial_campaigns
SET carrier_id=1
WHERE campaign_id=5;
Note: Not all ViciDial versions have carrier_id in the campaign table. Check your schema first.
SIP Trunk Configuration for CID
The actual SIP trunk configuration in Asterisk determines whether CID is allowed, blocked, or modified by carriers.
Example SIP Trunk Configuration
Edit /etc/asterisk/sip-vicidial.conf:
[carrier_outbound_trunk](!)
type=peer
context=from-carriers
disallow=all
allow=alaw,ulaw,gsm
nat=yes
host=carrier.example.com
port=5060
insecure=port,invite
[carrier_outbound_trunk](carrier_outbound_trunk)
accountcode=OUTBOUND_CARRIER_1
fromuser=customer_acct
fromdomain=carrier.example.com
defaultuser=customer_acct
secret=your_sip_password_here
Controlling CID Presentation in SIP INVITE
Add per-trunk CID settings:
[carrier_outbound_trunk](!)
; ... existing config ...
setvar=OUTBOUND_CID=15551234567
setvar=OUTBOUND_CID_NAME=Acme Sales
; Allow or restrict CID override
directmedia=no
Pass CID to carrier via dialplan:
exten => _91XXXXXXXXX,1,Set(CALLERID(num)=15551234567)
exten => _91XXXXXXXXX,2,Set(CALLERID(name)=Acme Sales)
exten => _91XXXXXXXXX,3,Dial(SIP/${EXTEN}@carrier_outbound_trunk)
Compliance and Call Recording CID Logging
ViciDial logs all calls with their CID in vicidial_log and vicidial_closer_log.
Verifying Logged CID
Check the call log for a specific campaign:
SELECT
call_id,
campaign_id,
callerid_number,
callerid_name,
call_date,
status
FROM vicidial_log
WHERE campaign_id=1 AND call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
ORDER BY call_date DESC
LIMIT 10;
Example output:
call_id: 1700156234.142
campaign_id: 1
callerid_number: 15551234567
callerid_name: Acme Sales
call_date: 2024-01-15 14:30:12
status: SALE
Auditing CID Changes Over Time
Create an audit log of CID configuration changes:
SELECT
campaign_id,
campaign_name,
outbound_cid,
cid_name,
modification_date
FROM vicidial_campaigns_archive
WHERE campaign_id=1
ORDER BY modification_date DESC;
If vicidial_campaigns_archive doesn't exist, manually log critical changes:
sudo asterisk -rx "database put CAMPAIGN_CID_AUDIT campaign_1_change_$(date +%s) '15551234567|$(date)'"
Troubleshooting CID Issues
Issue 1: CID Not Displaying Correctly to Called Party
Symptom: Outbound calls show wrong Caller ID or generic number.
Diagnosis:
- Check campaign CID setting:
SELECT outbound_cid, cid_name FROM vicidial_campaigns WHERE campaign_id=1\G
- Verify agent CID doesn't override:
SELECT outbound_cid, cid_name FROM vicidial_users WHERE user='agent_name'\G
- Check Asterisk dialplan generated:
grep -i "callerid" /etc/asterisk/extensions-vicidial.conf | head -20
- Monitor live call in Asterisk:
sudo asterisk -rx "core show channels verbose" | grep OUTGOING
- Check Asterisk logs:
sudo tail -100 /var/log/asterisk/messages | grep -i callerid
Solution:
Regenerate dialplan:
sudo systemctl restart viciserver
Or manually reload:
sudo asterisk -rx "dialplan reload"
Issue 2: CID Rejected by Carrier
Symptom: Calls connect but caller ID shows as "Anonymous" or default carrier number.
Diagnosis:
- Verify carrier accepts the CID:
sudo asterisk -rx "sip show peer carrier_outbound_trunk"
- Check SIP debug logs:
sudo asterisk -rx "sip set debug on"
# Make a test call
sudo asterisk -rx "sip set debug off"
sudo tail -200 /var/log/asterisk/messages | grep -i "callerid\|from:"
- Contact carrier to verify:
- CID number is whitelisted
- CID format is correct (E.164: +1NXXXXXXXXX)
- Account permissions allow CID override
Solution:
- Reformat CID to carrier's requirement
- Request CID whitelist approval from carrier
- Use carrier-assigned DID if available
Issue 3: Incorrect CID on Agent Transfers
Symptom: When an agent transfers a call, different CID presents.
Diagnosis:
Check if attended transfer preserves CID:
sudo asterisk -rx "core show function REDIRECTING"
Verify in call logs:
SELECT call_id, callerid_number, transfer_to, transfer_from
FROM vicidial_log
WHERE campaign_id=1 AND call_date >= NOW() - INTERVAL 1 HOUR;
Solution:
Configure transfer preservation in /etc/asterisk/extensions-custom.conf:
exten => _91XXXXXXXXX,1,Set(REDIRECTING(num)=${CALLERID(num)})
exten => _91XXXXXXXXX,2,Set(REDIRECTING(name)=${CALLERID(name)})
exten => _91XXXXXXXXX,3,Dial(SIP/extension@asterisk)
Issue 4: Database Changes Not Reflecting in Calls
Symptom: Updated campaign CID in database, but old number still showing.
Cause: Asterisk dialplan is cached in memory.
Solution:
Fully restart ViciDial services:
sudo systemctl stop viciserver
sudo systemctl stop vicidial-Apache
sleep 5
sudo systemctl start viciserver
sudo systemctl start vicidial-Apache
Verify reload completed:
sudo asterisk -rx "dialplan show from-internal" | grep -i callerid | head -5
Issue 5: CID Shows Campaign Name Instead of Number
Symptom: Caller ID displays campaign name (e.g., "Sales_Outbound") instead of phone number.
Diagnosis:
Check for misconfiguration in campaign CID field:
SELECT campaign_id, campaign_name, outbound_cid, cid_name
FROM vicidial_campaigns WHERE campaign_name='Sales_Outbound'\G
If outbound_cid contains non-numeric characters, it's misconfigured.
Solution:
Fix the field to contain only digits:
UPDATE vicidial_campaigns
SET outbound_cid='15551234567'
WHERE campaign_name='Sales_Outbound';
Verify the format matches E.164:
# Should match pattern: 1-15 digits, starting with 1 for US numbers
echo "15551234567" | grep -E '^1[0-9]{10,14}$' && echo "Valid" || echo "Invalid"
Debug CID in Real-Time
Enable verbose logging and run a test call:
# Terminal 1: Enable debug
sudo asterisk -rx "core set verbose 5"
sudo asterisk -rx "sip set debug on"
# Terminal 2: Monitor logs
sudo tail -f /var/log/asterisk/messages | grep -i callerid
# Terminal 3: Run test call from agent screen (/agc/vicidial.php)
# Monitor both logs
Check both agent screen and logs for confirmation:
sudo grep "campaign_id=1" /var/log/asterisk/messages | tail -20
Production Best Practices
1. Document CID Assignments
Maintain a spreadsheet or wiki of all campaign CID assignments:
| Campaign ID | Campaign Name | Assigned CID | CID Name | Carrier | Status |
|---|---|---|---|---|---|
| 1 | Sales_US | 15551234567 | Acme Sales | Carrier A | Active |
| 2 | Support_CA | 14165559999 | Acme Support | Carrier B | Active |
| 3 | Collections_Test | 15559876543 | Test CID | Carrier A | Testing |
2. Use Staging Environment
Test CID changes in a staging ViciDial before production:
# Backup production campaign settings
mysqldump -u asterisk -p asterisk vicidial_campaigns > campaigns_backup_$(date +%Y%m%d).sql
# Test in staging first
mysql -u asterisk -p asterisk_stage < test_campaign_cid.sql
3. Implement Change Control
Log all manual CID changes:
# Create audit log
echo "[$(date)] Changed campaign 1 CID from 15551111111 to 15551234567 - Admin: $(whoami)" >> /var/log/vicidial_cid_changes.log
4. Validate CID Format
Before updating, validate CID numbers:
# Simple validation script
validate_cid() {
if [[ $1 =~ ^1[0-9]{10,14}$ ]] || [[ $1 =~ ^\+1[0-9]{10,14}$ ]]; then
echo "Valid CID: $1"
return 0
else
echo "Invalid CID format: $1"
return 1
fi
}
validate_cid "15551234567" && echo "OK" || echo "FAIL"
5. Monitor CID Effectiveness
Regularly audit that CID is logging correctly:
-- Daily CID verification report
SELECT
DATE(call_date) as call_date,
campaign_id,
COUNT(*) as call_count,
COUNT(DISTINCT callerid_number) as unique_cids
FROM vicidial_log
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY DATE(call_date), campaign_id
ORDER BY call_date DESC;
Summary
Configuring Caller ID per ViciDial campaign requires understanding the CID assignment hierarchy, database configuration, and Asterisk dialplan integration. Key takeaways:
- Use the web admin (
/vicidial/admin.php) for simple, one-off campaign CID changes - Access the database directly for bulk updates or complex scenarios
- Understand the hierarchy: Campaign CID overrides agent CID, which overrides carrier default
- Verify in Asterisk: Monitor dialplan generation and reload to ensure changes take effect
- Test before production: Use staging environments and maintain change logs
- Audit regularly: Check
vicidial_logto confirm CID is presenting correctly to called parties - Handle carrier restrictions: Some carriers whitelist or restrict CID numbers; coordinate with your carrier
- Troubleshoot methodically: Check database → dialplan → Asterisk logs → carrier support
For dynamic CID assignment beyond static campaign settings, use AstDB lookups or custom dialplan logic tied to area codes, lead data, or other routing variables. Always maintain backups before bulk changes and test in a staging environment whenever possible.
The configuration is now complete and ready for production use. Monitor call logs regularly to ensure CID compliance and effectiveness.