Writing Your First CVP Studio Application


This guide is meant to be a starting point for anyone who wants to write applications with CVP Call Studio.  We’re not going to show you how to write a complex self-service application in this guide, only how to get started with writing and deploying a simple Studio application with CCE.  This guide assumes that you already have a working, Comprehensive Mode CVP installed with CCE and a number routed to an UCCE script you can experiment with. The goal is to teach you to write a CVP Studio app, deploy it, and run it.  You can find the source files for the app we are going to write here.


  1. Have CCE with CVP in comprehensive mode installed and functional (i.e. accepting calls). We have other blogs that cover installing CCE and CVP.
  2. Have CVP Studio installed on a desktop machine so you can create some magic. You can find this on the CVP ISO on the filesystem as seen below.  There is a 30 day demo license given with CVP Studio. Even though it’s a Java application, only Windows is supported. Technically only client OS’s supported, like Windows 7 or Windows 10, but in our experience with older versions Windows Server 2012 also tended to work. We’ve had less luck with the latest versions of Studio and Windows Server, so YMMV.

Screen Shot 2018-06-11 at 3.01.03 PM

UCCE Configuration Manager

First, even if nothing is setup, you may want to confirm a phone number is coming into CCE.  The easiest way to do this is to open the AW (Admin Workstation) and use a tool named Router Log Viewer.  This will show every call that hits the system, and you can confirm the number coming in.  You’ll first need to login to the AW server itself via RDP. Note that only one user at a time is allowed to access the configuration tools on an AW.

Router Log Viewer can be found in the Administration Tools folder located on the Desktop of the AW:

Screen Shot 2018-06-11 at 3.08.21 PM

Router Log Viewer looks like this.  The top half is successfully routed calls and the bottom half is failed calls (and some errors which will eventually become easy to read).  You can see my call to 980-201-7899 here has failed.  We are going to redo this number to support a small app written in studio.

Screen Shot 2018-06-11 at 3.10.28 PM

The next step here is to setup a Dialed Number.  You use the configuration manager utility on the AW to do most of your configuration in UCCE, minus scripting.  You can also find this under the Administration Tools folder on the desktop.  You can see it in the previous screenshot.  It looks like this once it’s open.

Screen Shot 2018-06-11 at 3.13.49 PM

We are going to browse under Tools -> List Tools -> Dialed Number / Script Selector List and configure this number.  The first time you open it, it will look like this.  You need to click the retrieve button before you can configure anything.

Screen Shot 2018-06-11 at 3.15.21 PM

The Router Log viewer earlier told us exactly what to configure.  The error says “No default label available for dialed number: cvp_rc2.9802017899

cvp_rc2 is our routing client and 9802017899 is going to be our dialed number string. Here is what our dialed number Attributes tab configuration should look like.

Screen Shot 2018-06-11 at 3.17.30 PM

We have now configured a Dialed Number, but it’s not pointed to anything, somehow we have to get this number to run a script.

We do this through what’s is called a Call Type.  A Call Type’s main purpose in CCE is reporting, but is also required to associate a Dialed Number to a Script. Use Configuration Manager to browse to Tools -> List Tools -> Call Type List in order to create one.

I’ve created CloverhoundBlog Call Type in my lab, you should create something similar.  It looks like this.

Screen Shot 2018-06-11 at 3.19.47 PM

From here we need to point our Dialed Number to this Call Type, so browse back to the Dialed Number List Tool, click retrieve and browse to our Dialed Number.

Select the Dialed Number, then click the second tab on the right named Dialed Number Mapping. Click the Add button and select the CloverhoundBlog Call Type we created earlier.

Screen Shot 2018-06-11 at 3.21.25 PM

It should look like this once it’s saved:

Screen Shot 2018-06-11 at 3.21.35 PM

Finally, when we get to scripting we’ll need a Network VRU Script to launch our custom Studio app. Only one is needed system-wide to launch any Studio scripts. This may already exist in your CCE environment, but if not we need to create it.

To do so, first browse to Tools -> List Tools -> Network VRU Script List. You should see or create an entry that looks like the below. It doesn’t have to be named CustomApplication, but make sure it’s purpose is clear.

Screen Shot 2018-06-11 at 3.24.43 PM

Great! Now we are done in Configuration Manager.  The scripting portions uses some CVP ECC Variables which should have been added via Configuration Manager when CVP was setup.  If you don’t see any or some of the variables we use in the next section in scripting, check out the CVP Configuration Guide here in the Micro-Applications Eccs table: CVP Configuration Guide

