// Blog

Tracking my Boxes with Twilio and Clarify

Originally published on the Clarify.io blog. View archived copy.

Never ending piles of boxes...The last time I moved, it was horrible. After days of packing, hours of driving, and days of unpacking, it was impossible to remember what was where. We went days trying to find which box had that thing and in some cases, we gave up and bought a new one just to find it days later.

This move was going to be different.

Not only were we going to be better organized, but I decided to put a few tools to work. I knew that there would be two things that would not be misplaced no matter what: my phone and the dog. Since the dog didn’t volunteer to help, I opted to use the phone.

My Idea

My first idea was to simply use Twilio as a voice recorder, get the transcripts, and email the results so I’d have a list of everything in each box. That code was similar to the Voicemail Twimlet which seemed both too complex and too simple at the same time.

My second – and ultimately final – idea was to use my employer – Clarify – to take the voice recordings and make them searchable.

So meet MoveApp:

My flow was relatively simple:

  1. First, I label all my boxes 1, 2, 3…
  2. Then, I call my Twilio number
  3. It prompts me for the box number which I type in and press #
  4. Then as I packed things, I simply said what it is.

(Behind the scenes, Twilio sends the recording to Clarify which does its processing.)

  1. Whenever I’m looking for something, I can send MoveApp a text message and it responds with a box number. It doesn’t get much simpler.

Building MoveApp

From a technical point of view, this is what the process looks like:

MoveApp Workflow

This looks like a lot of moving parts, but there are only four scripts that matter. You can follow along from my Github repository but here are the details.

The first script – start.php – receives the incoming call and prompts the user for a box number:

	<div id="crayon-57fb4167ef5a3330649180" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-mixed-highlight" title="Contains Mixed Languages"></span><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">PHP</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

<?php require ‘config.php’; echo xml(); ?> <Response> <Gather action=”<?php echo $config[‘webroot’]; ?>gather.php” method=“GET”> <Say>Please enter the number of the box you are packing. When you are done, press pound. We will keep all recordings of each box number. </Say> </Gather> </Response>

1
2
3
4
5
6
7
8
9
10
11
<?php
require ‘config.php’;
echo xml();
?>
<Response>
  <Gather action=<?php echo $config[‘webroot’]; ?>gather.php” method=“GET”>
    <Say>Please enter the number of the box you are packing. When you are
         done, press pound. We will keep all recordings of each box number.
    </Say>
  </Gather>
</Response>

The second script – gather.php – receives the box number, starts the recording, and sets the action callback. The action callback is the most important part. This will make sure that once the recording is done on the Twilio side, the recording URL will be sent to the next script.

	<div id="crayon-57fb4167ef5ba809657106" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-mixed-highlight" title="Contains Mixed Languages"></span><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">PHP</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

<?php require ‘config.php’; $digit = (int)$_REQUEST[‘Digits’]; xml(); ?> <Response> <Say>Recording contents for box number <?php echo $digit; ?>. Press pound when you’re done.</Say> <Record timeout=“3600” finishOnKey=”#” action=”<?php echo $config[‘webroot’]; ?>save.php?d=<?php echo $digit; ?>”></Record> </Response>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
require ‘config.php’;
$digit = (int)$_REQUEST[‘Digits’];
xml();
?>
<Response>
  <Say>Recording contents for box number
  <?php echo $digit; ?>.
  Press pound when youre done.</Say>
  <Record
  timeout=“3600”
  finishOnKey=”#”
  action=<?php echo $config[‘webroot’]; ?>save.php?d=<?php echo $digit; ?>></Record>
</Response>

Note: By default, this will allow a recording of up to 3600 seconds (60 minutes) and only stop when you hang up or hit the # sign. Don’t forget to speak clearly!

The third script – save.php – catches the recording URL and the box number and submits it to Clarify for processing:

	<div id="crayon-57fb4167ef5c0561103462" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-mixed-highlight" title="Contains Mixed Languages"></span><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">PHP</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

