Participate in Local Issues with a SMS Chatbot
Tags: techforgood, javascript, chatbot, twilio
Published: 2020-07-23 22:26:10

---
title: Participate in Local Issues with a SMS Chatbot
published: true
description: Learn how to build a SMS chatbot to call and email people in your community about local issues using Twilio SendGrid, Autopilot, Functions, and TwiML Bins.
tags: techforgood, javascript, chatbot, twilio
cover_image: https://twilio-cms-prod.s3.amazonaws.com/images/chatbotissues.width-1616.png
---
If you have opinions about how your city is run, it’s more important than ever to make your voice heard. This blog post will go over how to build a SMS chatbot using [Twilio Autopilot](https://www.twilio.com/autopilot), [Twilio SendGrid](https://sendgrid.com/), [Twilio Functions](https://www.twilio.com/docs/runtime/functions), [TwiML Bins](https://www.twilio.com/docs/runtime/tutorials/twiml-bins), and JavaScript to engage in local civic issues. 

One example might be San Francisco, where the city is planning to permanently cut 40 of 68 bus lines and free bus rides for youth. 

In this blog post, concerned citizens can tell members of the San Francisco County Transportation Authority to not cut bus lines. Read on for a step-by-step process to build the bot, and you can text the <strong>+14153068517</strong> number to see the example!
![sms example 1](https://twilio-cms-prod.s3.amazonaws.com/images/A9N6OpF72I9BdQxmoZ1CXcRZ9zGge95ufekWP8E3KLAfo.width-1600.png)

### Set Up your SMS Chatbot
To follow along with this post, you need three things:
- A Twilio account - [sign up for a free one here and receive an extra $10 if you upgrade through this link](http://www.twilio.com/referral/iHsJ5D)
- A Twilio phone number with SMS capabilities - [configure one here](https://www.twilio.com/console/phone-numbers/search)
- A SendGrid account - [make one here](https://app.sendgrid.com/)

Go to your [Autopilot console](https://www.twilio.com/console/autopilot/list) and under <em>Select a Bot</em> click <em>Start from Scratch</em>.
![build a bot autopilot button](https://twilio-cms-prod.s3.amazonaws.com/images/EZgjUqgpH-gtnNY84T1L1YVew4seXbmXgIVDU95TpP2zK.width-1000.png)

Give your bot a title like "MuniCall" and click <em>Create bot</em>.
![unique name button](https://twilio-cms-prod.s3.amazonaws.com/images/cPC2RvV3GbX1hSHNMgdXqZolmY3EG_otX0lWFQdtGqRqi.width-1000.png)

Next to the <em>Greeting</em> task, click <em>Program</em> and replace the JSON there with a <code>Say</code> and <code>Listen</code> Action announcing what services the bot can provide.

```json
{
        "actions": [
                {
                        "say": "Hi! I'm a chatbot that will automatically mass email or call ALL 11 San Francisco County Transportation Authority members for you. \n\n Send something like `email`, `call`, or `resources` to get started."
                },
                {
                        "listen": true
                }
        ]
}
```
Click <em>save</em>.

### Using Twilio Functions and TwiML Bins for Calls to Decision Makers
Click <em>All Tasks</em> and add a task called <em>Call</em>.

On the same line as that <em>Call</em> task, click <em>Train</em> to add samples that will trigger this task. Samples are different words or phrases the user might say to call their representatives, running this task. For the <em>Call</em> task you might add samples like "phone", "voicemail", "call representatives", "call reps", "dial", "leave a voicemail", and other similar phrases.

After adding your samples, click <em>Switch to program task</em> near the top-right.
![samples in UI](https://twilio-cms-prod.s3.amazonaws.com/images/u8Qwz3WAstYw1Nz2vSNRNml5d1lUx36a_woCY-D3dCj1w.width-1600.png)

Replace the JSON in the JSON bin with the following which uses a <em>Collect</em> Action to ask a series of questions and group them and a user's answers together.

```json
{
        "actions": [
                {
                        "collect": {
                                "name": "call_collect",
                                "questions": [
                                        {
                                                "question": "Let us call all 11 members of the San Francisco County Transportation Authority or leave a voicemail! What is your first name?",
                                                "name": "name"
                                        },
                                        {
                                                "question": "What is your SF zip code? If you need one, use 94109.",
                                                "name": "zip_code",
                                                "type": "Twilio.NUMBER"
                                        }
                                ],
                                "on_complete": {
                                        "redirect": {
                                                "method": "POST",
                                                "uri": "REPLACE-WITH-YOUR-FUNCTION-IN-THE-NEXT-PART.twil.io/municall"
                                        }
                                }
                        }
                }
        ]
}
```
After asking the user all the questions in the <code>questions</code> array, this task [redirects](https://www.twilio.com/docs/autopilot/actions/redirect) to a Twilio Function to make the phone calls using JavaScript. [Create a new Function here](https://www.twilio.com/console/functions/manage) by clicking the red plus button. Make a blank function and give it a name like "Muni Call" and add on to the path as shown below. Don't forget to replace the Function path in your <code>Call</code> task above!
![call Function name, path](https://twilio-cms-prod.s3.amazonaws.com/images/qQl1itKLgv-SmnTiWpSEigZqcBmIwO3V4sMOI6W6JeEHw.width-1600.png)

Replace the code in the Function with the following JavaScript:
```javascript
exports.handler = function(context, event, callback) {
    //Memory from the answered question
    const memory = JSON.parse(event.Memory);
    //get answers from Memory
    let name = memory.twilio.collected_data.call_collect.answers.name.answer; 
    let zipCode = memory.twilio.collected_data.call_collect.answers.zip_code.answer;
    
    const bodyCall = `Hello {{Supe}}. My name is ${name} and my zip code is ${zipCode}. Muni is a critical service to SF. Keep SF healthy, affordable, liveable, and accessible for all, including working families. The populations who ride Muni the most are the people our city is ALREADY failing to serve.`;
    
    const numbers = {
        'Aaron': '+14155547450',
        'Rafael': '+14155546968', 
        'Dean': '+14155547630',
        'Sandra': '+14155547410', 
        'Matt':'+14155547970', 
        'Gordon': '+14155547460', 
        'Hilary':'+14155545144',
        'Ahsha':'+14155546975',
        'Catherine': '+14155547752', 
        'Shamann': '+14155547670', 
        'Norman':'+14155546516'
    };
    const client = context.getTwilioClient();
    var ctr = 0;
    Object.keys(numbers).forEach(function(key) {
        console.log(key, numbers[key]);
        client.calls
        .create({
            machineDetection: 'Enable',
            url: `https://handler.twilio.com/twiml/EH19fc2a326d3871000810eb5495c2d861/?Supe=${key}&Name=${name}&Zip=${zipCode}`,
            to: numbers[key], 
            from: 'YOUR-TWILIO-NUMBER'
        }).then(function(call) {
            console.log(call.sid);
            ctr ++;
            console.log(ctr);
            if (ctr == Object.keys(numbers).length) {
                const resp = {
                    actions: [
                        {
                            say: "Thank you for calling all 11 reps of SF County Transit Authority. \n\n The call to them said: " + bodyCall + "\n\n You can also leave them a voicemail, sign this petition https://bit.ly/2ZNEfbv, spread the word to your friends, send more emails, and more. Want to get more involved? Fill out this form: https://forms.gle/FHqt7W62D9W2t164A"
                        }         
                    ]
                };
                callback(null, resp);
            }
        })
        .catch(err => {
            callback(err);
        });
    });
};
```
To make and customize your own civic engagement bot, you would replace the <code>bodyCall</code> with your own message to representatives about the local issue you want to change and then replace <code>numbers</code> to the phone numbers of the representatives you wish to call. Don't forget to include your name and precinct in the text!

First we access the memory to get the user's answers and save them as variables <code>name</code> and <code>zipCode</code>. <code>bodyCall</code> is a short transcript (of what the phone call will say to each representative) to be texted back to the user and <code>numbers</code> is an object containing the names of who to call and their corresponding phone numbers. We loop through that object and make an outbound call to each number with [answering machine detection (AMD) enabled](https://www.twilio.com/docs/voice/answering-machine-detection), passing it a URL to a [TwiML bin](https://www.twilio.com/console/twiml-bins) containing the following [TwiML](https://www.twilio.com/docs/glossary/what-is-twilio-markup-language-twiml):

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say voice="Polly.Joanna">Hello {{Supe}}. My name is {{Name}} and my zip code is {{Zip}}. Muni is a critical service to SF.  Keep SF healthy, affordable, liveable, and accessible for all, including working families.</Say>
</Response>
```
[You can read more on generating dynamic TwiML and templating with Twilio Bins here](https://support.twilio.com/hc/en-us/articles/230878368-How-to-use-templates-with-TwiML-Bins).

Once we reach the end of the object, go back in the Twilio Function to see that a text message is returned to the user confirming that each representative was called.
![sms example](https://twilio-cms-prod.s3.amazonaws.com/images/Screen_Shot_2020-07-20_at_12.22.10_PM.width-1600.png)

### Contacting Decision Makers with Twilio SendGrid and Twilio Functions
To contact decision makers on a different medium, we're going to go back to your bot in your [Autopilot console](https://www.twilio.com/console/autopilot/list) and add a new task called <code>Email</code>. On the same line as <code>Email</code>, click <em>Train</em> to add some samples that will trigger this task such as "email", "email reps", "email representatives", "email SFMTA", "send email", and similar phrases.

Then click <em>Switch to program task</em> near the top-right and add the following JSON that uses a similar Collect flow to the <code>Call</code> task:
```json
{
        "actions": [
                {
                        "collect": {
                                "name": "email_collect",
                                "questions": [
                                        {
                                                "question": "Let us email all 11 members of the San Francisco County Transportation Authority! What is your name?",
                                                "name": "name"
                                        },
                                        {
                                                "question": "What SF neighborhood do you live (or work)? If you need one, maybe try FiDi or Japantown.",
                                                "name": "live_work"
                                        },
                                        {
                                                "question": "What is your SF zip code? If you need one, use 94109.",
                                                "name": "zip_code"
                                        },
                                        {
                                                "question": "What are your demands? If you send `default` we will send one for you (ie. move funds from the police dept. to Muni.)",
                                                "name": "demands"
                                        },
                                        {
                                                "question": "Why is Muni important to you? How does it affect your day-to-day life? If you send `default` we will answer this for you (ie. `Muni is important to me and other San Franciscans because I take it to get to work, volunteer, see friends.`)",
                                                "name": "important_to_you"
                                        }
                                ],
                                "on_complete": {
                                        "redirect": {
                                                "method": "POST",
                                                "uri": "https://YOUR-TWILIO-FUNCTION.twil.io/muni_email"
                                        }
                                }
                        }
                }
        ]
}
```
The last two questions in the `Collect` flow above are more open-ended: the user can type out a longer response or they can send "default" for the chatbot to instead use a default response.

Grab your [SendGrid API key](https://app.sendgrid.com/settings/api_keys). In the [Twilio Functions Configuration section](https://www.twilio.com/console/runtime/functions/configure), save it as the environment variable <code>SENDGRID_API_KEY</code> like so:
![env variable](https://twilio-cms-prod.s3.amazonaws.com/images/Uo5N_eV259xNocOUG9b41rA0QCtR87JLhMLuJGIctV35K-.width-500.png)

Now it can be referenced with <code>context.SENDGRID_API_KEY</code> in any of your Twilio Functions.

Make another new Twilio Function that the <code>email</code> task will redirect to. Give it a name and path like this below, and don't forget to replace the Function path in your <code>email</code> task.
![email function path and name](https://twilio-cms-prod.s3.amazonaws.com/images/VL1EmeNV-aoxfEOjDxb0fp_B7LL0lk5jCF4quSZt72RkP.width-1000.png)

In your Function, replace the code with the following JavaScript:

```js
const sgMail = require('@sendgrid/mail');
exports.handler = function(context, event, callback) {
    sgMail.setApiKey(context.SENDGRID_API_KEY);
    //Memory from the answered question
    let memory = JSON.parse(event.Memory);
    //get answers from Memory
    let name = memory.twilio.collected_data.email_collect.answers.name.answer; 
    let liveWork = memory.twilio.collected_data.email_collect.answers.live_work.answer;
    let zipCode = memory.twilio.collected_data.email_collect.answers.zip_code.answer;
    let demands = memory.twilio.collected_data.email_collect.answers.demands.answer.toLowerCase();
    let important_to_you = memory.twilio.collected_data.email_collect.answers.important_to_you.answer.toLowerCase();
    
    if (demands === 'default') {
        demands = "We demand that Muni for Youth and the 40 Muni bus lines that are meant to be cut as a result of lack of funding are reinstated. It is routes like the 8, 9, 14, 29, etc.. that serve lower-income communities that are the most PACKED and clearly need MORE lines, not fewer.";
    }
    
    if (important_to_you == 'default') {
        important_to_you = "Every SFUSD student benefits from Muni. A progressive state does not let its most critical services fail. Muni is about accessibility and connecting people--connecting us to family, friends, and what makes SF special.";
    }
    const messages = [
        {
            to: 'Aaron.Peskin@sfgov.org', 
            from: `${name} <we_love_and_need_muni@sf.com>`,
            subject: '🍩Muni is a critical service to SF. 🍩',
            html: `Hi Aaron! Keep SF healthy, affordable, liveable, and accessible for all, including working families. <p>40% of emissions in SF come from transportation.</p><p>My name is ${name}, I live and work in ${liveWork}, and my zip code is ${zipCode}.${demands} ${important_to_you}</p> <p>Thank you for your time.</p>`,
        //...copy and paste this for each representative. Complete code https://github.com/elizabethsiegle/muni_call_email_representatives_chatbot/blob/master/email.mjs
        },
    ];
    sgMail.send(messages)
    .then(response => {
        const resp = {
            actions: [
            {
                say: "Thank you for emailing all 11 members of the SF County Transit Authority. You can also leave them a voicemail, sign this petition https://bit.ly/2ZNEfbv, spread the word to your friends, send more emails, and more. Want to get more involved? Fill out this form: https://forms.gle/FHqt7W62D9W2t164A. \n\n If you want to contact just one representative, try SF Transport Authority Chair/District 3 supervisor Aaron Peskin at (415) 554-7450 and Aaron.Peskin@sfgov.org or District 9 supervisor Hillary Ronen (also on the Metropolitan Transportation Commission) at (415) 554-5144 and RonenStaff@sfgov.org. You can also send more calls and emails by chatting with this bot."
            },
            {
                listen: true
            }
                ]
        };
        callback(null, resp);
    })
    .catch(err => {
      callback(err);
    });
};
```
This code imports SendGrid at the top, gets the answers to each question in the <code>email</code> task, and checks if the user sent "default" for the last two questions. If so, we send ready-made blurbs on why Muni is important and create an array called <code>messages</code> to send bulk emails with SendGrid. When each email is sent, the chatbot sends a confirmation message back to the user. [Check out this blog post for more information on sending bulk emails with SendGrid in Node.js](https://www.twilio.com/blog/sending-bulk-emails-3-ways-sendgrid-nodejs).

![email sms example](https://twilio-cms-prod.s3.amazonaws.com/images/77mofTHbVTJmCW99RqCf41PIlR4mISkSAHBJiIl_jNy37.width-1600.png)
You can test your chatbot in the Twilio console's Autopilot simulator, but now let's also hook up the bot to a Twilio phone number so your friends can text it!

### Configure your Bot with a Twilio Number
Go to the Autopilot console and select <em>Channels</em> from the left-hand menu. Click <em>Programmable Messaging</em>.
![channels](https://twilio-cms-prod.s3.amazonaws.com/images/e4YWOT_DlW7ja1KQ_IrvheNkDaeY-v-E51BkDApGs1SOn.width-1000.png)
Copy that Messaging URL and in a new tab configure your Twilio number in your [phone number console](https://www.twilio.com/console/phone-numbers/incoming).
![prog sms console](https://twilio-cms-prod.s3.amazonaws.com/images/M9JoUEuSyKNOPmnJGRJTuSHiDnHW6AERWWn8GljEcAnJR.width-1000.png)
If you don't have a Twilio number yet, go to the [Phone Numbers section](https://www.twilio.com/console/phone-numbers) of your [Twilio Console](https://www.twilio.com/console) and search for a phone number in your country and region, making sure the SMS checkbox is ticked.
![buy a number](https://twilio-cms-prod.s3.amazonaws.com/images/7NeAgVi9g7RjkbTzPOpnDKHapmRmGplouf74DTEUvWsYM.width-1000.png)
In the <em>Messaging</em> section of your purchased number, in the <em>A Message Comes In</em> section, set the <em>Webhook</em> to be your Messaging URL and hit <em>Save</em>.
![configure phone number in console](https://twilio-cms-prod.s3.amazonaws.com/images/pxaphQTevvjq3OAGmWoiQtoI4Yn7KhhtfzBFm2FH37veL.width-1000.png)
Now you can get out your phone, text the number, and share the number with people to contact San Francisco County Transportation Authority representatives, or whoever you would like to reach! [The complete code for this blog post and chatbot can be found here on GitHub](https://github.com/elizabethsiegle/muni_call_email_representatives_chatbot).

### What's Next for Civic-Minded Chatbots?
Twilio makes it easy to programmatically call, text, email, and generally communicate. You can make your chatbot more complex by adding other tasks to provide information such as:
- [resources on helping keep Muni funded](https://github.com/elizabethsiegle/muni_call_email_representatives_chatbot/blob/master/resources.json)
- facts or statistics on public transit
- an option to provide an email confirmation to the user (so they get emailed a copy of the email sent to representatives)
Of course, you can customize this code to whatever issues you are most passionate about. If you’re interested in using coding for social change, check out this interview with Sachin Medhekar who is [trying to help fight homelessness](https://www.twilio.com/blog/developers-doing-good-sachin-medhekar), [how to create successful advocacy campaigns](https://www.twilio.com/hub/change-how-design-advocacy-campaigns-scale-and-win), or see the work [Twilio.org](http://twilio.org/) is doing! 

Here's to hoping we can help keep mass transportation funded and better serve those who rely on it. Thanks for reading and let us know online or in the comments what you're building to make the world a better place!
- Twitter: [@lizziepika](https://twitter.com/lizziepika)
- GitHub: [elizabethsiegle](https://github.com/elizabethsiegle)
- Email: lsiegle@twilio.com