CCE Scripting

Next we are going to open Script Editor which you can also find in the Administrative Tools folder.  This is where you will create all your CCE scripts.  People may wonder what the difference between a CCE script and a CVP script is. Well, CCE doesn’t work with audio files, or complex backend app routing, it’s more based around skill group routing, allocations and reporting.  Any complex IVR functions are in CVP.  Most call flows are setup to route into CCE, set some Call Types and call data for end to end reporting, transfer into CVP for IVR treatment, and then return to CCE with some variables that direct it to the right Skill Group / Queue and call treatment post IVR.

To get started, we are going to create a new Routing Script. Within Script Editor, Click File -> New and then choose Routing Script.

Screen Shot 2018-06-11 at 3.30.04 PM

This interface is drag and drop as long as your in edit mode (which a new script opens into by default). You can add elements by right clicking on the palette and choosing New Object. We are going to use only a few nodes for this script. Set Variable, Send to VRU, Release Call and Run External Script. You can also download the script I created here.

Screen Shot 2018-06-11 at 3.34.34 PM

Here is the completed script and then some details below:

Screen Shot 2018-06-11 at 6.25.30 PM

  • The following are set scripts. I’ve shown the first one as a picture, but you should be able to set the rest from the instructions.
    • user.microapp.input_type = “D”

Screen Shot 2018-06-11 at 3.38.51 PM

  • user.microapp.media_server = “ – Replace the IP with your CVP, keep the port at 7000. Note: This is optional as of version 10.5! You can just leave this step off entirely and CVP will set it automatically.
  • user.microapp.app_media_lib = “..” Note: This is optional as of version 10.5! You can just leave this step off entirely and CVP will set it automatically.
  • user.microapp.UseVXMLParams = “N”

After connecting all these in a line connect the Send to VRU node.  This node brings in the VXML Gateway or VVB (Virtual Voice Browser), which works in conjunction with CVP to provide IVR treatment.

Screen Shot 2018-06-11 at 10.25.02 PM

Next, we need to set the parameters to pass to our scripts. We’ll use another Set Variable step for this. To begin with, we’re going to run the HelloWorld application packaged with CVP to make sure our install is good.

We will use the Call.user.microapp.ToExtVXML[] variable array to pass info into CVP and we get info back from the apps in the Call.user.microapp.FromExtVXML[].  For this small app we are going to pass in just 2 variables, the callid and the application we want to run (callid is passed automatically in the latest versions of CVP, but we’ll include it for training purposes). We will replace HelloWorld with our app in the next steps. Our last set variable step should be as follows.

  • user.microapp.ToExtVXML[0] = concatenate(“application=HelloWorld;”,concatenate(“callid=”,Call.user.media.id))

Screen Shot 2018-06-11 at 10.25.17 PM

Essentially, we dynamically created a string above and passed it into the IVR that looks like this application=HelloWorld;callid=<CALLGUID>. You separate variables with a semicolon (“;”) when passing them from CCE to CVP. Each variable we pass this way becomes available within our Studio app.

Lastly we connect the final Set Variable step to a Run External Script node and select our CustomApplication VRU Script that we configured in UCCE earlier.  Save our script and name it CloverhoundBlog and we are good!

Screen Shot 2018-06-11 at 10.25.10 PM

The last step is to attach the Call Type we created earlier named CloverhoundBlog to our Script also named CloverhoundBlog.  In script editor from the menu, choose Script -> Call Type Manager.

Screen Shot 2018-06-11 at 3.54.43 PM

This will open up the Call Type Manager.  Browse to the Schedules tab and select our call type CloverhoundBlog.

Screen Shot 2018-06-11 at 3.54.53 PM

From here select Add, then select our script and click Save.

Screen Shot 2018-06-11 at 3.55.47 PM

It should look like this when completed.

Screen Shot 2018-06-11 at 3.55.54 PM

That’s it!  Give your number a call and you should hear the CVP HelloWorld application.  Congrats!

Media Server on CVP

CVP needs a media server for audio files, and we are going to use the one built into the CVP Windows server with Microsoft IIS for this.  A media server is just an HTTP web server, so hypothetically you can host audio files wherever you want. CVP references them as a URL.

On the CVP server you should see a C:\inetpub\wwwroot folder in the install drive. This is your media folder. It will look like this.

Screen Shot 2018-06-11 at 4.15.11 PM

If your CVP Server is you will find file hosted at  You can test this by placing a wav file in this folder and then hitting it in any web browser, the audio will play! If this doesn’t work, you need to make sure IIS is running and is accessible via HTTP.

