IVRs – Standard Abilities, Tips and Tricks

Philippe Lindheimer

Philippe Lindheimer

I didn’t get a lot of feedback from last week’s article on what you wanted to hear so I scanned the forums a bit and decided the IVR generated enough questions that I would put together an article going into a bit of depth on this. Well – it grew a lot longer then anticipated but here you go. I hope this is useful, please provide comments, feedback and let us know what you want to hear about next week if you want these informational series to continue!

IVRs – Standard Abilities, Tips and Tricks
An IVR, or Digital Receptionist, is one of the powerful features that users of freePBX™ take advantage of when designing their call handling options. The IVR can be used as a simple means to answer the phone and direct callers to different departments, or to create much more complex trees of information sources, and beyond.

Common questions repeated on freePBX™ and other forums range from basic operation, how to expose access to internal features such as voicemail checking, and more complex tasks like integrating remote extensions connected through Dundi to enable direct extension dialing across a cluster.

This article will begin by giving an overview of the built in abilities and covering some more standard but subtle techniques of using the timeout (t) and invalid (i) extensions, and exposing feature codes into your IVR. Also, hooking into an IVR with a custom context to do more customized applications, and a bit about how Asterisk resolves extensions so you can understand and debug such custom changes will be discussed.

Overview of Standard Features

Prior to configuring specific IVR options, choose if the IVR should allow direct extension dialing and/or ‘dial-by-name’ directory dialing. The directory dialing simply exposes the directory application which must be installed and enabled in the Feature Code menu. On most systems you will have a single choice for Directory Context: Default. The directory segregates groups of users based on the voicemail context they are assigned. Unless you have created different voicemail contexts when configuring voicemail, everyone will be available in the directory. Otherwise, it lets you limit the directory dialing to those contexts. (We will not elaborate any further on this aspect and assume you only have default as your voicemail context for the sake of this article).

The enable direct dial option is fairly straight forward but still leads to occasional confusion. Choosing that will allow any local extension to be dialed by its extension number. Furthermore, if that extension has a Follow-Me configured, the Follow-Me will be used. (As a side note – it will also be used in directory dialing above). Only the extensions are exposed which leads to common questions when users are trying to direct dial Ring Groups, Queues, Conference Rooms, etc. These are not exposed by checking this box, nor would we want them exposed for good reason. Exposing these is described below.

IVR Options

The next section of the IVR GUI provides the means to specify what action to take when a given option is pressed. For each menu choice you may configure:

  • The Return to IVR checkbox – we’ll get back to that later
  • The text box on the left where you put in the desired IVR option that the caller will press (which does not need to be a single digit)
  • The destination on the right – what to do when the caller presses that option.

In most cases, these are fairly straight forward. You may have a Ring Group setup for “Sales” and provide an option where you tell the caller to press 1 for “Sales”. So you put in 1 as your option, and choose the “Sales” Ring Group. Another example may be the need to expose a “meet-me” conference room. You may want to treat this like the above example, press 3 for the conference room. Alternatively, you may want to use the same conference room number that is used internally so people don’t have to remember another number. The solution is simple, if your conference room number is 7666 (R-O-O-M) you can simply put 7666 as your IVR option (in the left textbox) and then choose that same conference room as the destination.

But how to expose something like voicemail system access at the IVR when there are no destinations listed? Voicemail access or other feature codes do not show up as destinations to the IVR or anywhere else in freePBX™ until you expose them as a Misc Destination. Since this article is about IVRs, I will leave it to the reader to work this exercise on his or her own. Go to the Misc Destinations module, create a destination for the feature code you want to expose (e.g. voicemail access) and then go back to the IVR and now you should be able to choose your newly created destination in the Misc Destination list.

Next, how do you control the behavior when a user presses an invalid extension or waits to long. Asterisk has two special extensions called the ‘t’ extension and the ‘i’ extensions which are used to handle timeouts and invalid extensions, respectively. When you create an IVR, it will create both of those options by default unless you specifically define your own options for them. The default behavior is to simply play an appropriate message and then loop back to the beginning of the IVR – up to 3 times before it drops the call. This may not be the desired behavior and is easy to override by simply putting ‘i’ or ‘t’ as the option in the same way you would define any other IVR option digits, and then choose an appropriate destination. Maybe you just want it to go back to the beginning of this IVR; you do this by selecting ‘yourself’ as the destination.

