Gather User Input via Keypad (DTMF Tones)

In this guide, we'll show you how to gather user input during a phone call through the phone's keypad (using DTMF tones) in your application. By using the TwiML <Gather> Verb, you can create interactive voice response (IVR) systems and other phone based interfaces for your users.

Choose a language and let's get started! 

Also, see our IVR landing page for specific IVR features and language walkthroughs.

Loading Code Samples...
Language
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 6.x
  • 7.x
SDK Version:
  • 2.x
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 5.x
  • 6.x
SDK Version:
  • 4.x
  • 5.x
// This example uses JavaScript language features present in Node.js 6+
'use strict';

const express = require('express');
const twilio = require('twilio');
const urlencoded = require('body-parser').urlencoded;

let app = express();

// Parse incoming POST params with Express middleware
app.use(urlencoded({ extended: false }));

// Create a route that will handle Twilio webhook requests, sent as an 
// HTTP POST to /voice in our application
app.post('/voice', (request, response) => {
  // Use the Twilio Node.js SDK to build an XML response
  let twiml = new twilio.TwimlResponse();

  // Use the <Gather> verb to collect user input 
  twiml.gather({ numDigits: 1 }, (gatherNode) => {
    gatherNode.say('For sales, press 1. For support, press 2.');
  });

  // If the user doesn't enter input, loop
  twiml.redirect('/voice');

  // Render the response as XML in reply to the webhook request
  response.type('text/xml');
  response.send(twiml.toString());
});

// Create an HTTP server and listen for requests on port 3000
app.listen(3000);
const express = require('express');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const urlencoded = require('body-parser').urlencoded;

const app = express();

// Parse incoming POST params with Express middleware
app.use(urlencoded({extended: false}));

// Create a route that will handle Twilio webhook requests, sent as an
// HTTP POST to /voice in our application
app.post('/voice', (request, response) => {
  // Use the Twilio Node.js SDK to build an XML response
  const twiml = new VoiceResponse();

  // Use the <Gather> verb to collect user input
  const gather = twiml.gather({numDigits: 1});
  gather.say('For sales, press 1. For support, press 2.');

  // If the user doesn't enter input, loop
  twiml.redirect('/voice');

  // Render the response as XML in reply to the webhook request
  response.type('text/xml');
  response.send(twiml.toString());
});

// Create an HTTP server and listen for requests on port 3000
console.log('Twilio Client app HTTP server running at http://127.0.0.1:3000');
app.listen(3000);
// In Package Manager, run:
// Install-Package Twilio.Mvc -DependencyVersion HighestMinor

using System.Web.Mvc;
using Twilio.Mvc;
using Twilio.TwiML;
using Twilio.TwiML.Mvc;

public class VoiceController : TwilioController
{
  [HttpPost]
  public TwiMLResult Index(VoiceRequest request)
  {
    var response = new TwilioResponse();

    // Use the <Gather> verb to collect user input
    response.BeginGather(new {numDigits = 1});
    response.Say("For sales, press 1. For support, press 2.");
    response.EndGather();

    // If the user doesn't enter input, loop
    response.Redirect("/voice");

    return TwiML(response);
  }
}
# Get twilio-ruby from twilio.com/docs/ruby/install
require 'rubygems' # This line not needed for ruby > 1.8
require 'sinatra'
require 'twilio-ruby'

post '/voice' do
  Twilio::TwiML::Response.new do |r|
    r.gather numDigits: 1 do |g|
      g.say 'For sales, press 1. For support, press 2.'
    end
    r.redirect('/voice')
  end.text
end
// In Package Manager, run:
// Install-Package Twilio.AspNet.Mvc -DependencyVersion HighestMinor

using System.Web.Mvc;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