Screen Shot 2018-06-11 at 4.17.17 PM

We are going to place all the files from this zip into our audio folder for this blog.  Here are the files.

Our folder should look like this when complete, or at least have the three files required for our application.

Screen Shot 2018-06-11 at 6.15.08 PM

CVP Studio

Alright, time to tame the beast we actually came here for! When we load up CVP Studio it’s going to look like this. You will probably have no apps at all in the Navigator pane is this is a fresh install. (As you can see, I have one other existing app currently loaded in mine).

Screen Shot 2018-06-11 at 4.02.55 PM

From here we are going to start a new project.  Browse to File -> New -> Call Studio Project and make a project named CloverhoundBlog. By default Studio will place projects into a local “workspace” folder, but you can override this and store your projects in any folder you like.

Screen Shot 2018-06-11 at 4.03.49 PM

Once you click finish, you will be taken to the main CVP app page.  The app we create is going to be very simple, we are going to play a single menu and navigate to 2 different audio files based off that menu.

Here is what CVP Studio looks like after a creating a new application.

Screen Shot 2018-06-11 at 4.03.56 PM

You can find some app level properties by right clicking on the project’s root, and selecting properties.

Screen Shot 2018-06-11 at 4.06.24 PM

There are a few important ones.  The biggest is the Default Audio Path URL located on the Audio Settings tab. This should be the root of your audio folder, which is generally an IIS server hosted on one of your CVP machines.  In our lab, every CVP service including our media server run on Studio should look something like this assuming your using the default CVP setup for your media as we showed under the Media Server section (there are ways to make this dynamic, allowing for failover, but they require some bits of custom code and won’t be covered here yet).

Screen Shot 2018-06-11 at 4.17.44 PM

Another important app-wide setting in-case you’re using Nuance is under the General Settings. You must enable TTS and Speech under the VXMLGateway type if you plan to use more than just DTMF.  No need to change this now but good to know about it for the future.

Screen Shot 2018-06-11 at 4.18.28 PM

Alright, time to create the app finally.  Our app looks like this right now. Every Studio call flow begins with a “Start of Call” element.

Screen Shot 2018-06-11 at 4.03.56 PM

Next, we are going to drag over the CVP Subdialog Start element and attach it to our Start of Call.  This is required for all CVP apps. Behind the scenes, this element handles loading the parameters we’re sending from CCE. It will look like this before we connect our elements.

Screen Shot 2018-06-11 at 4.26.50 PM

To connect steps, we right click on start of call, go to Exit States, and choose next.  This gives us an arrow we can use to connect the elements together. Click on the next step with the arrow to complete the connection.

Screen Shot 2018-06-11 at 4.25.05 PM

And here it is connected.

Screen Shot 2018-06-11 at 4.25.21 PM

Next we are going to drag over a 2_Option_Menu, which is going to be our menu providing two options: “Thanks for calling Cloverhound demo, Press 1 for sales or 2 for service.”

Once that’s dragged onto our palette, connect the CVP Subdialog Start 01 element to the Menu element using the ‘Done’ Exit State from the menu. 

Screen Shot 2018-06-11 at 4.28.49 PM

Now let’s take a look at the elements settings. You can find all the specs of each element here: CVP Element Specification Guide

The most important ones to note with menus are the DTMF keypresses we’re accepting, the Max NoInput and the Max NoMatch settings.NoMatch and NoInput represent how many times the menu will allow the caller to retry in response to timeouts with no entries or entries with invalid inputs. When a call reaches the NoInput or NoMatch limit, the flow will proceed through NoInput or NoMatch exit states which you can route as desired in your call flow. In this application we are just going to hang them up.

Screen Shot 2018-06-11 at 4.29.29 PM

Also, very important is the audio tab of this menu, this is how we define what wav file to play to the caller for this element. Remember, CVP only uses G.711 by default.

We want to check Use Default Audio Path, this means that  we set earlier will be prepended to whatever is typed here. This is why I only have to type menu1.wav.  The end result used by CVP will be:

Screen Shot 2018-06-11 at 4.29.55 PM

*Note: If you want to play more than one wav, you can right click the word Initial to add subsequent ones, or use it to add “Say It Smart” to dynamically read back things like numbers, dates or currency values.  This is how you build complex sentences in the IVR.

Screen Shot 2018-06-11 at 4.39.06 PM

Now that the menu is configured, we are going to drag over two Audio elements, which simply play audio files to the caller. One will say “Service” and other will say “Sales” back to the caller, depending on which option is selected.