This next example will desribe a technique to allow extension dialing at the IVR while ‘blocking’ certain extensions. Assume the boss does not want the general public direct dialing him or her from the IVR but other extensions should be accessible. If a caller dials the boss’s extension, it should go to his or her assistant instead. How do you accomplish this? In this case, you would define an IVR option that is the same as the boss’s extension number and then set the destination for that option to the assistant’s extension. Because of the way the IVR context is created, and how Asterisk works, the caller will now be re-directed to the assistant if they dial the boss’s extension (see details below for a further explanation). (Note – if this technique is used, it will not keep the ‘dial-by-name’ directory from reaching the boss.)

Now, back to the Return to IVR checkbox – what is that and how would you use it. In a more sophisticated IVR tree, where you have IVRs nested under other IVRs, you often want an option to offer the selection of: “to return to the previous menu, press 9 now” (where 9 is an arbitrary option). This is what Return to IVR does and is available in both the IVR and Announcement modules. Specifically, if this IVR was called as a child from another IVR, and the user presses that option, it will return up one level. You still need to define an alternate destination on the right – to handle the case where this IVR is not called as a child – but this will always be ignored if the box is checked and this IVR was called from another.

Let’s look at a simple example from above. We want to redefine the invalid ‘i’ option to go back to the top of the current IVR – however, we want to play a custom message first. How can we accomplish this? The simple way would be to define the ‘i’ option and choose as its destination an invalid option announcement that you previously created. But don’t check the Return to IVR here. Instead, check it in the announcement module where you define the invalid option announcement that you have chosen for the ‘i’ option. The end results when a user presses an invalid option, they will go to the announcement you specified. Since the announcement has Return to IVR checked, it will return back to this IVR after it plays its message, having the desired result.

A more sophisticated example might be creating a child IVR that provides directions to your facility. The parent IVR would choose the Directions IVR as its destination when someone wants directions. In the Directions IVR, you may have directions from the airport, highway, etc. Each of those would call an appropriate announcement module destination with the directions. You would also include an option saying ‘to return to the previous menu, press 9’ (for example). So now option ‘9’ becomes the option where you check Return to IVR and when pressed, it will return to which ever IVR called it. So, for example, if you have a day and night IVR you use, you can have both of them provide an option for directions and both point to this same Directions IVR. The return path will always be back to the correct IVR. Of course, you will also want to check Return to IVR in each of the announcements that provide the directions.

Hooking into an IVR with custom extensions

Let’s start by looking at the Asterisk dial plan that is generated from a fairly simple IVR that has two options and the ‘i’ extension redefined, in addition to enabling directory dialing and direct extension dialing:

include => ivr-7-custom
include => ext-findmefollow
include => ext-local
include => app-directory
exten => #,1,Goto(app-directory,#,1)
exten => h,1,Hangup
exten => s,1,Set(LOOPCOUNT=0)
exten => s,n,Set(__DIR-CONTEXT=default)
exten => s,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT})
exten => s,n,Set(_IVR_CONTEXT=${CONTEXT})
exten => s,n,GotoIf($["${CDR(disposition)}" = "ANSWERED"]?begin)
exten => s,n,Answer
exten => s,n,Wait(1)
exten => s,n(begin),Set(TIMEOUT(digit)=3)
exten => s,n,Set(TIMEOUT(response)=10)
exten => s,n,Background(custom/welcome)
exten => hang,1,Playback(vm-goodbye)
exten => hang,n,Hangup
exten => 1,1,dbDel(${BLKVM_OVERRIDE})
exten => 1,n,Set(__NODEST=)
exten => 1,n,Goto(ext-group,444,1)
exten => 2,1,dbDel(${BLKVM_OVERRIDE})
exten => 2,n,Set(__NODEST=)
exten => 2,n,Goto(ext-local,${VM_PREFIX}201,1)
exten => i,1,dbDel(${BLKVM_OVERRIDE})
exten => i,n,Set(__NODEST=)
exten => i,n,Goto(app-announcement-2,s,1)
exten => t,1,Goto(loop,1)
exten => loop,1,Set(LOOPCOUNT=$[${LOOPCOUNT} + 1])
exten => loop,n,GotoIf($[${LOOPCOUNT} > 2]?hang,1)
exten => loop,n,Goto(ivr-7,s,begin)
exten => return,1,Set(_IVR_CONTEXT=${CONTEXT})
exten => return,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT_${CONTEXT}})
exten => return,n,Goto(ivr-7,s,begin)
exten => fax,1,Goto(ext-fax,in_fax,1)
; end of