public class VoiceController : TwilioController
{
    [HttpPost]
    public ActionResult Index()
    {
        var response = new VoiceResponse();

        // Use the <Gather> verb to collect user input
        response.Gather(new Gather(numDigits: 1)
		                .Say("For sales, press 1. For support, press 2."));
        // If the user doesn't enter input, loop
        response.Redirect("/voice");

        return TwiML(response);
    }
}
<?php
// Create a route that will handle Twilio webhook requests, sent as an
// HTTP POST to /voice in our application
require_once '/path/to/vendor/autoload.php';

use Twilio\Twiml;

// Use the Twilio PHP SDK to build an XML response
$response = new Twiml();

// Use the <Gather> verb to collect user input
$gather = $response->gather(array('numDigits' => 1));
// use the <Say> verb to request input from the user
$gather->say('For sales, press 1. For support, press 2.');

// If the user doesn't enter input, loop
$response->redirect('/voice');

// Render the response as XML in reply to the webhook request
header('Content-Type: text/xml');
echo $response;
from flask import Flask
from twilio import twiml

app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def voice():
    """Respond to incoming phone calls with a menu of options"""
    # Start our TwiML response
    resp = twiml.Response()

    # Start our <Gather> verb
    with resp.gather(numDigits=1) as gather:
        gather.say('For sales, press 1. For support, press 2.')

    # If the user doesn't select an option, redirect them into a loop
    resp.redirect('/voice')

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
# Get twilio-ruby from twilio.com/docs/ruby/install
require 'rubygems' # This line not needed for ruby > 1.8
require 'sinatra'
require 'twilio-ruby'

post '/voice' do
  Twilio::TwiML::VoiceResponse.new do |r|
    r.gather numDigits: 1 do |g|
      g.say('For sales, press 1. For support, press 2.')
    end
    r.redirect('/voice')
  end.to_s
end
import com.twilio.sdk.verbs.Gather;
import com.twilio.sdk.verbs.Redirect;
import com.twilio.sdk.verbs.Say;
import com.twilio.sdk.verbs.TwiMLResponse;
import com.twilio.sdk.verbs.TwiMLException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class VoiceServlet extends HttpServlet {

    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // Create a TwiML response and add our friendly message.
        TwiMLResponse twiml = new TwiMLResponse();

        Gather gather = new Gather();
        gather.setNumDigits(1);
        try {
            gather.append(new Say("For sales, press 1. For support, press 2."));
            twiml.append(gather);
            twiml.append(new Redirect("/voice"));
        } catch (TwiMLException e) {
            throw new RuntimeException(e);
        }

        response.setContentType("application/xml");
        response.getWriter().print(twiml.toXML());
    }
}
from flask import Flask
from twilio.twiml.voice_response import VoiceResponse, Gather

app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def voice():
    """Respond to incoming phone calls with a menu of options"""
    # Start our TwiML response
    resp = VoiceResponse()

    # Start our <Gather> verb
    gather = Gather(num_digits=1)
    gather.say('For sales, press 1. For support, press 2.')
    resp.append(gather)

    # If the user doesn't select an option, redirect them into a loop
    resp.redirect('/voice')

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
import com.twilio.twiml.Gather;
import com.twilio.twiml.Redirect;
import com.twilio.twiml.Say;
import com.twilio.twiml.TwiML;
import com.twilio.twiml.TwiMLException;
import com.twilio.twiml.VoiceResponse;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class VoiceServlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // Create a TwiML response and add our friendly message.
        TwiML twiml = new VoiceResponse.Builder()
                .gather(
                        new Gather.Builder()
                                .numDigits(1)
                                .say(new Say.Builder("For sales, press 1. For support, press 2.").build())
                                .build()
                )
                .redirect(new Redirect.Builder().url("/voice").build())
                .build();

        response.setContentType("application/xml");
        try {
            response.getWriter().print(twiml.toXml());
        } catch (TwiMLException e) {
            throw new RuntimeException(e);
        }
    }
}
This example returns TwiML containing a <Say> tag nested within a <Gather> tag. The user will be prompted to choose sales or support.
Use <Gather> to collect user input via the keypad (DTMF tones)