Screen Shot 2018-06-11 at 4.40.45 PM

First let’s rename our elements so they are easier to track.  Right click on the audio elements and choose rename.

Screen Shot 2018-06-11 at 4.41.56 PM

Now let’s right click on the menu and connect things together. We can see that a Menu element has multiple Exit States available, one for each option, one for maximum nomatch events, and one for maximum noinput events.  Let’s connect option 1 to sales and option 2 to service.

Screen Shot 2018-06-11 at 4.40.35 PM

We end up with the call flow below. You will notice that any element without all of it’s exit states completed will have a little yellow warning icon. We didn’t connect the max_nomatch and max_noinput yet, so we are still getting warnings. Note that Studio won’t let you deploy an application until all such warnings are cleared.

Screen Shot 2018-06-11 at 4.43.31 PM

We’ll come back and fix those, but first we are going to go set the audio properties of our audio elements to use the appropriate wav files.

Screen Shot 2018-06-11 at 5.35.43 PM

The next step is to drag over a CVP Subdialog Return Element and connect it to the remaining exit states. This element returns control back to CCE (DO NOT use the Hangup element or any other return element here, those apply in different deployment models). First we will connect the Audio elements’ Done exit states.

Screen Shot 2018-06-11 at 5.42.47 PM

Next we will attach the max_noinput and max_nomatch exit states from our Menu to the CVP Subdialog Return.

Screen Shot 2018-06-11 at 5.43.05 PM

The last step is to set a caller_input on the CVP Subdialog Return. This is a return value to CCE you can set to any value you need. We’re not using this right now but setting it is required (marked with a red star), so we’ll just set it to 1 for now, which we’ll use to indicate the script completed successfully.

Screen Shot 2018-06-11 at 6.09.18 PM

Our final app looks like this:

Screen Shot 2018-06-11 at 5.43.13 PM

We will want to export our source code so we have a backup and also export the app for deployment to our VXML servers.  They are different, we will do a backup of the source code first. Let’s right click on the application in studio and select “Export…

Screen Shot 2018-06-11 at 5.46.49 PM

From here we want to select General -> Archive File.

Screen Shot 2018-06-11 at 5.46.57 PM

Next give it a name we and directory you like and finish it up.

Screen Shot 2018-06-11 at 5.47.28 PM

Now we have a backup of our source code.  To use it just use the File -> Import… within CVP Studio. In practice you’ll want a more automated way to back up your projects, such as Source Control or working within a Dropbox or other cloud synchronized folder. The source folder for your project can be used directly for backups in this case.

The next step is creating a deploy zip file for the application. We are going to right click on the CloverhoundBlog app and choose the Deploy option.

Screen Shot 2018-06-11 at 5.47.46 PM

Select the Archive File option, give it a name and folder location you like, then click Finish.

Screen Shot 2018-06-11 at 6.04.14 PM

Now you have your deployment file and your good to go.  The last step is to upload it to CVP through the ops console (There are a couple other ways to deploy Studio scripts, but we don’t recommend them. The Archive File option is by far the easiest and least error-prone).

Deploying the CVP Application through Ops Console

To access the Ops Console, use the URL https://<CVP Ops Console IP>:9443/oamp. You will need to accept the browser security warnings if your certificates are not trusted. The login screen looks like this:

Screen Shot 2018-06-11 at 6.17.42 PM

After logging in, we need to browse to our VXML server we want to deploy this application to.  Use Device Management -> VXML Server.

Screen Shot 2018-06-11 at 6.20.14 PM

It will look like this.

Screen Shot 2018-06-11 at 6.20.46 PM

Select your CVP VXML server and in the menu bar, go to File Transfer -> VXML Applications.

Screen Shot 2018-06-11 at 6.21.49 PM

Select our deployment file.  I’ve left a copy here for you.

Screen Shot 2018-06-11 at 6.22.47 PM

Once you click Transfer, it will be pushed down to the CVP VXML Server.

Screen Shot 2018-06-11 at 6.22.59 PM

In production environments, you can do similar for all VXML Servers at once by following the similar VXML Application File Transfer option under Bulk Administration.

Pointing CCE to your application

We need to go back to our script in CCE and change the name of the application we had previously pointed at “HelloWorld” to now point to CloverhoundBlog.

Let’s open our script up in Script Editor on the CCE AW.

Screen Shot 2018-06-11 at 6.25.30 PM

You can see just barely above, but you can put the script into Edit mode by clicking the small pencil icon shown here.