You will notice the includes at the top. The first is IVR-7-custom is included at the very top. The name of this context will not change since the ‘7’ is a unique identifier that is auto-generated. Now you can safely use this context in extensions_custom.conf. The subsequent pair of included contexts are ext-findmefollow and then ext-local. These are included as a result of choosing direct extension dialing. Lastly, app-directory is included as well as the next “goto” extension as a result of the Directory Dialing choice we made. Beyond that, we will not go into detail on the code that is generated except to note a couple of observations. Since the ‘i’ extension has been defined, it does not “goto” the auto-generated ‘loop’ code. Instead, it goes to an announcement we have defined that plays a custom invalid message and then Returns to IVR as we described previously. Timeouts will still go to the auto generated loop since we did not redefine them.

Now let’s talk about standard Asterisk flow so you can understand how and where to insert custom contexts to do specialized tasks. A common source of confusion is the include statement. Often custom dialplan instructions are put into a custom context such as ivr-7-custom and then nothing happens. Here is why: when a call comes in to this IVR, it is directed to the ‘s’ extension which means it will go through the normal flow up until playing the background command and then it will stop and wait the response timeout (TIMEOUT(response)) time for digits to be pressed (and if none are pressed, it will look for the ‘t’ extension). Once digits are pressed, it will scan the entire context, ignoring any includes to see if it can find a match. If no match is found, it will then go to the first include and repeat the process recursively within that context (including other contexts that are included within them). If nothing is found, it will then check the next include – and so-forth, until it finds a match. (And if none are found – since we have defined the ‘i’ extension, the call will eventually go to the dialplan defined at the ‘i’ extensions.) The important point to take away here is that it will never even look at the included contexts if it finds an acceptable match in the main context.

We will use the example blocking the boss’s extension from above to see how this flow works. Assume the boss’s extension is 301. In this dialplan there is no 301 within the ivr-7 context, so it now starts to check the includes until it eventually finds extension 301 in ext-findmefollow or ext-local. Since we didn’t want this behavior, we created a new option for the boss’s extension to send callers to the administrative assistant (in this example, 220). We now have the following additional code inserted:

exten => 301,1,dbDel(${BLKVM_OVERRIDE})
exten => 301,n,Set(__NODEST=)
exten => 301,n,Goto(ext-local,220,1)

since this is defined within this context, Asterisk will search no further, it will never look at the included ext-local or ext-findmefollow context (even though they come first), and direct the caller to extension 220 in its place.

If you want to do something a little more ‘general’ such as enable any meet-me room that is configured within this IVR, or maybe allow direct dialing via a Dundi setup that you have created. This is where the custom includes come in. Let’s use the conference room example. This is where you want to take advantage of

include => ivr-7-custom

to easily expose all of your meet-me rooms. You could define each one individually as described earlier, but then you would have to manually add options here each time you added something from the conference module.

Within extensions_custom.conf – you can simply add the following 2 lines which would result in this specific IVR having access to all your conference rooms:

include => ext-meetme

That’s it. Now when someone dials a conference room extension at the IVR, it will first look for it within the IVR’s main context, and when it doesn’t find it, it will start going through the included contexts, which leads it to the ext-meetme where these are defined. Now you have the desired behavior since any new conference room that is created gets put into ext-meetme. Taking this same approach, you can expose other aspects of the dial plan in this same way. If you have a Dundi setup, and want to give access to extensions defined in a Dundi context you have created, you could put it here as well and they could be direct dialed from this IVR.

Beware if you start using custom contexts like this. Make sure you really understand what you are doing since it is easy to create security holes or result in undesirable or unpredictable behavior.


The IVR is a powerful tool that can be used to create simple welcome messages and call routing, or more complex IVR trees with subroutine-like return capabilities. You can use the existing GUI along with other modules like Misc Destinations and Announcements to expose additional functionality to the IVR and change default behaviors to your preferences. To dig further into it, you can write your own custom contexts to control and expose abilities although it requires an understanding of the way Asterisk prioritizes and processes extensions to get the achieved results. This should only be done by users who really understand the implications and consequences.

We hope you find this article useful, please post comments and questions, and let us know what you want to hear in the next series!


Share this Blogpost

Start the Discussion

Sign up for our Newsletter

Scroll to Top