This example returns TwiML containing a <Say> tag nested within a <Gather> tag. The user will be prompted to choose sales or support.

Kevin Whinnery
Paul Kamp
Andrew Baker
David Prothero

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
SDK Version:
  • 4.x
  • 5.x
SDK Version:
  • 6.x
  • 7.x
SDK Version:
  • 2.x
  • 3.x
SDK Version:
  • 5.x
SDK Version:
  • 5.x
  • 6.x
SDK Version:
  • 4.x
  • 5.x
// This example uses JavaScript language features present in Node.js 6+
'use strict';

const express = require('express');
const twilio = require('twilio');
const urlencoded = require('body-parser').urlencoded;

let app = express();

// Parse incoming POST params with Express middleware
app.use(urlencoded({ extended: false }));

// Create a route that will handle Twilio webhook requests, sent as an 
// HTTP POST to /voice in our application
app.post('/voice', (request, response) => {
  // Use the Twilio Node.js SDK to build an XML response
  let twiml = new twilio.TwimlResponse();

  // Use the <Gather> verb to collect user input 
  twiml.gather({ numDigits: 1 }, (gatherNode) => {
    gatherNode.say('For sales, press 1. For support, press 2.');
  });

  // If the user doesn't enter input, loop
  twiml.redirect('/voice');

  // Render the response as XML in reply to the webhook request
  response.type('text/xml');
  response.send(twiml.toString());
});

// Create an HTTP server and listen for requests on port 3000
app.listen(3000);
const express = require('express');
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const urlencoded = require('body-parser').urlencoded;

const app = express();

// Parse incoming POST params with Express middleware
app.use(urlencoded({extended: false}));

// Create a route that will handle Twilio webhook requests, sent as an
// HTTP POST to /voice in our application
app.post('/voice', (request, response) => {
  // Use the Twilio Node.js SDK to build an XML response
  const twiml = new VoiceResponse();

  // Use the <Gather> verb to collect user input
  const gather = twiml.gather({numDigits: 1});
  gather.say('For sales, press 1. For support, press 2.');

  // If the user doesn't enter input, loop
  twiml.redirect('/voice');

  // Render the response as XML in reply to the webhook request
  response.type('text/xml');
  response.send(twiml.toString());
});

// Create an HTTP server and listen for requests on port 3000
console.log('Twilio Client app HTTP server running at http://127.0.0.1:3000');
app.listen(3000);
// In Package Manager, run:
// Install-Package Twilio.Mvc -DependencyVersion HighestMinor

using System.Web.Mvc;
using Twilio.Mvc;
using Twilio.TwiML;
using Twilio.TwiML.Mvc;

public class VoiceController : TwilioController
{
  [HttpPost]
  public TwiMLResult Index(VoiceRequest request)
  {
    var response = new TwilioResponse();

    // Use the <Gather> verb to collect user input
    response.BeginGather(new {numDigits = 1});
    response.Say("For sales, press 1. For support, press 2.");
    response.EndGather();

    // If the user doesn't enter input, loop
    response.Redirect("/voice");

    return TwiML(response);
  }
}
# Get twilio-ruby from twilio.com/docs/ruby/install
require 'rubygems' # This line not needed for ruby > 1.8
require 'sinatra'
require 'twilio-ruby'

post '/voice' do
  Twilio::TwiML::Response.new do |r|
    r.gather numDigits: 1 do |g|
      g.say 'For sales, press 1. For support, press 2.'
    end
    r.redirect('/voice')
  end.text
end
// In Package Manager, run:
// Install-Package Twilio.AspNet.Mvc -DependencyVersion HighestMinor

using System.Web.Mvc;
using Twilio.AspNet.Mvc;
using Twilio.TwiML;