<?php require ‘config.php’; $number = (int)$_GET[‘d’]; $url = $_POST[‘RecordingUrl’]; if (filter_var($url, FILTER_VALIDATE_URL) === false) { echo xml(); echo ‘&lt;Response&gt;&lt;Say&gt;Invalid URL.&lt;/Say&gt;&lt;/Response&gt;’; die(); } $clarify->saveBoxIDWithMedia($number, $url); echo xml(); ?> <Response> <Redirect method=“GET”><?php echo $config[‘webroot’] ?>start.php</Redirect> </Response>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require ‘config.php’;
$number = (int)$_GET[‘d’];
$url = $_POST[‘RecordingUrl’];
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
  echo xml();
  echo ‘&lt;Response&gt;&lt;Say&gt;Invalid URL.&lt;/Say&gt;&lt;/Response&gt;’;
  die();
}
$clarify->saveBoxIDWithMedia($number, $url);
echo xml();
?>
<Response>
  <Redirect method=“GET”><?php echo $config[‘webroot’] ?>start.php</Redirect>
</Response>

Note: Clarify will take roughly one minute of processing for every minute of audio. Since this only happens once, it’s not an issue.

The final script – search.php – receives the incoming text message, submits the search to Clarify, processes the results and responds with a simple text:

	<div id="crayon-57fb4167ef5c7035840460" class="crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate" data-settings=" minimize scroll-mouseover" style=" margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important;">
	
		<div class="crayon-toolbar" data-settings=" mouseover overlay hide delay" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-title"></span>
		<div class="crayon-tools" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"><span class="crayon-mixed-highlight" title="Contains Mixed Languages"></span><div class="crayon-button crayon-nums-button" title="Toggle Line Numbers"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-plain-button" title="Toggle Plain Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-wrap-button" title="Toggle Line Wrap"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-expand-button" title="Expand Code"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-copy-button" title="Copy"><div class="crayon-button-icon"></div></div><div class="crayon-button crayon-popup-button" title="Open Code In New Window"><div class="crayon-button-icon"></div></div><span class="crayon-language">PHP</span></div></div>
		<div class="crayon-info" style="min-height: 16.8px !important; line-height: 16.8px !important;"></div>
		<div class="crayon-plain-wrap"><textarea wrap="soft" class="crayon-plain print-no" data-settings="dblclick" readonly style="-moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4; font-size: 12px !important; line-height: 15px !important;">

<?php require ‘config.php’; $query = preg_replace(”/[^A-Za-z ]/”, "", $_REQUEST[‘Body’]); $names = $clarify->searchForBoxes($query); if (count($names) > 0) { $about = implode($names, ’, ’); } else { $about = ‘0 boxes’; } echo xml(); ?> <Response> <Message>We found ”<?php echo htmlspecialchars($query); ?>” in <?php echo htmlspecialchars($about); ?>. </Message> </Response>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require ‘config.php’;
$query = preg_replace(”/[^A-Za-z ]/”, "", $_REQUEST[‘Body’]);
$names = $clarify->searchForBoxes($query);
if (count($names) > 0) {
  $about = implode($names, ’, ’);
} else {
  $about = ‘0 boxes’;
}
echo xml();
?>
<Response>
  <Message>We found <?php echo htmlspecialchars($query); ?> in <?php echo htmlspecialchars($about); ?>.
</Message>
</Response>

The Results

Graham ChristensenI’m happy to say that I used this for my move last month. While there were still a lot of complexities with moving, the application worked flawlessly, and it turns out that I didn’t need to be that organized. After the move, finding everything was faster and easier than I could have imagined.

You can get and deploy all the code from my Github repository or just click the “Deploy to Heroku” button on that page, fill in your Clarify credentials, and then set your Twilio voice and SMS urls to point at the app. It will be the easiest part of your move.