Creating an outbound dialer with the 3CX CFD
On this topic
In this article we’ll explain how to create an automatic dialer application using the 3CX Call Flow Designer. Using dialers you can automatically make outbound calls and connect them to internal extensions (e.g. queues or agents extensions), so your staff doesn’t waste valuable time dialing, improving productivity.
The project for this application is installed along with the 3CX Call Flow Designer, in folder “Documents\3CX Call Flow Designer Demos”.
It’s important to note that Dialers start working as soon as the 3CX Queue Manager Service starts. Therefore, you need to use “Create a Condition” components to decide if it’s a good moment to make calls. For example, you can check the time of the day, if today is a holiday or we’re in a weekend. And depending on that you decide if you make calls or not. If you don’t add this logic, the dialer will start making calls as soon as it starts, and will not stop until you stop the 3CX Queue Manager Service.
The list of numbers to call can be anywhere, for example in a text file, in a database, etc. For this example we’ll use numbers from a text file. We’ll also show how to restrict outbound calls to monday to friday in a specific time frame, and finally how to control outbound calls to be made only when an agent is ready to take it.
Step 1: Create the project
First, we need to create a new project. Open the CFD and go to “File > New > Project”, select the folder where you want to save it, and enter a name for the project. In this case we’ll name it “OutboundDialerDemo”.
The project includes a callflow named “Main.flow” by default. We won’t be using this callflow, so you can delete it. Then add a new Dialer to the project. To do this, go to the Project Explorer window, right click on the project name node and select New Dialer. Set the name to “MainDialer”. Select the new dialer object in the Project Explorer window, and the Properties Window will show the dialer properties:
Dialers have 2 properties that customize their behavior:
- ParallelDialers: this is the quantity of simultaneous dialer instances that will be launched.
- PauseBetweenDialerExecution: this is the quantity of seconds that each instance will wait between flow executions.
Let’s explain this using a simple example. If we set ParallelDialers to 5, and PauseBetweenDialerExecution to 30 seconds, this is what will happen:
- A first dialer instance is created. It gets the number to call and makes the first call. Then it waits 30 seconds.
- After 6 seconds, a second dialer instance is created. It gets the number to call and makes the second call. Then this instance waits 30 seconds.
- After 6 seconds, a third dialer instance is created. It gets the number to call and makes the third call. Then this instance waits 30 seconds.
- After 6 seconds, a fourth dialer instance is created. It gets the number to call and makes the fourth call. Then this instance waits 30 seconds.
- After 6 seconds, a fifth dialer instance is created. It gets the number to call and makes the fifth call. Then this instance waits 30 seconds.
- After another 6 seconds, the first instance wakes up from waiting for 30 seconds, and makes another call.
- After another 6 seconds, the second instance wakes up from waiting for 30 seconds, and makes another call.
- And so on…
This iteration continues until the 3CX Queue Manager Service is stopped, the queue is deleted, or the voice app is removed from the queue.
As a consequence, using these 2 settings we control the call through rate. If we set ParallelDialers to 5, and PauseBetweenDialerExecution to 30 seconds, we’ll be making 10 calls per minute. If we need more or less, we need to increase or decrease these values.
Step 2: Check if it’s time to make calls
For this demo, we want that our dialer makes calls only from Monday to Friday, between 9am and 5pm. To accomplish this, we will use a “Create a condition” component. Drag it from the toolbox and drop it into the designer. Set “checkTimeToCall” for the name of this new component. This component needs 2 branches: “timeToCall” and “nothingToDo”. The first branch will be executed when it’s time to make a call, and the second branch when we’re out of that time frame.
Now we need to set an expression for the Condition property of the timeToCall branch. We need a C# expression that returns true when the current date and time is between Monday and Friday, and from 9am to 5pm. We can use the following expression for that:
((int)DateTime.Now.DayOfWeek) > 0 && ((int)DateTime.Now.DayOfWeek) < 6 && DateTime.Now.Hour >= 9 && DateTime.Now.Hour < 17
Step 3: Check if there are agents ready to take the calls
The dialer that we’re creating will make outbound calls to numbers from a text file, and then connect these calls to an internal extension. The internal extension will be a queue in our 3CX Phone System, and this queue will have some agents assigned. Let’s assume for this demo that the queue extension number is 800, and our agents have extensions 201, 202 and 203. We want to check if any of these extensions is free to receive a call. We’ll do this using the 3CX Call Control API, from a Launch External Script component.
Let’s write the C# code for the script we’ll invoke to check if there are free extensions to handle our calls. The code we need is pretty simple, we just need to get the DN object for each extension and check if they have any ActiveConnection attached. It could be the following:
public class ExtensionStateHelper
public bool IsThereAnyFreeExtension()
return PhoneSystem.Root.GetDNByNumber("201").GetActiveConnections().Length == 0 ||
PhoneSystem.Root.GetDNByNumber("202").GetActiveConnections().Length == 0 ||
PhoneSystem.Root.GetDNByNumber("203").GetActiveConnections().Length == 0;
Save that C# code in a file named “CheckExtensionsState.cs”, into the “Libraries” folder of the project. Then, drag a Launch External Script component from the toolbox to the designer, inside the timeToCall branch, name it “checkFreeExtensions”, and configure it as follows:
Now we need to check the result of this script. To do this, we’ll use another Create a condition component, just underneath the Launch External Script component. We’ll use “isThereAnyFreeExtension” for the name, and we’ll add 2 branches to it: yesMakeCall and noFreeExtensions. Our diagram will look like this:
Finally, we need to set the Condition property for the branch “yesMakeCall”. This condition must be met when the previous script returned true. So the expression in this case should be:
At this point, when the branch “yesMakeCall” is executed, all our validations are satisfied, we’re in the time frame we need, and there is at least 1 free extension, so it’s time to make the call.
Step 4: Get the number to call from a text file and make the call
For this demo we’ll get the numbers to call from a text file. Let’s use a file named “NumbersToCall.txt”, which contains a number in each line.
In order to get the number to call, we need an index variable, to select the line to read from the text file, which we need to share between all the parallel dialers. This way, when we increment the index, the following dialer instance will use the incremented index, and so on. To do this, we need a static variable defined in a C# script. Let’s create a new text file in the project “Libraries” folder, name it “CallIndexHolder.cs”, and add the following code to it:
public class CallIndexHolder
private static int callIndex = 0;
public int GetCallIndex()
public void SetCallIndex(int index)
callIndex = index;
Please note that the variable “callIndex” is being declared static. That means that only 1 instance of that variable will exist in the entire process (3CX Queue Manager service), and therefore it will be shared between all the dialers.
Now we need to use a Launch External Script component to get the CallIndex, let’s name it “getCallIndex”, place it inside the branch “yesMakeCall”, and configure it as follows:
Then we need to read the number to call from the text file. Let’s add a new Read / Write to File component, just below the “getCallIndex” component, name it “readNumberToCall”, and configure it as follows:
Please note that we’re specifying the path to the file containing the numbers to call. You will need to adjust this to the path in your 3CX server.
It might happen that the index goes beyond the number of lines in the text file. In that case, the component “readNumberToCall” will read an empty string. So we need to check if this is the case or not before making the call. We need another Create a condition component to verify this case. We just need a single branch inside this condition, to check if there is a number available. The Condition property can be set to:
When that condition is met, we have a number to call. In that case, we’ll increment the CallIndex, using another Launch External Script component, and finally make the call using a Make Call component. The Make Call component should be configured as follows:
Using that configuration, we’ll be making a call from extension 800 (our queue having agents 201, 202 and 203), and the destination number taken from the text file.
This is how the “yesMakeCall” branch will look like after adding all the components to it.
Step 5: Build and deploy to 3CX Phone System
The project is ready. We just need to build and upload it to our 3CX Phone System server. To do this:
- Go to “Build > Build All”. The CFD will create the file “OutboundDialerDemo.tcxvoiceapp”.
- Go to the “3CX Management Console > Call Queues”, create a new queue, configure it with name and extension, check the “Voice apps” option, and upload the file created by the CFD in the previous step.
- Save the changes to the queue. The dialer is ready and will start making calls as soon as the 3CX Queue Manager service is started.