public class VoiceController : TwilioController
{
    [HttpPost]
    public ActionResult Index()
    {
        var response = new VoiceResponse();

        // Use the <Gather> verb to collect user input
        response.Gather(new Gather(numDigits: 1)
		                .Say("For sales, press 1. For support, press 2."));
        // If the user doesn't enter input, loop
        response.Redirect("/voice");

        return TwiML(response);
    }
}
<?php
// Create a route that will handle Twilio webhook requests, sent as an
// HTTP POST to /voice in our application
require_once '/path/to/vendor/autoload.php';

use Twilio\Twiml;

// Use the Twilio PHP SDK to build an XML response
$response = new Twiml();

// Use the <Gather> verb to collect user input
$gather = $response->gather(array('numDigits' => 1));
// use the <Say> verb to request input from the user
$gather->say('For sales, press 1. For support, press 2.');

// If the user doesn't enter input, loop
$response->redirect('/voice');

// Render the response as XML in reply to the webhook request
header('Content-Type: text/xml');
echo $response;
from flask import Flask
from twilio import twiml

app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def voice():
    """Respond to incoming phone calls with a menu of options"""
    # Start our TwiML response
    resp = twiml.Response()

    # Start our <Gather> verb
    with resp.gather(numDigits=1) as gather:
        gather.say('For sales, press 1. For support, press 2.')

    # If the user doesn't select an option, redirect them into a loop
    resp.redirect('/voice')

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
# Get twilio-ruby from twilio.com/docs/ruby/install
require 'rubygems' # This line not needed for ruby > 1.8
require 'sinatra'
require 'twilio-ruby'

post '/voice' do
  Twilio::TwiML::VoiceResponse.new do |r|
    r.gather numDigits: 1 do |g|
      g.say('For sales, press 1. For support, press 2.')
    end
    r.redirect('/voice')
  end.to_s
end
import com.twilio.sdk.verbs.Gather;
import com.twilio.sdk.verbs.Redirect;
import com.twilio.sdk.verbs.Say;
import com.twilio.sdk.verbs.TwiMLResponse;
import com.twilio.sdk.verbs.TwiMLException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class VoiceServlet extends HttpServlet {

    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // Create a TwiML response and add our friendly message.
        TwiMLResponse twiml = new TwiMLResponse();

        Gather gather = new Gather();
        gather.setNumDigits(1);
        try {
            gather.append(new Say("For sales, press 1. For support, press 2."));
            twiml.append(gather);
            twiml.append(new Redirect("/voice"));
        } catch (TwiMLException e) {
            throw new RuntimeException(e);
        }

        response.setContentType("application/xml");
        response.getWriter().print(twiml.toXML());
    }
}
from flask import Flask
from twilio.twiml.voice_response import VoiceResponse, Gather

app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def voice():
    """Respond to incoming phone calls with a menu of options"""
    # Start our TwiML response
    resp = VoiceResponse()

    # Start our <Gather> verb
    gather = Gather(num_digits=1)
    gather.say('For sales, press 1. For support, press 2.')
    resp.append(gather)

    # If the user doesn't select an option, redirect them into a loop
    resp.redirect('/voice')

    return str(resp)

if __name__ == "__main__":
    app.run(debug=True)
import com.twilio.twiml.Gather;
import com.twilio.twiml.Redirect;
import com.twilio.twiml.Say;
import com.twilio.twiml.TwiML;
import com.twilio.twiml.TwiMLException;
import com.twilio.twiml.VoiceResponse;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class VoiceServlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

        // Create a TwiML response and add our friendly message.
        TwiML twiml = new VoiceResponse.Builder()
                .gather(
                        new Gather.Builder()
                                .numDigits(1)
                                .say(new Say.Builder("For sales, press 1. For support, press 2.").build())
                                .build()
                )
                .redirect(new Redirect.Builder().url("/voice").build())
                .build();

        response.setContentType("application/xml");
        try {
            response.getWriter().print(twiml.toXml());
        } catch (TwiMLException e) {
            throw new RuntimeException(e);
        }
    }
}