Screen Shot 2018-06-11 at 6.25.22 PM

From here we are going to select our Set Variable with the name of the custom app we want to call and change it from ‘HelloWorld’ to ‘CloverhoundBlog’.

Screen Shot 2018-06-11 at 6.25.57 PM

That’s it, place a call to your number and you should here it work!  The last step is we are going to cover a couple housekeeping / maintenance areas on the CVP VXML Server in case you have issues.


Some random facts and places to check on CVP:

  • The CVP Application is installed at C:\Cisco\CVP. General logs for CVP are kept in the logs folder, but they do not go in depth on the execution of specific scripts. You will find mostly generic, licensing and startup errors in these logs, along with lots of statistics.

Screen Shot 2018-06-11 at 6.36.08 PM

  • The CVP VXML Server (which hosts and executes Studio applications) is located at C:\Cisco\CVP\VXMLServer. It has its own logs folder that is mostly generic except you can find some useful error in the GlobalErrorLog folder from time to time.

Screen Shot 2018-06-11 at 6.35.59 PM

  • For individual application logs you will want to dig down all the way too: C:\Cisco\CVP\VXMLServer\applications\<Your Application Name>. In this folder you will find a logs folder, which has great activity and error logs. Both are very detailed and quite handy.

Screen Shot 2018-06-11 at 6.37.20 PM

Here is the Activity Log of our app running and me pressing 1.

Screen Shot 2018-06-11 at 6.38.22 PM,06/11/2018 18:13:04.943,,start,newcall,,06/11/2018 18:13:04.943,,start,ani,+19803338415,06/11/2018 18:13:04.943,,start,areacode,NA,06/11/2018 18:13:04.943,,start,exchange,NA,06/11/2018 18:13:04.943,,start,dnis,+19803338415,06/11/2018 18:13:04.943,,start,uui,NA,06/11/2018 18:13:04.943,,start,iidigits,NA,06/11/2018 18:13:04.943,,start,parameter,callid=FFA5C3026CFB11E8925BD306C,06/11/2018 18:13:04.943,,start,parameter,_dnis=811111111110002,06/11/2018 18:13:04.943,,start,parameter,_ani=+19803338415,06/11/2018 18:13:04.943,CVP Subdialog Start_01,enter,,06/11/2018 18:13:05.053,CVP Subdialog Start_01,exit,done,06/11/2018 18:13:05.054,2_Option_Menu_01,enter,,06/11/2018 18:13:05.058,2_Option_Menu_01,interaction,audio_group,initial_audio_group,06/11/2018 18:13:08.610,2_Option_Menu_01,interaction,utterance,1,06/11/2018 18:13:08.610,2_Option_Menu_01,interaction,inputmode,dtmf,06/11/2018 18:13:08.610,2_Option_Menu_01,interaction,interpretation,1,06/11/2018 18:13:08.614,2_Option_Menu_01,interaction,confidence,1,06/11/2018 18:13:08.705,2_Option_Menu_01,data,value,1,06/11/2018 18:13:08.705,2_Option_Menu_01,data,selection,1,06/11/2018 18:13:08.705,2_Option_Menu_01,data,confidence,1,06/11/2018 18:13:08.705,2_Option_Menu_01,data,value_confidence,1,06/11/2018 18:13:08.706,2_Option_Menu_01,exit,option1,06/11/2018 18:13:08.706,Sales,enter,,06/11/2018 18:13:08.710,Sales,interaction,audio_group,initial_audio_group,06/11/2018 18:13:08.739,Sales,exit,done,06/11/2018 18:13:08.739,CVP Subdialog Return_01,enter,,06/11/2018 18:13:10.338,CVP Subdialog Return_01,exit,,06/11/2018 18:13:10.340,,end,how,app_session_complete,06/11/2018 18:13:10.340,,end,result,normal,06/11/2018 18:13:10.340,,end,duration,5

  • One other folder under C:\Cisco\CVP\VXMLServer\applications\<Your Application Name> is the admin folder. This contains tools you can use to manually deploy and update apps (not recommended in general). The status.bat file is also useful for figuring out if and how much the app is being used.  Here is what it looks running the script while I’m calling in:

Screen Shot 2018-06-11 at 6.42.11 PM


It looks like a lot of steps and the first time you do it, it certainly is.  I tried to make this as easy as possible, but I’m sure getting it working the first time will be a treat.  We will write a follow-up blog around how to do more complex self-service apps in studio like Database and Java Elements, but we wanted to start with a primer of how to even get these apps running.