<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nicolas Grenié</title>
    <description>The latest articles on DEV Community by Nicolas Grenié (@picsoung).</description>
    <link>https://dev.to/picsoung</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F40598%2Fd7ab6a68-94ab-43c2-9806-2d4d63f4dc87.jpeg</url>
      <title>DEV Community: Nicolas Grenié</title>
      <link>https://dev.to/picsoung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/picsoung"/>
    <language>en</language>
    <item>
      <title>Collect Addresses on Typeform using Algolia Places</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Wed, 06 May 2020 20:16:41 +0000</pubDate>
      <link>https://dev.to/typeform/collect-addresses-on-typeform-using-algolia-places-1jog</link>
      <guid>https://dev.to/typeform/collect-addresses-on-typeform-using-algolia-places-1jog</guid>
      <description>&lt;p&gt;During the last weeks as the world was getting under lockdown, many small businesses had to close doors and put their activities on hold. This was actually a new beginning for many business owners, as they were looking for opportunities to continue running their shops while respecting government measures and social distances.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://typeform.com"&gt;Typeform&lt;/a&gt; we've seen many initiatives to help digitalize small businesses, by providing for example interfaces to take online orders or do deliveries. From farmers in the mountains of Chamonix to a bakery in Barcelona, all stores were facing similar issues and were looking for simple solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://typeform.com"&gt;Typeform&lt;/a&gt; lets you create easily a visual "menu" where customers can pick what they want to buy. Typeform then calculates the price automatically and displays a credit card payment field using &lt;a href="https://stripe.com"&gt;Stripe&lt;/a&gt;. Overall it's a very seamless process until you reach the part where you have to ask your customer for their address and where you should deliver the goods.&lt;/p&gt;

&lt;p&gt;In most cases, it's done by asking a group of questions. Usually, you ask first the street, then the postcode and finally the city. But when it comes to addresses it's hard to be consistent as there are so many ways to write it. Especially right now when this typeform is shared with people that are not tech-savvy. This means business owners have to spend countless hours going manually to every single order a check if the address was correctly filled.&lt;/p&gt;

&lt;p&gt;Unfortunately, we currently don't have native support in Typeform's product for an autocomplete address field. But as a Developer Advocate, I don't take no for an answer!&lt;/p&gt;

&lt;p&gt;There has to be a better way! And this is where hacker spirit kicks in!&lt;/p&gt;

&lt;p&gt;Algolia has been maintaining since 2016 a library called Places, doing exactly what we need. It's based on data from OpenStreetMap, and do autosuggestion as you type.&lt;/p&gt;

&lt;p&gt;In this article, I will show you how you can connect it to your Typeform and collect accurate addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it live 📺
&lt;/h2&gt;

&lt;p&gt;If you want to get a preview of what we are about to build, check it out &lt;a href="https://tf-algolia-places.glitch.me"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the address of your choice, and you should be redirected to a typeform to order some good pizzas 🍕&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/XHvgQpf080vtTX2jf7/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/XHvgQpf080vtTX2jf7/giphy.gif" alt="demo typeform algolia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-requisites 🛒
&lt;/h3&gt;

&lt;p&gt;A Typeform account, create one for free &lt;a href="https://www.typeform.com/?utm_source=dev.to&amp;amp;utm_campaign=devrel_projects&amp;amp;utm_medium=referral&amp;amp;utm_content=tf-algolia-places"&gt;here&lt;/a&gt;&lt;br&gt;
An Algolia Places account, get one for free &lt;a href="https://www.algolia.com/users/sign_up/places"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Add Algolia Places to your project 📍
&lt;/h2&gt;

&lt;p&gt;The good thing about this hack? We don't need any server-side code!&lt;br&gt;
Everything could happen in a plain HTML page with a bit of Javascript.&lt;/p&gt;

&lt;p&gt;Let's start by loading the library on our page.&lt;br&gt;
Adds this at the bottom of just before &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/places.js@1.18.1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In our page, we then add an HTML element that will be the autocomplete field.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"address-input"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Where do you live?"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we have to initialize the library and connect it to this field.&lt;/p&gt;

&lt;p&gt;Add this snippet at the end of your page&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;placesAutocomplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#address-input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;YOUR_APP_ID&lt;/code&gt; and &lt;code&gt;YOUR_API_KEY&lt;/code&gt; by the values given in Algolia dashboard.&lt;/p&gt;

&lt;p&gt;💥You should now have a functioning autocomplete field. Open your HTML page and try it out.&lt;/p&gt;
&lt;h3&gt;
  
  
  Customize the library 🖌️
&lt;/h3&gt;

&lt;p&gt;Right now, our example auto-suggests addresses all over the world, but the library is very flexible. If you add &lt;code&gt;countries: ['us']&lt;/code&gt; for example it will only show addresses in the US.&lt;/p&gt;

&lt;p&gt;I recommend you to check the &lt;a href="https://community.algolia.com/places/documentation.html"&gt;documentation&lt;/a&gt; to customize it the way you want 😉&lt;/p&gt;
&lt;h3&gt;
  
  
  Listen to changes 👂
&lt;/h3&gt;

&lt;p&gt;What is happening when the user has selected their address? At the moment nothing, because we haven't coded this part.&lt;/p&gt;

&lt;p&gt;To do that we add an event listener to the &lt;code&gt;placesAutocomplete&lt;/code&gt; object we created earlier. The Algolia Places library has many events available, but we are only interested by the &lt;code&gt;change&lt;/code&gt; event. This event will be triggered every time the address selected changes.&lt;/p&gt;

&lt;p&gt;In your code add the following lines:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;placesAutocomplete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now you can restart your app, type an address, and select it. In your browser developer console, you now see the details of what's returned by the library.&lt;/p&gt;

&lt;p&gt;🤩 That's a lot of interesting data formatted exactly the way we need, but we may just need a subset of it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's prepare your typeform 👩‍🎨
&lt;/h2&gt;

&lt;p&gt;Now that you've seen the potential of this library, you may have a better understanding of which type of data you want to use in your typeform.&lt;/p&gt;

&lt;p&gt;For this example, we are going to pass &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;postcode&lt;/code&gt; and &lt;code&gt;country&lt;/code&gt; value only. To pass the data from our code to the typeform we are going to rely on &lt;a href="https://help.typeform.com/hc/en-us/articles/360029114712-How-to-use-Hidden-Fields"&gt;Hidden Fields&lt;/a&gt;. Hidden fields are a way to pass data to a typeform by adding query parameters to its URL.&lt;/p&gt;

&lt;p&gt;Your original typeform URL was:&lt;br&gt;
&lt;code&gt;https://picsoung.typeform.com/to/FWq00K&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It's now going to be &lt;code&gt;https://picsoung.typeform.com/to/FWq00K?address=xxxx&amp;amp;postcode=xxxx&amp;amp;country&amp;amp;city=xxxx&lt;/code&gt; where &lt;code&gt;xxxx&lt;/code&gt; is the value extracted thanks to Algolia Places.&lt;/p&gt;

&lt;p&gt;Let's now add hidden fields to your typeform. Click &lt;code&gt;+&lt;/code&gt; and select &lt;code&gt;hidden fields&lt;/code&gt;. Hidden fields are sitting at the top of your form and you can add as many as you want. Only the parameters declared as hidden fields will be passed to the results. You can also use hidden fields in the conditional logic, for example, to showcase that you don't do deliveries in certain postcodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/kHxIgm99KvBOn6s90e/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/kHxIgm99KvBOn6s90e/giphy.gif" alt="Add hidden fields to a typeform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure it works by opening the URL of your typeform with hidden fields values put manually. Once you've submitted the typeform, in the &lt;code&gt;Results&lt;/code&gt; panel you should see that the values have been passed and recorded correctly.&lt;/p&gt;
&lt;h2&gt;
  
  
  Link our code to the typeform 🔗
&lt;/h2&gt;

&lt;p&gt;Now that we have the two pieces working independently, let's connect them together!&lt;/p&gt;
&lt;h3&gt;
  
  
  Construct the URL of the form 🏗️
&lt;/h3&gt;

&lt;p&gt;As we saw we need to append query parameters to our Typeform URL.&lt;br&gt;
In our code, add this snippet and replace &lt;code&gt;YOUR_TYPEFORM_URL&lt;/code&gt; with your own typeform URL.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;typeformURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_TYPEFORM_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hidden_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hidden_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hidden_values&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hidden_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;completeURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;typeformURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hidden_query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We create a &lt;code&gt;hidden_values&lt;/code&gt; object with all the parameters we get from Algolia Places. &lt;br&gt;
We then turn this object into a string so it looks like &lt;code&gt;country=France&amp;amp;city=Paris...&lt;/code&gt; using a bit of ES6 magic to store it in &lt;code&gt;hidden_query&lt;/code&gt; variable.&lt;br&gt;
&lt;code&gt;completeURL&lt;/code&gt; is then the concatenation of our original URL and the hidden values.&lt;/p&gt;

&lt;p&gt;We now have two options, either we redirect the user to our typeform, or we embed it in our page.&lt;/p&gt;
&lt;h4&gt;
  
  
  Redirect ↪️
&lt;/h4&gt;

&lt;p&gt;Redirection is the easiest thing, just after the previous snippet add this line in your code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completeURL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that's it, you are now redirected to your form and location data are passed as hidden fields.&lt;/p&gt;
&lt;h4&gt;
  
  
  Embed 🖼️
&lt;/h4&gt;

&lt;p&gt;To embed your typeform in your page we will use our &lt;a href="https://github.com/typeform/embed"&gt;Embed SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let's add the Embed SDK at the bottom of your page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://embed.typeform.com/embed.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; of your HTML page you need to add an HTML element where the form will be embedded.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"typeform_embed"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"height: 900px;width: 100%;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Give it the size you want by modifying the &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; properties.&lt;/p&gt;

&lt;p&gt;Now we need to embed the typeform when we receive the &lt;code&gt;change&lt;/code&gt; event from the Algolia library.&lt;/p&gt;

&lt;p&gt;Just after the line &lt;code&gt;let completeURL ...&lt;/code&gt; add the following:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;embedElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#typeform_embed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;typeformEmbed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;makeWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;embedElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;completeURL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hideHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hideFooter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buttonText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Take the survey!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Typeform successfully submitted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This piece of code loads the typeform with all the parameters and place it in the object with id &lt;code&gt;typeform_embed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.typeform.com/embed/"&gt;Typeform's Embed SDK&lt;/a&gt; has a lot of features and you can personalize many things on the look and feel of the embed, we just went for the easiest path.&lt;/p&gt;

&lt;p&gt;Note, the &lt;code&gt;onSubmit&lt;/code&gt; function, this will be triggered when the form is submitted. This could be useful to hide the form after being submitted, for example.&lt;/p&gt;

&lt;p&gt;You should now have a typeform appearing on your page after selecting an address in the field. And if you change the address it will update the typeform URL and embed it again.&lt;/p&gt;
&lt;h2&gt;
  
  
  Going further 🚀
&lt;/h2&gt;

&lt;p&gt;With this hack, you are now collecting sanitized addresses from your customers when they are filling up a typeform. 🎉&lt;/p&gt;

&lt;p&gt;You can personalize the settings of the Algolia Places library to restrict to certain countries or to a different type of address. The library even supports searching for airports!&lt;/p&gt;

&lt;p&gt;You can also pass other types of data as hidden fields to your form. Like the latitude or longitude.&lt;/p&gt;

&lt;p&gt;With a bit of CSS you can modify the look and feel of the search box and make it your own.&lt;/p&gt;

&lt;p&gt;On Typeform you can now add some logic jumps to react differently depending on the locations data collected in the hidden fields.&lt;/p&gt;

&lt;p&gt;I hope you liked this hack and found it useful.&lt;br&gt;
Feel free to suggest some other ideas ;)&lt;/p&gt;

&lt;p&gt;The complete source code is available on &lt;a href="https://glitch.com/~tf-algolia-places"&gt;Glitch&lt;/a&gt;&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/tf-algolia-places?previewSize=0&amp;amp;path=index.html" alt="tf-algolia-places on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>typeform</category>
      <category>algolia</category>
    </item>
    <item>
      <title>Typeform Handler - Extract phone number and call user</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 30 Apr 2020 00:51:16 +0000</pubDate>
      <link>https://dev.to/picsoung/typeform-handler-extract-phone-number-and-call-user-9j4</link>
      <guid>https://dev.to/picsoung/typeform-handler-extract-phone-number-and-call-user-9j4</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Category Submission: Engaging Engagements
&lt;/h4&gt;

&lt;p&gt;A simple way to connect a typeform to Twilio, and call a user when the form is submitted.&lt;br&gt;
A simple example good candidate for a code exchange code sample.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Link
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://picsoung.typeform.com/to/VN616s"&gt;https://picsoung.typeform.com/to/VN616s&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://glitch.com/%7Etf-twilio"&gt;https://glitch.com/~tf-twilio&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I built it (what's the stack? did I run into issues or discover something new along the way?)
&lt;/h2&gt;

&lt;p&gt;Express app hosted on Glitch &lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources/Info
&lt;/h2&gt;

</description>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Tutorial: Hacking a robot while respecting fundamental laws of robotics</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Mon, 19 Aug 2019 18:43:45 +0000</pubDate>
      <link>https://dev.to/typeform/tutorial-hacking-a-robot-and-respecting-fundamental-laws-of-robotics-54c4</link>
      <guid>https://dev.to/typeform/tutorial-hacking-a-robot-and-respecting-fundamental-laws-of-robotics-54c4</guid>
      <description>&lt;p&gt;This past week I got invited to attend &lt;a href="https://signal.twilio.com" rel="noopener noreferrer"&gt;Twilio Signal&lt;/a&gt; conference in San Francisco as part of their Champions program.&lt;/p&gt;

&lt;p&gt;I had the chance to meet other awesome Champions at our Summit. You should all follow them, they are all doing amazing things in their communities all around the world. Find more about the Twilio Champions program &lt;a href="https://www.twilio.com/champions" rel="noopener noreferrer"&gt;over here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The conference itself was full of great announcements around the Twilio eco-system. I am mostly excited by &lt;a href="https://www.twilio.com/conversations" rel="noopener noreferrer"&gt;Conversations&lt;/a&gt;, as a way to connect many people uing different systems (SMS, WhatsApp, chat...) into the same conversation. The new &lt;a href="https://github.com/twilio/twilio-cli" rel="noopener noreferrer"&gt;Twilio CLI&lt;/a&gt; to do everything around Twilio directly in the terminal looks pretty awesome too.&lt;/p&gt;

&lt;p&gt;Another big announcement at Signal was version 3 of &lt;a href="https://www.twilio.com/quest" rel="noopener noreferrer"&gt;TwilioQuest&lt;/a&gt; available on Desktop. If you are not familiar with TwilioQuest, imagine a video game where you gain XP points by solving coding challenges.&lt;br&gt;
It's a fun way to learn about the Twilio world and programming in general.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fquest%2Fnext%2Fimg%2Fscreenshots%2Fexplore.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.twilio.com%2Fquest%2Fnext%2Fimg%2Fscreenshots%2Fexplore.png" alt="screenshot of TwilioQuest"&gt;&lt;/a&gt;&lt;/p&gt;
Screenshot of TwilioQuest



&lt;p&gt;The main character you interact within TwilioQuest, is named &lt;em&gt;Cedric&lt;/em&gt; and is a friendly robot that is guiding you through your quest against the &lt;em&gt;Legacy Systems&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The thing I did not realize: Cedric is real! He and his friends attended Signal too. They were so many roaming the expo floor and booths.&lt;/p&gt;

&lt;p&gt;There even was a special Signal mission on TwilioQuest to earn XPs if you were spending some time with the team of &lt;a href="https://mistyrobotics.com" rel="noopener noreferrer"&gt;Misty Robotics&lt;/a&gt; (parent company of the Misty robot, Cedric's robot family).&lt;/p&gt;

&lt;p&gt;And this exactly what I did! I went over to meet the Misty Robotics team to learn more about those friendly robots🤖&lt;/p&gt;

&lt;p&gt;The team was organizing Developers testing sessions, and inviting people to try their &lt;em&gt;Hello World&lt;/em&gt; tutorial to "hack" the robot.&lt;/p&gt;

&lt;p&gt;Misty is an incredible robot, among many things she has multiple sensors to move around your house without bumping into anything, a speaker to express herself, a screen to show some emotions, and a camera with face recognition capability. And all that is hackable through an SDK! 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpxgaixc6e8stohh53h3o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fpxgaixc6e8stohh53h3o.jpg" alt="Misty robot look"&gt;&lt;/a&gt;&lt;/p&gt;
Isn't she lovely?



&lt;p&gt;I had a lot of fun following the tutorial. I made Misty move, make her blink her light and even taught her to recognize me. At the end of the session, the team was handing out surveys to collect feedback. And as you may have already guessed it was a Typeform! 🤩&lt;/p&gt;

&lt;p&gt;Then I had no option... I had to connect Misty to Typeform.&lt;/p&gt;

&lt;p&gt;I wanted to make Misty react every time someone was filling up the survey.&lt;/p&gt;

&lt;p&gt;Here is how I managed to connect the two.&lt;/p&gt;
&lt;h1&gt;
  
  
  Overall principle 📖
&lt;/h1&gt;

&lt;p&gt;We rely on Typeform webhooks functionality to react immediately after someone answered.&lt;/p&gt;

&lt;p&gt;The webhook is received by an app that can call the Misty API and make the robot react.&lt;/p&gt;

&lt;p&gt;But to be able to communicate with the Misty robot, your app needs to be on the same WIFI network, so it's most likely that you will run it locally on your laptop.&lt;/p&gt;

&lt;p&gt;We will use &lt;a href="http://ngrok.io" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; to expose localhost to the world 🌍.&lt;/p&gt;
&lt;h1&gt;
  
  
  Make the Misty move her arm
&lt;/h1&gt;

&lt;p&gt;We create a small express app with only one endpoint in a file named &lt;code&gt;app.js&lt;/code&gt;. This endpoint will receive webhook notification and then call Misty API.&lt;/p&gt;

&lt;p&gt;This is how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// parse application/x-www-form-urlencoded&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;

&lt;span class="c1"&gt;// parse application/json&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.41.129.96&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;//change to your own&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/arms`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Velocity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;degrees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can run the app by using the command &lt;code&gt;node app.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And to make her arm go up, run the following command &lt;code&gt;curl -X POST https://localhost:300&lt;/code&gt; in your terminal. &lt;/p&gt;

&lt;p&gt;And if everything works well you should see Misty's left arm going up 🎉&lt;/p&gt;
&lt;h1&gt;
  
  
  Connect it to Typeform 🔗
&lt;/h1&gt;

&lt;p&gt;All this is working well locally, but wouldn't it be cool to connect it to other services?&lt;/p&gt;

&lt;p&gt;To make it happen we need the help of an awesome tool called &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;. ngrok will expose your localhost and make it available to rest of the internet by giving it a URL. This URL is unique to you and every time you launch ngrok. Make sure to read its &lt;a href="https://dashboard.ngrok.com/get-started" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have ngrok installed you can run the command &lt;code&gt;ngrok http 300&lt;/code&gt;.&lt;br&gt;
This should give you a URL back. We are going to use it to call our app from the outside.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUtnS6C0VFJKLTaOVZKDdJGkKcPch-HAy4B%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUtnS6C0VFJKLTaOVZKDdJGkKcPch-HAy4B%2Fimage.png" alt="Screenshot of ngrok"&gt;&lt;/a&gt;&lt;/p&gt;
Screenshot of ngrok



&lt;p&gt;On your Typeform dashboard, we can now select the form we want to connect to Misty, and under &lt;em&gt;Connect &amp;gt; Webhooks&lt;/em&gt; add a new webhook with this URL.&lt;/p&gt;

&lt;p&gt;And voilà 🎉&lt;br&gt;
You now have a robot that raises her arm every time someone fills up your typeform.&lt;/p&gt;

&lt;p&gt;This will work until you kill ngrok or the node app. Ngrok will give you a new URL every time you launch it, so just keep it open while you are developing.&lt;/p&gt;
&lt;h1&gt;
  
  
  Go beyond 🚀
&lt;/h1&gt;

&lt;p&gt;After seeing Misty raising her arm the first time, I could not restrain myself, and I shouted a loud "Woo-hoo" on the conference floor 😊.&lt;/p&gt;

&lt;p&gt;But I could not stop jus now when I was so close to building something even cooler.&lt;/p&gt;

&lt;p&gt;My ultimate goal was to build an app that will make Misty speak and react to the things that were posted on the typeform.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make her arm move dynamically 👋
&lt;/h2&gt;

&lt;p&gt;So I built a &lt;a href="https://picsoung.typeform.com/to/n6NnNI" rel="noopener noreferrer"&gt;simple typeform&lt;/a&gt;, where people could leave their name and decide which arm Misty should raise. &lt;/p&gt;

&lt;p&gt;To make it easier to extract data from typeform webhook payload, I had to update the &lt;code&gt;ref&lt;/code&gt; of my questions. On your typeform select the question and look at the bottom of the sidebar and click &lt;code&gt;Edit&lt;/code&gt;. There you can change it to whatever you please. I called mine &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;arm_choice&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd1nt04ao0vck22.cloudfront.net%2Fuploads%2F2015%2F07%2F09121737%2Fquestion-settings-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd1nt04ao0vck22.cloudfront.net%2Fuploads%2F2015%2F07%2F09121737%2Fquestion-settings-2.png" alt="screenshot typeform edit ref"&gt;&lt;/a&gt;&lt;/p&gt;
Edit Ref on typeform question



&lt;p&gt;Now let's see how to extract those values from the webhook payload 👇&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;arm_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arm_choice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;selected_arm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arm_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;username_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;username_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then you can pass &lt;code&gt;select_arm&lt;/code&gt; value to Misty API, and raise the corresponding arm.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/arms`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;Arm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;selected_arm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Velocity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;degrees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Maker her speak 🤖🗣️
&lt;/h2&gt;

&lt;p&gt;Misty REST API lets you send WAV audio files using the &lt;code&gt;SaveAudio&lt;/code&gt; endpoint (&lt;a href="https://docs.mistyrobotics.com/misty-ii/reference/rest/#saveaudio-data-string-" rel="noopener noreferrer"&gt;doc&lt;/a&gt;) but... they have to be encoded in base64 😤&lt;/p&gt;

&lt;p&gt;So I had to find a hack to generate a &lt;code&gt;.wav&lt;/code&gt; file and convert it to base64.&lt;/p&gt;

&lt;p&gt;It took me a couple of trials to find the perfect library to do it, but &lt;a href="https://github.com/Marak/say.js/" rel="noopener noreferrer"&gt;say.js&lt;/a&gt; saved my day!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;say&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;say&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;say&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Using those few lines, it creates a &lt;code&gt;.wav&lt;/code&gt; file named &lt;code&gt;hello_${username}.wave&lt;/code&gt; with a voice that says &lt;code&gt;Hello nicolas&lt;/code&gt; for example.&lt;br&gt;
Unfortunately, I could not find the name for the female voices on my mac, so we are stuck with Alex for now 🤷‍♂️&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cont&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wav&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WaveFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wav64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wav&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBase64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ROBOT_IP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/audio`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
      &lt;span class="na"&gt;FileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`hello_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.wav`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wav64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ImmediatelyApply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//make Misty play it right away&lt;/span&gt;
      &lt;span class="na"&gt;OverwriteExisting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And this 🔝 is how I read the file, convert it to base64 and call Misty API to make it play on the robot.&lt;/p&gt;

&lt;p&gt;And this how it finally looks 🤩&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1159195895646183424-934" src="https://platform.twitter.com/embed/Tweet.html?id=1159195895646183424"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1159195895646183424-934');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1159195895646183424&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The code for the entire app is available here👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Hope that got you excited to hack things around and play with Misty 🤖.&lt;br&gt;
Their crowdfunding campaign is over, but you can already &lt;a href="https://shop.mistyrobotics.com/" rel="noopener noreferrer"&gt;pre-order&lt;/a&gt; it.&lt;/p&gt;

&lt;p&gt;🙏 Special thanks to Twilio Champions team for inviting me to be part of this great adventure 😃 &lt;/p&gt;

</description>
      <category>robots</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Create a Salesforce lead from Typeform in less than half an hour</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 14 Mar 2019 19:56:42 +0000</pubDate>
      <link>https://dev.to/typeform/create-a-salesforce-a-lead-from-typeform-in-less-than-half-an-hour-lmg</link>
      <guid>https://dev.to/typeform/create-a-salesforce-a-lead-from-typeform-in-less-than-half-an-hour-lmg</guid>
      <description>&lt;p&gt;At Typeform, we love to use our product to run things. As you may have read in &lt;a href="https://www.typeform.com/blog/inside-story/21-ways-typeform-uses-typeforms/" rel="noopener noreferrer"&gt;a previous post&lt;/a&gt;, we use typeforms to rate our lunches every day, gather feedback about upcoming features, and even run our internal FIFA contest. There are so many ways to use Typeform :)&lt;/p&gt;

&lt;p&gt;We are also heavy Salesforce users: we use it to keep our partner program organized. Companies that are interested in integrating with Typeform contact us via this partner &lt;a href=""&gt;form&lt;/a&gt;, but then nothing happens. If we believe a lead could produce an interesting conversation, we have to create the lead &lt;em&gt;manually&lt;/em&gt; in Salesforce.&lt;/p&gt;

&lt;p&gt;I can hear developer folks out there saying, “There should be a better way!” 🤔&lt;/p&gt;

&lt;p&gt;You’re right! We should be able to enjoy both by using the engaging Typeform UI to collect data and the powerful Salesforce funnel to organize the data into leads.&lt;/p&gt;

&lt;p&gt;And this is what I’m going to explain here. I connected our typeform to our Salesforce organization and saved our team precious time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites 🛒
&lt;/h1&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://www.salesforce.com/" rel="noopener noreferrer"&gt;Salesforce&lt;/a&gt; organization&lt;/li&gt;
&lt;li&gt;A Typeform account--&lt;a href="https://www.typeform.com/" rel="noopener noreferrer"&gt;create one for free&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A half hour of free time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Buckle up and let's get started! 🛫&lt;/p&gt;

&lt;h1&gt;
  
  
  Principles 📖
&lt;/h1&gt;

&lt;p&gt;This hack relies on Typeform webhooks. You can attach one or more webhooks to a Typeform so that when a new response is submitted, you are notified at the URL of your choice.&lt;/p&gt;

&lt;p&gt;Webhooks happen in real time, so they allow you to react quickly and keep everything in sync.&lt;/p&gt;

&lt;p&gt;On the Salesforce side, we will rely on their &lt;a href="https://www.salesforce.com/products/guide/lead-gen/web-to-lead/" rel="noopener noreferrer"&gt;Web-to-Lead&lt;/a&gt; solution. It's a quick way to generate leads from a web form.&lt;/p&gt;

&lt;p&gt;To receive webhook details from Typeform and send them to Salesforce, we use &lt;a href="http://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;. &lt;a href="http://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt; is both an online IDE and a server. The app is deployed automatically, so there’s no need to worry about servers.&lt;/p&gt;

&lt;p&gt;You can also use other serverless solutions like &lt;a href="https://aws.amazon.com/lambda" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;, &lt;a href="https://cloud.google.com/functions/" rel="noopener noreferrer"&gt;Google Cloud functions&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/services/functions" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;, and &lt;a href="https://stdlib.com" rel="noopener noreferrer"&gt;Stdlib&lt;/a&gt;. Your choice! 😉&lt;/p&gt;

&lt;h1&gt;
  
  
  Implement the solution 👩‍💻
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Prepare the typeform
&lt;/h2&gt;

&lt;p&gt;Our typeform contains all of the questions we want to ask. Each question is identified by both an &lt;code&gt;id&lt;/code&gt; and a &lt;code&gt;ref&lt;/code&gt; property. Both are unique and automatically generated, but the &lt;code&gt;id&lt;/code&gt; value can't be changed. &lt;a href="https://gist.github.com/picsoung/1b2665b6083876c949bdf6fe09d1ed7d" rel="noopener noreferrer"&gt;Example of form definition&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACVug-zrn3ZNGJd2rtG7SxpwUtYs8_C-RXYB%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACVug-zrn3ZNGJd2rtG7SxpwUtYs8_C-RXYB%2Fimage.png" alt="details of field definition"&gt;&lt;/a&gt;&lt;/p&gt;
details of field definition



&lt;p&gt;We &lt;em&gt;can&lt;/em&gt; update the &lt;code&gt;ref&lt;/code&gt; values to make the code more readable. I’ll use the &lt;a href="https://tf-edit-ref.glitch.me" rel="noopener noreferrer"&gt;Typeform Edit Block Ref app&lt;/a&gt; to modify the &lt;code&gt;ref&lt;/code&gt; properties of fields in our typeform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACVnWFu2hplJMpEK3nRSwVGc0jPT0YDDZiIB%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACVnWFu2hplJMpEK3nRSwVGc0jPT0YDDZiIB%2Fimage.png" alt="screenshot of edit ref app"&gt;&lt;/a&gt;&lt;/p&gt;
screenshot of edit ref app



&lt;p&gt;Now the questions have &lt;code&gt;ref&lt;/code&gt; values like &lt;code&gt;first_name&lt;/code&gt;, &lt;code&gt;last_name&lt;/code&gt; instead of random characters. 👍&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUecZQAfoNOQrgagEGrSU5epgSh9qRG4BYB%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUecZQAfoNOQrgagEGrSU5epgSh9qRG4BYB%2Fimage.png" alt="After edit result"&gt;&lt;/a&gt;&lt;/p&gt;
Looks better, no? 😉



&lt;h2&gt;
  
  
  Get your Salesforce organization ID 🗄️
&lt;/h2&gt;

&lt;p&gt;To send leads to our Salesforce organization, I need to identify it by passing our &lt;code&gt;oid&lt;/code&gt; (organization ID) as a parameter. &lt;/p&gt;

&lt;p&gt;You can find the &lt;code&gt;OID&lt;/code&gt; in your Salesforce dashboard. Click on the ⚙️ icon, and you should find it under &lt;em&gt;Settings&lt;/em&gt; in the &lt;code&gt;Company Information&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUtchZh8oZF7pDNQ3Oa3guTw9_HdNisZRYB%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACUtchZh8oZF7pDNQ3Oa3guTw9_HdNisZRYB%2Fimage.png" alt="sc"&gt;&lt;/a&gt;&lt;/p&gt;
Where to find your Salesforce OID



&lt;p&gt;Keep the &lt;code&gt;OID&lt;/code&gt; handy! You will need it later. 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's code 🎉
&lt;/h3&gt;

&lt;p&gt;I knew you wanted to get to this part as soon as possible! So let's get our hands dirty. 😈&lt;/p&gt;

&lt;p&gt;As I said earlier, our function will extract details from the Typeform webhook payload and then call the Salesforce API to create a lead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// let's answer back quickly to typeform 👌&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;received from Typeform webhook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;form_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// build the lead object&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lead_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;last_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// salesforce debug mode&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As you can see in this snippet, you’ll create a &lt;code&gt;/hook&lt;/code&gt; route, excepting a &lt;code&gt;POST&lt;/code&gt; request. Then, you’ll process the incoming request and extract the relevant data to build the &lt;code&gt;lead_data&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For security reasons, don't store the &lt;code&gt;OID&lt;/code&gt; value directly in the code. Instead, store it as an environment variable.&lt;/p&gt;

&lt;p&gt;I also added a debug parameter so you can test it out without harming your real organization.&lt;/p&gt;

&lt;p&gt;The only thing left to do is to call the Salesforce Web-to-Lead API and create a lead.&lt;/p&gt;

&lt;p&gt;This is the missing piece to add:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lead_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;res&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;err&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's all you need to connect things together. 🎊&lt;/p&gt;
&lt;h1&gt;
  
  
  Try it live
&lt;/h1&gt;

&lt;p&gt;To quickly try this integration, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://glitch.com/~tf-webtolead" rel="noopener noreferrer"&gt;Remix the project&lt;/a&gt; on Glitch&lt;/li&gt;
&lt;li&gt;Add your own &lt;code&gt;OID&lt;/code&gt; to the &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Remove, add, or modify data extraction from the Typeform webhook payload in lines 21-28 in &lt;code&gt;server.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Show&lt;/code&gt; to see the URL of your project hosted on Glitch (and keep it for the next step)&lt;/li&gt;
&lt;li&gt;In Typeform, select your lead generation typeform and add your Glitch app URL under &lt;code&gt;Connect &amp;gt; Webhooks&lt;/code&gt; 
The URL format should be &lt;code&gt;https://{random_name}.glitch.me/hook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test by filling in and submitting your lead generation typeform--after you submit it, you should see a new lead in your Salesforce organization&lt;/li&gt;
&lt;li&gt;Celebrate! 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACXSHV_zi6VJp4bDmEO8MFpF6iSZjVyUTrQB%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.evernote.com%2Fl%2FACXSHV_zi6VJp4bDmEO8MFpF6iSZjVyUTrQB%2Fimage.png" alt="new lead in Salesforce"&gt;&lt;/a&gt;&lt;/p&gt;
Succesfully created a lead in Salesforce




&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/tf-webtolead?path=index.html" alt="tf-webtolead on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Go beyond 🗺️
&lt;/h1&gt;

&lt;p&gt;This is a simple hack to connect Typeform and Salesforce. To make it more complete, you can map more fields from your lead object to your typeform questions. It even works with custom Salesforce fields.&lt;/p&gt;

&lt;p&gt;If you are curious about connecting Typeform with other services, check out our &lt;a href="https://developer.typeform.com" rel="noopener noreferrer"&gt;developer documentation&lt;/a&gt; and build your own solution! 😉&lt;/p&gt;

&lt;p&gt;To stay updated about projects like this one, subscribe to our &lt;a href="https://developerplatform.typeform.com/to/DlIzNU" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>salesforce</category>
    </item>
    <item>
      <title>A whole new world to explore</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 07 Feb 2019 01:51:00 +0000</pubDate>
      <link>https://dev.to/typeform/a-whole-new-world-to-explore-590a</link>
      <guid>https://dev.to/typeform/a-whole-new-world-to-explore-590a</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Apr62nI63tWcvQNzo" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2Apr62nI63tWcvQNzo"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@serjosoza?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;sergio souza&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2018 the Typeform crew had the pleasure to meet some of you at conferences like Nordic APIs, or JS Heroes, or hackathons like HackUPC in Barcelona, or Hackference in Birmingham. It’s always great to meet users and partners at those events. You help us build the future of Typeform and its platform 🤩&lt;/p&gt;

&lt;p&gt;I can tell you that for 2019, from where we are we have a new fantastic point of view, the head full of ideas and no one to tell us no. A hundred thousand things to see and as many dazzling places we never knew we wanted to visit…&lt;/p&gt;

&lt;p&gt;The only thing that’s crystal clear is that now we are in a whole new world with you, our beloved Developer Community!&lt;/p&gt;

&lt;p&gt;So let’s get this year started, hop on this magic carpet ride together, and let’s check out our next destinations.&lt;/p&gt;

&lt;p&gt;We will begin our adventure by going to Boulder for a few events:&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸 BoulderJS meetup, Boulder
&lt;/h4&gt;

&lt;p&gt;20th February 2019&lt;/p&gt;

&lt;p&gt;For the first step of our Boulder trip, we will stop by BoulderJS meetup, meeting the local Javascript community.&lt;/p&gt;

&lt;p&gt;I will be sharing my experience building my first app using Vue.js, when I created &lt;a href="https://%F0%9F%8C%9A%F0%9F%8C%9E.ws" rel="noopener noreferrer"&gt;https://🌚🌞.ws&lt;/a&gt; to track events for the 2018 Solar Eclipse.&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/Boulder-JS/events/xmkdvmyzdbbc/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸WriteTheDocs Boulder
&lt;/h4&gt;

&lt;p&gt;21st February 2019&lt;/p&gt;

&lt;p&gt;WriteTheDoc is a global community of tech writers. Last year we participated in their sister events API the docs in Paris and London. It’s a great pleasure to be welcomed by the Boulder local group to exchange about documentation and Developer Experience best practices.&lt;/p&gt;

&lt;p&gt;I will be presenting about best practices on Developer Experience on Webhooks.&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/Write-the-Docs-Boulder-Denver/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸Typeform Office Hours
&lt;/h4&gt;

&lt;p&gt;While we will be in Boulder, we thought we wanted to meet our lovely users. That’s why we are organizing some Office Hours on Thursday 21st and Friday 22nd.&lt;br&gt;&lt;br&gt;
It’s your opportunity to come meet us and come with your questions about Typeform product.&lt;br&gt;&lt;br&gt;
We will be here to assist you, especially if you are interested to build things using our APIs.&lt;/p&gt;

&lt;p&gt;🎟 ️&lt;a href="https://developerplatform.typeform.com/to/azugOg" rel="noopener noreferrer"&gt;Signup here&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇺🇸HackCU, Boulder
&lt;/h4&gt;

&lt;p&gt;23–24th February&lt;/p&gt;

&lt;p&gt;We don’t sponsor a lot of student hackathons but when we do, but do it’s because we have a special connection with their team. We are delighted to visit Gerard Sans founder of HackUPC and now a master student at CU-Boulder and Shubha Sharma, our summer intern in senior year in the same university. They are part of the outstanding team organizing HackCU.&lt;/p&gt;

&lt;p&gt;Can’t wait to see what hackers will build!&lt;/p&gt;

&lt;h4&gt;
  
  
  🇪🇸API Meetup BCN, Barcelona
&lt;/h4&gt;

&lt;p&gt;28th February&lt;/p&gt;

&lt;p&gt;It now has been more than 10 years that Barcelona has been selected to be the &lt;em&gt;Mobile Capital of the World&lt;/em&gt; for a week every year. During a week more than 100 thousand people will come from all over the world to discuss the newest trends in technology.&lt;/p&gt;

&lt;p&gt;Taking the opportunity of all those folks coming to Barcelona, the local API meetup is hosting their annual MWC meetup and we are excited to host it in our HQ! Join us for a night of API nerding! 🤓&lt;/p&gt;

&lt;p&gt;🎟️ &lt;a href="https://www.meetup.com/API-Meetup-Barcelona/events/258461375/" rel="noopener noreferrer"&gt;Register&lt;/a&gt; (FREE)&lt;/p&gt;

&lt;h4&gt;
  
  
  🇪🇸Women Techmakers, Barcelona
&lt;/h4&gt;

&lt;p&gt;6th April&lt;/p&gt;

&lt;p&gt;You still have a bit of time to get ready, but we are beyond excited to be part of the second edition of the Women Techmarkers conference in Barcelona.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://womentechmakersbcn.github.io" rel="noopener noreferrer"&gt;Learn more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I really hope you have a chance to catch us at one of those events! Remember, if you are organizing a meetup, a conference, a hackathon or an AI-powered ostrich race, and you want someone from Typeform to show up, let us know by filling the &lt;a href="https://picsoung.typeform.com/to/QXS2h1?source=dev_to_eventsq1" rel="noopener noreferrer"&gt;this typeform&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>hackathons</category>
      <category>conference</category>
      <category>developeradvocacy</category>
      <category>barcelona</category>
    </item>
    <item>
      <title>Prevent duplicate entries on your forms using Serverless </title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Mon, 01 Oct 2018 07:21:01 +0000</pubDate>
      <link>https://dev.to/picsoung/prevent-duplicate-entries-on-your-forms-using-serverless--1cea</link>
      <guid>https://dev.to/picsoung/prevent-duplicate-entries-on-your-forms-using-serverless--1cea</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8IcxpJsH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AtQgn3k8gqNFRNmvk" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8IcxpJsH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AtQgn3k8gqNFRNmvk" alt=""&gt;&lt;/a&gt;“monkey looking at mirror” by &lt;a href="https://unsplash.com/@andremouton?utm_source=medium&amp;amp;utm_medium=referral"&gt;Andre Mouton&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s a recurring question from our customers: how to prevent people from answering a typeform twice?&lt;/p&gt;

&lt;p&gt;Until now, we were telling them to discard the duplicates when they were looking at results, but now we may have a stronger solution using our own APIs and a bit of Serverless logic.&lt;/p&gt;

&lt;p&gt;I may have a tendency to always try to solve problems using technology, so when my co-workers told me about this duplicate issue, I knew we could do something using our API.&lt;/p&gt;

&lt;p&gt;You can check a working prototype &lt;a href="https://picsoung.typeform.com/to/czF813"&gt;here&lt;/a&gt;. Try to answer once, and then try again, you should be blocked.&lt;/p&gt;

&lt;h3&gt;
  
  
  General principle 🗺
&lt;/h3&gt;

&lt;p&gt;For this example, we will prevent a user to fill again a typeform if their email address has already been associated to a previous response.&lt;/p&gt;

&lt;p&gt;We will use the native logic jump functionality. If the email is &lt;em&gt;"authorized"&lt;/em&gt; we will go to the next question, if not we will go to a statement block saying &lt;em&gt;"sorry, you already filled this form"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can manually add a list of email addresses, but we want to automate this, right? 😄&lt;/p&gt;

&lt;p&gt;For that automation we will use our webhooks. When a new response is submitted, it will trigger a webhook. The webhook will extract the email from the payload, create a new logic block, and update the logic on Typeform using our &lt;a href="https://developer.typeform.com/create/"&gt;Create API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a chart on how it will work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D3JEPfDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/909/1%2AK3jKvYQk7xxxa2k8JxIEWw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D3JEPfDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/909/1%2AK3jKvYQk7xxxa2k8JxIEWw.gif" alt=""&gt;&lt;/a&gt;A gif worths a thousand words&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare your typeform 💄
&lt;/h3&gt;

&lt;p&gt;First step of this tutorial is to prepare your typeform to make it work with our integration. If you don’t have yet an email block, add one to your form now like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--15N-IHvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A3_WPEzlwgEKitPgff-LUjw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--15N-IHvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A3_WPEzlwgEKitPgff-LUjw.gif" alt=""&gt;&lt;/a&gt;Drag and drop an email block into your form&lt;/p&gt;

&lt;p&gt;We also need to add a statement block. This is where we will redirect the user if they already filled the typeform, so come up with a nice message 😁&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add base of logic block ⚖️&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Now get into the logic panel, so you can add the logic base of our form. Select the email block, and add a new constraint that will redirect to the statement block if email is equal to &lt;em&gt;&lt;a href="mailto:test@test.com"&gt;test@test.com&lt;/a&gt;&lt;/em&gt; (you can delete it later). And in all other cases jump to your next question.&lt;/p&gt;

&lt;p&gt;On the statement block, add a logic to always redirect to the email block. This is how it should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bBCxUxvT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/472/1%2ApZwGCuF3C6t2MjuE9JZdsA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bBCxUxvT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/472/1%2ApZwGCuF3C6t2MjuE9JZdsA.png" alt=""&gt;&lt;/a&gt;Logic map for our form&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test it 🏄‍&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To make sure the logic works, let’s test it! Go fill your form and use &lt;em&gt;&lt;a href="mailto:test@test.com"&gt;test@test.com&lt;/a&gt;&lt;/em&gt; in the email block, you should be redirected to the statement block and then back again to the email block.&lt;/p&gt;

&lt;p&gt;Does it work? Time to automate it 😜&lt;/p&gt;
&lt;h3&gt;
  
  
  A bit of code 🤓
&lt;/h3&gt;

&lt;p&gt;We now want to add a small piece of code that will automatically add a new rule in our logic every time someone answers a form for the first time.&lt;/p&gt;

&lt;p&gt;To make ease development and deployment we will use AWS Lambda and Serverless Framework, so please make sure you have both have &lt;a href="https://aws.amazon.com/cli/"&gt;AWS CLI&lt;/a&gt; configured and &lt;a href="http://serverless.com/"&gt;Serverless&lt;/a&gt; framework installed before going further.&lt;/p&gt;

&lt;p&gt;Then, clone our repo locally on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/picsoung/tf-lambda-limit-one-entry.git
cd tf-lambda-limit-one-entry
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the folder you will find a serverless.yml file that contains configuration instruction for our function.&lt;/p&gt;

&lt;p&gt;If you open it, you will see a few placeholders for some environnement variables we will need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;functions:
  addLimitLogic:
    handler: handler.addLimitLogic
    environment:
      FORM_ID: '' # Which form you want to update
      FIELD_ID: '' # Which field
      FIELD_REF: ''
      ALREADY_FILLED_FIELD_REF: ''
      TF_TOKEN: '' #Typeform API token
    events:
      - http: POST addLimitLogic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Get TF_TOKEN value 🔑
&lt;/h4&gt;

&lt;p&gt;You will need to create a Personal API Token for your account.&lt;br&gt;&lt;br&gt;
On Typeform, go to &lt;em&gt;My Account &amp;gt; Personnal Tokens.&lt;/em&gt; &lt;br&gt;
Create a new token and copy its value in the &lt;code&gt;serverles.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;h4&gt;
  
  
  Get FORM_ID value 📃
&lt;/h4&gt;

&lt;p&gt;Your can find the vale of FORM_ID by looking at the public URL of your typeform.&lt;br&gt;
It should be of the form &lt;code&gt;https://{username}.typeform.com/to/{form_id}&lt;/code&gt;.&lt;br&gt;
Copy &lt;code&gt;form_id&lt;/code&gt; to the &lt;code&gt;serverless.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;h4&gt;
  
  
  Get FIELD_ID, FIELD_REF and ALREADY_FILLED_FIELD_REF value 📃
&lt;/h4&gt;

&lt;p&gt;To get the remaining values, we will make a call in the browser to the following URL: &lt;a href="https://api.typeform.com/forms/%7Bform_id%7D"&gt;https://api.typeform.com/forms/{form_id}&lt;/a&gt; (replace &lt;code&gt;form_id&lt;/code&gt; by the value you found earlier).&lt;/p&gt;

&lt;p&gt;You should see a JSON file, this is the definition of your typeform, it has all the fields and logic described in a scripted manner.&lt;/p&gt;

&lt;p&gt;From this JSON file we will extract the values we are interested in.&lt;br&gt;&lt;br&gt;
&lt;code&gt;FIELD_ID&lt;/code&gt; and &lt;code&gt;FIELD_REF&lt;/code&gt; correspond to the &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;ref&lt;/code&gt; properties of the email block. &lt;/p&gt;

&lt;p&gt;Find the email block and copy values. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALREADY_FILLED_FIELD_REF&lt;/code&gt; corresponds to the &lt;code&gt;ref&lt;/code&gt; property of the statement block. Find the statement block and copy it’s ref value.&lt;/p&gt;

&lt;p&gt;All the environment variables in &lt;code&gt;serverless.yml&lt;/code&gt; should now have a value.&lt;br&gt;&lt;br&gt;
We are ready to deploy this function to the cloud.&lt;/p&gt;
&lt;h4&gt;
  
  
  Deploy Serverless function ⏫
&lt;/h4&gt;

&lt;p&gt;Go back to your terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sls deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run a bunch of scripts and at the end it should give your a URL from AWS, in the form of &lt;code&gt;https://{something}.execute-api.{aws_region}.amazonaws.com/{env}/addLimitLogic&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Copy this URL.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add Webhook to our form 🔗
&lt;/h4&gt;

&lt;p&gt;This are the final steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the URL we created at the previous as a webhook to our form.&lt;/li&gt;
&lt;li&gt;On your Typeform dashboard, go to the &lt;em&gt;Integrate&lt;/em&gt; tab of form and select &lt;em&gt;Webhooks.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;There, paste the URL and turn on the toggle. The bubble next to Webhooks should now be green.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BOOM! You now have a Typeform connected to a webhook that will add logic blocks automatically!&lt;/p&gt;

&lt;h3&gt;
  
  
  Rejoice! 😍
&lt;/h3&gt;

&lt;p&gt;Now that everything is setup, let’s try if our integration is working properly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fill your form for the first time using an email address.&lt;/li&gt;
&lt;li&gt;Once is submitted, go to your Typeform Create interface and check the Logic panel. You should see a new rule.&lt;/li&gt;
&lt;li&gt;Try to fill the form again using the same email address, you should now see the message you defined earlier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your form is now protected against duplicate entries based on email address!&lt;/p&gt;

&lt;h3&gt;
  
  
  Going further 🚀
&lt;/h3&gt;

&lt;p&gt;I just wanted to show a simple example so you all have a base to come up with more complex use cases. There are many other things that could be done.&lt;/p&gt;

&lt;p&gt;For this example we used email as an unique identifier but, as you may have guessed. it’s easy to find a workaround to fill the form twice. Instead, you can probably use a random id, and pass it as a &lt;code&gt;hidden_field&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Keep in mind that if you use it with email restriction, the limitation will only work after you put it in place. If you want to limit people who already filled the form, it might worth writing a script to extract email from previous responses and create corresponding logic block.&lt;/p&gt;

&lt;p&gt;I hope you liked this tutorial, please let me know if anything is broken or unclear, and feel free to suggest ideas for next projects!&lt;/p&gt;

&lt;p&gt;Happy Hacking \m/&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.typeform.com/?utm_source=dev.to&amp;amp;utm_medium=engineering-blog-article&amp;amp;utm_campaign=engineering-blog-links"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z1idAeA8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Ac3pyvOdjIvMwidwBGIbhMw.png" alt="🎵 Sweet dreams are made by geeks, who are we to ditch a PR? We travel to events and assorted meetups. Everybody is looking for swag."&gt;&lt;/a&gt;🎵 Sweet dreams are made by geeks, who are we to ditch a PR? We travel to events and assorted meetups. Everybody is looking for swag.&lt;/p&gt;




</description>
      <category>api</category>
      <category>aws</category>
      <category>typeform</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Get better at programming by helping others on Glitch</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Wed, 08 Nov 2017 21:31:52 +0000</pubDate>
      <link>https://dev.to/picsoung/get-better-at-programming-by-helping-others-on-glitch-1b4</link>
      <guid>https://dev.to/picsoung/get-better-at-programming-by-helping-others-on-glitch-1b4</guid>
      <description>&lt;p&gt;I started to learn programming about 15 years ago. In a time without Github and very limited resources to learn. A lot of my early learnings were made through imitation of existing websites. I would check their source code, copy-paste parts of it on mine and try to understand what it was doing by modifying it.&lt;/p&gt;

&lt;p&gt;After few years of practice, I had enough basic knowledge to help other beginners with their questions on bulletin boards. This was a great way to give back to the community that welcomed me when I began. I really enjoyed it because I got to put myself in someone else's shoes, understanding their issues and walk them through a solution. This teaches you pedagogy and empathy while you are re-enforcing your coding knowledge.&lt;br&gt;
&lt;em&gt;Now that I think about it, those early days were probably the foundation of my Developer Advocate career ðŸ˜‡&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Contribute and give back ðŸ¤ ðŸ¤—
&lt;/h2&gt;

&lt;p&gt;When you just started to learn a technology it could be really intimidating to give back to the community. It's not easy to submit your first Pull Request on Github. Or answer your first question on Stack Overflow. People have created initiatives like &lt;a href="https://twitter.com/yourfirstpr" rel="noopener noreferrer"&gt;YourFirstPR&lt;/a&gt; or &lt;a href="https://hacktoberfest.digitalocean.com" rel="noopener noreferrer"&gt;Hacktoberfest&lt;/a&gt; to lower the barrier to entry and make PR less scary.&lt;/p&gt;

&lt;p&gt;I feel that contributing and giving back got a lot easier with tools like &lt;a href="https://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;.&lt;br&gt;
I already mentioned Glitch in previous &lt;a href="https://hackernoon.com/is-glitch-developer-advocates-best-friend-b91af5b57656" rel="noopener noreferrer"&gt;posts&lt;/a&gt;, especially from the Developer Advocate perspective.&lt;br&gt;
With the &lt;em&gt;remix&lt;/em&gt; feature, you can clone a project and add your own sauce to it.&lt;br&gt;
If you ever get stuck you can ask the community for help with the &lt;em&gt;Help&lt;/em&gt; button.&lt;/p&gt;

&lt;p&gt;If you are interested to help others, you can check often the Glitch homepage and see if people need help. You can join people's project, offer help and start directing them to find a solution. At the end, they will thank you with a ðŸ’– on your profile.&lt;/p&gt;

&lt;p&gt;But questions are still rare, and popup at random times, so you might not satisfy your desires of community collaboration.&lt;/p&gt;

&lt;p&gt;I wanted to get more involved so I created a small tool to be notified whenever someone asks a question. &lt;/p&gt;

&lt;p&gt;Meet: &lt;a href="https://glitch-notifier.glitch.me/" rel="noopener noreferrer"&gt;Glitch Notifier&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://glitch-notifier.glitch.me/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.glitch.com%2F66902a08-bff3-43c7-9cc0-a044b858c5d5%252Fglitch_notifier_logo.png%3F1510099469712" alt="Glitch Notifier logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am a heavy user of Slack, so naturally, I wanted to get notified directly on Slack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feer5ant6bz2rnsrjwvmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feer5ant6bz2rnsrjwvmy.png" alt="example of post on slack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://glitch-notifier.glitch.me/" rel="noopener noreferrer"&gt;Glitch Notifier&lt;/a&gt; is open for the community to use. You log in with Slack, you choose the tags you want to follow, and add the Notifier app to your Slack team. You will then receive notification any time a question matches your criteria.&lt;/p&gt;

&lt;p&gt;You can contribute to the project by &lt;a href="https://glitch.com/~glitch-notifier" rel="noopener noreferrer"&gt;remixing&lt;/a&gt; it.&lt;/p&gt;

&lt;p&gt;I've been testing this tool for a few weeks now. I helped about 10 people and received ðŸ’– 8 times. There were about 100 questions asked in a month, on a variety of topics. I remember helping someone set up their environment variables or someone building a chatbot in Messenger...&lt;/p&gt;

&lt;p&gt;No matter your experience or your skillset, you are able to help someone in the community!&lt;/p&gt;

&lt;p&gt;If you are interested to learn how it was built, keep reading ðŸ˜‰&lt;/p&gt;
&lt;h2&gt;
  
  
  How is it built? ðŸ’»ðŸ›
&lt;/h2&gt;

&lt;p&gt;Like in the old days, looking at page's source gives you a lot of information. That's how I found out that Glitch has an undocumented API.&lt;/p&gt;

&lt;p&gt;So far I've found 3 endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET &lt;a href="https://api.glitch.com/projects" rel="noopener noreferrer"&gt;https://api.glitch.com/projects&lt;/a&gt; list projects&lt;/li&gt;
&lt;li&gt;GET &lt;a href="https://api.glitch.com/users" rel="noopener noreferrer"&gt;https://api.glitch.com/users&lt;/a&gt; list users&lt;/li&gt;
&lt;li&gt;GET &lt;a href="https://api.glitch.com/projects/questions" rel="noopener noreferrer"&gt;https://api.glitch.com/projects/questions&lt;/a&gt; list current open questions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last endpoint is the one we are interested in. It returns an array of questions or an empty array when no question is asked.&lt;/p&gt;

&lt;p&gt;To check periodically (every minute) on this endpoint to see if there are open questions, I have set up a small Lambda function (&lt;a href="https://github.com/picsoung/lambda-glitch-monitoring" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;) using &lt;a href="https://serverless.com" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If there are questions, I send them to a specific endpoint (&lt;code&gt;/questions/hook&lt;/code&gt;) on our Glitch app.&lt;/p&gt;

&lt;p&gt;There, we will check if we already have the question in our database. We use &lt;a href="https://faunadb.com" rel="noopener noreferrer"&gt;FaunaDB&lt;/a&gt;, as our cloud database. &lt;/p&gt;

&lt;p&gt;If the question is not yet in our database we should notify our users.&lt;/p&gt;

&lt;p&gt;Doing a Map request on our database we find which users are following the question's tags, and we notify them on Slack.&lt;/p&gt;

&lt;p&gt;Here is the corresponding code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;notifyPeople&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;users_in_db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_by_tag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="p"&gt;}))));&lt;/span&gt;


    &lt;span class="nx"&gt;users_in_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="c1"&gt;// request match results&lt;/span&gt;
       &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;usersRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
       &lt;span class="nx"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userRef&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
         &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userRef&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
         &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
           &lt;span class="nx"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendQuestionToSlack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;incoming_webhook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="c1"&gt;// does not exist&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;err&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To notify people on Slack we use an incoming webhook integration, with a bit of formatting so it looks nicer.&lt;/p&gt;

&lt;p&gt;Result in a Slack channel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feer5ant6bz2rnsrjwvmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feer5ant6bz2rnsrjwvmy.png" alt="example of post on slack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you like it, let me know if you have any question or comment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@cikstefan" rel="noopener noreferrer"&gt;Å tefan Å tefanÄÃ­k&lt;/a&gt; on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>devrel</category>
      <category>javascript</category>
      <category>serverless</category>
    </item>
    <item>
      <title>How to Monitor Stack Overflow Activity in Slack</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 10 Aug 2017 16:01:01 +0000</pubDate>
      <link>https://dev.to/picsoung/how-to-monitor-stack-overflow-activity-in-slack-bmi</link>
      <guid>https://dev.to/picsoung/how-to-monitor-stack-overflow-activity-in-slack-bmi</guid>
      <description>&lt;h4&gt;
  
  
  Powered by a complete serverless stack
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AtWzWtTvWgglmNujgAREraA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AtWzWtTvWgglmNujgAREraA.jpeg"&gt;&lt;/a&gt;Group of Developer Advocates watching developers coding — Credits: &lt;a href="https://pixabay.com/en/meerkat-snout-baby-mammal-guard-275967/" rel="noopener noreferrer"&gt;Pixabay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developer Advocates or Evangelists are often asked how they measure success.&lt;/p&gt;

&lt;p&gt;One could argue that GitHub ⭐️’s on repositories are great. And Ash Hathaway shares her thoughts &lt;a href="https://medium.com/@ash_hathaway/developer-evangelism-and-github-metrics-7e1c0a9d2fe2" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Others could say that Stack Overflow questions give a good sense of an API popularity. I would agree with this statement.&lt;/p&gt;

&lt;p&gt;If you don’t have a forum for your product, developers may end up asking questions directly on Stack Overflow.&lt;/p&gt;

&lt;p&gt;I would not encourage companies to redirect all their support questions there or pushing for their brand tags, this is just bad. You are hijacking a community for your own needs instead of contributing to it.&lt;/p&gt;

&lt;h4&gt;
  
  
  But :
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;What happens when someone is posting a question there?&lt;br&gt;&lt;br&gt;
How do you get notified?&lt;br&gt;&lt;br&gt;
How can you react quickly?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my experience, you can only receive notifications when there are new questions on a particular tag. This might not cover all the questions posted about your API.&lt;/p&gt;

&lt;p&gt;You can also use tools like &lt;a href="http://mention.net/" rel="noopener noreferrer"&gt;Mention&lt;/a&gt;. It covers more than Stack Overflow, but it’s not instantaneous.&lt;/p&gt;

&lt;p&gt;To be more reactive, I hacked together something for our team at &lt;a href="http://3scale.net/" rel="noopener noreferrer"&gt;3scale&lt;/a&gt; a long time ago. I recently rewrote it using serverless technologies. It monitors questions about &lt;strong&gt;3scale&lt;/strong&gt; and posts them on our &lt;strong&gt;#support&lt;/strong&gt; Slack channel. The support team can jump on it and answer quickly.&lt;/p&gt;

&lt;p&gt;I want to share this project, so you too can monitor Stack Overflow directly in Slack.&lt;/p&gt;
&lt;h3&gt;
  
  
  The tools
&lt;/h3&gt;

&lt;p&gt;To fit in 2017 trend, we will only use serverless technologies, which will make this tool free to use:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; to host the logic of our app
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://faunadb.com" rel="noopener noreferrer"&gt;FaunaDB&lt;/a&gt; to store databases
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://serverless.com" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt; to simplify deployments
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://slack.com" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; to be notified when a new question is asked&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The logic
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://api.stackexchange.com/docs" rel="noopener noreferrer"&gt;Stack Exchange API&lt;/a&gt; has an endpoint to search for questions. You can look for a term in tags, in the title, in the body of the question or all at the same time. We will search for all the attributes.&lt;/p&gt;

&lt;p&gt;Create a key to access Stack Exchange API &lt;a href="https://stackapps.com/apps/oauth/register" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our function will regularly call this endpoint to check if there are new questions posted. We will use the Schedule Events feature offered natively by Lambda.&lt;/p&gt;

&lt;p&gt;We will store the questions in a database to keep track of the ones we already sent to Slack and avoid duplicates.&lt;/p&gt;

&lt;p&gt;If a Stack Overflow question is not in our database, we add it to the database and send details to Slack.&lt;/p&gt;
&lt;h3&gt;
  
  
  FaunaDB
&lt;/h3&gt;

&lt;p&gt;I discovered &lt;a href="http://faunadb.com" rel="noopener noreferrer"&gt;FaunaDB&lt;/a&gt; a few months ago at &lt;a href="http://gluecon.com" rel="noopener noreferrer"&gt;Gluecon&lt;/a&gt;. They present themselves as the first &lt;strong&gt;serverless&lt;/strong&gt; database engine. Everything is hosted on their end. FaunaDB is a globally distributed database that doesn’t require any provisioning. Capacity is metered and available on demand, so you only pay for what you use.&lt;/p&gt;

&lt;p&gt;If you are familiar with &lt;a href="http://firebase.com" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;, you will recognize a similar data structure and routes to access resources. But it comes with more features, which makes it easier for example to query the database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0pxmiU6sfl1i-Zi3Z39LEw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0pxmiU6sfl1i-Zi3Z39LEw.png"&gt;&lt;/a&gt;Example: How to create an entry in FaunaDB&lt;/p&gt;

&lt;p&gt;For this app, you will need a database, with a &lt;strong&gt;questions&lt;/strong&gt; class. We will also add an index &lt;strong&gt;questions_by_id&lt;/strong&gt; on terms &lt;strong&gt;data&lt;/strong&gt; and &lt;strong&gt;question_id.&lt;/strong&gt; This will let us query the questions class by the Stack Overflow id.&lt;/p&gt;

&lt;p&gt;If you are concerned about your database usage, you can add TTL to the &lt;strong&gt;questions&lt;/strong&gt; class. This will automatically delete instances older than the TTL value.&lt;/p&gt;

&lt;p&gt;Finally, you will need to create a server key for the questions class. This key will be used to authenticate our function to FaunaDB servers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A5qAmmrJkz9vsu3veKnkJoQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A5qAmmrJkz9vsu3veKnkJoQ.png"&gt;&lt;/a&gt;Example: How to retrieve an entry in FaunaDB&lt;/p&gt;
&lt;h3&gt;
  
  
  Slack
&lt;/h3&gt;

&lt;p&gt;To post to Slack, we would just need a simple incoming web hook. Create one &lt;a href="https://my.slack.com/services/new/incoming-webhook/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure the project
&lt;/h3&gt;

&lt;p&gt;Make sure you have installed &lt;a href="http://serverless.com" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt; framework and configured the &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; tool.&lt;/p&gt;

&lt;p&gt;You can now clone this project locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:picsoung/stackOverflowMonitor.git
cd stackOverflowMonitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In serverless.ymlyou will modify the environment variables to your own values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FAUNADB_SECRET&lt;/code&gt; is the secret we created earlier to access FaunaDB
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;STACK_EXCHANGE_KEY&lt;/code&gt; is the API key to access Stack Exchange API
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SLACK_WEBHOOK_URL&lt;/code&gt; is the URL of the Slack incoming webhook you’ve created
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SLACK_CHANNEL&lt;/code&gt; should be an existing channel name in your Slack team such as #support or #stackoverflow
SEARCH_KEYWORD is the keyword you are interested in monitoring such as Node.js or Angular2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have changed all the variables to your own values, we can test if everything works. We invoke the function locally with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serverless invoke local — function getStackOverflowQuestions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it’s the first time you are launching the function, it should post a message to your Slack channel. It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AgWayFFnCGTPnj8YgfqQlJA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AgWayFFnCGTPnj8YgfqQlJA.png"&gt;&lt;/a&gt;How the notification should look like in your Slack channel&lt;/p&gt;

&lt;p&gt;If you are happy with the result you can now deploy the function with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serverless deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the function is called every 20 minutes. You can customize it by changing the schedule property in serverless.yml file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extend the project
&lt;/h3&gt;

&lt;p&gt;For now, we are only monitoring for one term. You can launch multiple instances of this function to watch more terms or tags on Stack Overflow.&lt;/p&gt;

&lt;p&gt;If you are interested in near to real-time solution, I encourage you to check &lt;a href="http://streamdata.io/" rel="noopener noreferrer"&gt;Streamdata.io&lt;/a&gt;. Their tools turn pulling API into streaming API.&lt;/p&gt;

&lt;p&gt;If you want some nice dashboards that show how active your community is on Stack Overflow, I recommend &lt;a href="http://keen.io/" rel="noopener noreferrer"&gt;Keen.io&lt;/a&gt;. You can send all your Stack Overflow data there. Keen offers a &lt;a href="https://keen.github.io/dashboards/" rel="noopener noreferrer"&gt;variety of libraries&lt;/a&gt; to build beautiful dashboards.&lt;/p&gt;

&lt;p&gt;We can also add more features in Slack, like buttons or menus. So people can claim a question or get assigned a question to answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This was a small project that led me to discover how to use FaunaDB. Using AWS Lambda it’s way more efficient that the Heroku instance that I had in the past.&lt;/p&gt;

&lt;p&gt;I hope you’ve found this serverless example useful. The code is &lt;a href="https://github.com/picsoung/stackoverflowmonitor" rel="noopener noreferrer"&gt;open&lt;/a&gt; on GitHub so feel free to contribute and add new features.&lt;/p&gt;

&lt;p&gt;If you are working for a company that is selling to developers I am sure you already heard the “Be where the developers are.”&lt;/p&gt;

&lt;p&gt;In the online world you have a good chance to find developers on websites like Hackers News, Stack Overflow, or GitHub. It’s important to measure what people say about your product or technologies on those sites.&lt;/p&gt;

&lt;p&gt;This was a small project that led me to discover how to use FaunaDB. Using AWS Lambda is way more efficient than the Heroku instance that I had in the past.&lt;/p&gt;

&lt;p&gt;I hope you’ve found this serverless example useful. The code is &lt;a href="https://github.com/picsoung/stackoverflowmonitor" rel="noopener noreferrer"&gt;open&lt;/a&gt; on GitHub so feel free to contribute and add new features.&lt;/p&gt;




</description>
      <category>startup</category>
      <category>technology</category>
      <category>tech</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Hacking Oregon Eclipse — story of a side project</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Thu, 27 Jul 2017 07:22:41 +0000</pubDate>
      <link>https://dev.to/picsoung/hacking-oregon-eclipse--story-of-a-side-project-ml</link>
      <guid>https://dev.to/picsoung/hacking-oregon-eclipse--story-of-a-side-project-ml</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl57s3450czcdiltf09vf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl57s3450czcdiltf09vf.gif"&gt;&lt;/a&gt;Screencast of eclipse project&lt;/p&gt;

&lt;p&gt;Lately, I have been curious about the new “in vogue” Javascript framework: &lt;a href="http://vuejs.org" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; (it’s a pleonasm, I know). I just needed a side-project idea to discover this new shiny toy everybody is talking about.&lt;/p&gt;

&lt;p&gt;The idea of a project came while one night in a bar while sipping a good IPA with my fellow Advocate &lt;a href="http://twitter.com/dzello" rel="noopener noreferrer"&gt;Josh&lt;/a&gt;. We were talking about the coming Solar Eclipse in the US, and where to go to see it.&lt;br&gt;&lt;br&gt;
Sadly, I did not personally plan to enjoy one of the many &lt;a href="http://oregoneclipse2017.com/" rel="noopener noreferrer"&gt;hippie gathering&lt;/a&gt;happening in Oregon the week of the eclipse. But I am sure I would be able to enjoy this rare phenomenon close to where I live in California.&lt;/p&gt;

&lt;p&gt;With some basic googling I found the official &lt;a href="https://eclipse2017.nasa.gov" rel="noopener noreferrer"&gt;NASA Website&lt;/a&gt; that is listing all the events organized in the country. Good news: Astronomers, Science Museums, and NASA facilities will be holding tons of event for everybody to enjoy the eclipse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F749%2F1%2AEHYetAr3Yx_nmbf1682jRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F749%2F1%2AEHYetAr3Yx_nmbf1682jRQ.png"&gt;&lt;/a&gt;Map of events displayed on NASA website&lt;/p&gt;

&lt;p&gt;Unfortunately, the user experience on this NASA website was not super exciting. You would have to point and zoom on a Map to find the different events around you. I thought there should be a better and nicer way: that’s why I’ve built &lt;a href="https://%F0%9F%8C%9A%F0%9F%8C%9E.ws" rel="noopener noreferrer"&gt;🌚🌞.ws&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ARHLAkdTbworb0QavR_eLTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ARHLAkdTbworb0QavR_eLTA.png"&gt;&lt;/a&gt;The &lt;a href="https://%F0%9F%8C%9A%F0%9F%8C%9E.ws" rel="noopener noreferrer"&gt;🌚🌞.ws&lt;/a&gt; experience&lt;/p&gt;
&lt;h3&gt;
  
  
  Provide a better search experience 🔍🗓
&lt;/h3&gt;

&lt;p&gt;My primary goal was to offer a pleasant search experience, where people would put their location and the app will show events nearby.&lt;/p&gt;

&lt;p&gt;When it comes to search, my tool of choice is &lt;a href="http://Algolia.com" rel="noopener noreferrer"&gt;Algolia&lt;/a&gt;. They offer APIs and SDKs to provide intuitive search in websites like &lt;a href="http://twitch.tv" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt;, &lt;a href="http://producthunt.com" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; or &lt;a href="http://news.ycombinator.com" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To be able to use their solution I needed to get all the events data. By checking the source code of NASA website, I’ve found the Google spreadsheet they were using to populate events on the map. I just had to download it and turn this file into JSON.&lt;/p&gt;

&lt;p&gt;I created an events index on &lt;a href="http://algolia.com" rel="noopener noreferrer"&gt;Algolia&lt;/a&gt;, where I would store all the events. To be able to perform a geo-based search I renamed the location field to _geoloc, and that was it. I could already search for events around a specific point on the globe with its latitude and longitude coordinates.&lt;/p&gt;

&lt;p&gt;Then, instead of having a field where people will freely put their address, I have used &lt;a href="http://community.algolia.com/places/" rel="noopener noreferrer"&gt;Algolia Places&lt;/a&gt;. It’s a text field with auto completion on addresses or city names. This tool uses Open Street Map data so it’s pretty accurate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0mEqCkEnJRzzlWvZE-q_hA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A0mEqCkEnJRzzlWvZE-q_hA.gif"&gt;&lt;/a&gt;Algolia Places experience&lt;/p&gt;

&lt;p&gt;Using this tool, users could start typing Saand the tool will suggest San Francisco. On a callback function the app will get all the info about this location, like it’s latitude and longitude, as well as its state or its postal code.&lt;/p&gt;

&lt;p&gt;That’s how I got my first MVP running in few hours. Catching the change event on the input field, receiving the data about the location, perform a geo search on the event index and display the results.&lt;/p&gt;
&lt;h3&gt;
  
  
  Get local Eclipse circumstances 🌒🌘
&lt;/h3&gt;

&lt;p&gt;I was pretty happy about my MVP, but I wanted to add more information regarding local circumstances of the eclipse. Wouldn’t be cool to know how long it will last? Or when will be the maximum?&lt;/p&gt;

&lt;p&gt;Naively, I thought that the eclipse was happening everywhere at the same time. So I just had to take the date and convert it to local time zone.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/xoMgnJDXd3k"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Looks like I forgot my basic physics knowledge…&lt;/p&gt;

&lt;p&gt;The Moon and the Earth are both moving at the same time, so the shadow of the Moon on Earth is also moving.&lt;/p&gt;

&lt;p&gt;Check this animation to visualize it better:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-889187888797286401-730" src="https://platform.twitter.com/embed/Tweet.html?id=889187888797286401"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-889187888797286401-730');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=889187888797286401&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;So I had to find a way to get all those local circumstances as I could not guess them.&lt;/p&gt;

&lt;p&gt;Well, if I am being 100% honest with you… I could… Through my research, I’ve learned about the &lt;a href="https://en.wikipedia.org/wiki/Besselian_elements" rel="noopener noreferrer"&gt;Besselian elements&lt;/a&gt;. With some calculations, you can predict all the steps of an eclipse on any point on Earth. It sounds even more crazy when you realize that it was found in 1820 and that other civilizations have used similar techniques thousands of years ago.&lt;/p&gt;

&lt;p&gt;The only documents I’ve found were full of endless equations, and I had no faith to deal with them in Javascript…&lt;/p&gt;

&lt;p&gt;I finally discovered an API from the &lt;a href="http://aa.usno.navy.mil/data/docs/Eclipse2017.php" rel="noopener noreferrer"&gt;US Naval Observatory&lt;/a&gt; that would do that for me. This API is giving back the timing for the different phases of the eclipse as well as the magnitude, the sun azimuth, and some angles.&lt;/p&gt;

&lt;p&gt;Once again my naively believed that with all this data, I had enough things to draw a beautiful visualization of the Moon shadow on the Sun.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/796beafd8fbafbb2d36171c22050f269/href" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/796beafd8fbafbb2d36171c22050f269/href" rel="noopener noreferrer"&gt;https://medium.com/media/796beafd8fbafbb2d36171c22050f269/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tried during two days to find the right way of doing it. I used all the trigonometry I remembered from high school. My dream were full of crazy calculations. After many trials I could not get the results other websites were showing. I had to give up 😩.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If anybody has a clue, I would love to try and document a walk through on how to display an eclipse in SVG/CSS depending on latitude, longitude.&lt;br&gt;&lt;br&gt;
At the moment, visualizations are coming from &lt;a href="http://timeanddate.com/eclipse/in/usa/" rel="noopener noreferrer"&gt;Timeanddate&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Finding a domain name 💻🔗
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can easily bet that all the nice domains for this particular events are squatted by people with business minds, giving you little information in the middle of many popup ads.&lt;/p&gt;

&lt;p&gt;I tried variations around eclipse, events,US ; but I did not like anything…&lt;/p&gt;

&lt;p&gt;Until a few days ago when &lt;a href="https://www.producthunt.com/posts/domainoji" rel="noopener noreferrer"&gt;Domainji&lt;/a&gt; got featured on Product Hunt.&lt;br&gt;&lt;br&gt;
That was it: I had to get an emoji domain! 🎉&lt;/p&gt;

&lt;p&gt;I’ve learned a lot about &lt;a href="https://www.punycoder.com/" rel="noopener noreferrer"&gt;punny codes&lt;/a&gt;, and decided to buy the simple&lt;a href="http://%F0%9F%8C%9A%F0%9F%8C%9E.ws" rel="noopener noreferrer"&gt;🌚🌞.ws&lt;/a&gt; on &lt;a href="https://t.co/cE1K2b3ef2" rel="noopener noreferrer"&gt;i❤.ws&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do you see how the Moon is looking at the Sun with appetite?&lt;br&gt;&lt;br&gt;
This is what’s happening during an eclipse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Emoji domains are a pain when it comes to open graph tags. For example, Facebook OpenGraph debugger doesn’t recognize them as valid URLs. I had some fun times trying to debug this part of the website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue experience👨‍💻👍
&lt;/h3&gt;

&lt;p&gt;You remember I’ve started this post talking about &lt;a href="https://vuejs.org" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;?&lt;br&gt;&lt;br&gt;
Yeah, so what about it?&lt;/p&gt;

&lt;p&gt;To get started I read &lt;a href="http://matthiashager.com/complete-vuejs-application-tutorial" rel="noopener noreferrer"&gt;Matthias Hager’s&lt;/a&gt; tutorial, which gave me a pretty good base on how things were working. It was intuitive for the use case I had.&lt;br&gt;&lt;br&gt;
I did not cut my app into components, until I was sure that everything was working together.&lt;br&gt;&lt;br&gt;
I was happy to find a lot of resources and existing components like &lt;a href="https://github.com/Gomah/vue-places" rel="noopener noreferrer"&gt;Places&lt;/a&gt;, &lt;a href="https://github.com/vue-bulma/tooltip" rel="noopener noreferrer"&gt;Tooltip&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/prerender-spa-plugin" rel="noopener noreferrer"&gt;Prerender&lt;/a&gt; (for opengraph tags). And I also got to discover &lt;a href="http://bulma.io" rel="noopener noreferrer"&gt;Bulma CSS&lt;/a&gt; which is delightful to use compared to Bootstrap.&lt;/p&gt;

&lt;p&gt;You can find the code of the project &lt;a href="https://github.com/picsoung/eclipse2017" rel="noopener noreferrer"&gt;here&lt;/a&gt; : so if you have any comment on how to make it more “ &lt;strong&gt;Vuesque&lt;/strong&gt; ” please let me know.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this hack, feel free to through feedback and feature request.&lt;/p&gt;

&lt;p&gt;Please enjoy the Eclipse safely!&lt;/p&gt;




</description>
      <category>vue</category>
      <category>eclipse</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Turn boring email notifications into actionable Slack conversations</title>
      <dc:creator>Nicolas Grenié</dc:creator>
      <pubDate>Fri, 30 Jun 2017 17:12:10 +0000</pubDate>
      <link>https://dev.to/picsoung/turn-boring-email-notifications-into-actionable-slack-conversations-dd3</link>
      <guid>https://dev.to/picsoung/turn-boring-email-notifications-into-actionable-slack-conversations-dd3</guid>
      <description>&lt;p&gt;Yesterday I was discussing with a client answering some of their questions about our &lt;a href="http://3scale.net" rel="noopener noreferrer"&gt;3scale API management&lt;/a&gt; solution. Among many other things they were curious about our &lt;em&gt;“alert system”&lt;/em&gt; and how could we notify them in a case of high traffic on their API. Simple! We send you an email if someone is about to reach their API quota.&lt;/p&gt;

&lt;p&gt;Almost at the same time I was answering this question I think I heard myself saying… “wait, what?! emails?!”. Kind of apologizing we were not offering a more modern solution.We ended the call, and I was left with a furious willing of hacking around to see how we can improve this experience. I had to find out! This is the story of my morning hack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Abc01avAKIn8kMyN7XZ6s4A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Abc01avAKIn8kMyN7XZ6s4A.png"&gt;&lt;/a&gt;Ugly email notification&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F461%2F1%2A7pX-AQdOPIjLaUb0Dlamrw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F461%2F1%2A7pX-AQdOPIjLaUb0Dlamrw.jpeg"&gt;&lt;/a&gt;Expected result in Slack&lt;/p&gt;

&lt;h4&gt;
  
  
  Connecting blocks🔌🏗
&lt;/h4&gt;

&lt;p&gt;I don’t know about you, but when I think about notifications, I usually think about &lt;a href="http://slack.com" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;. That’s where I try to gather all the automatic reporting for the tools I use. This hack will send notifications to Slack.&lt;/p&gt;

&lt;p&gt;Also, sadly, our engineers won’t have time to build a nice alert API so I will have to work with the source I have: &lt;em&gt;an email&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are many mail APIs like &lt;a href="http://context.io" rel="noopener noreferrer"&gt;Context.io&lt;/a&gt; or &lt;a href="http://nylas.com" rel="noopener noreferrer"&gt;Nylas&lt;/a&gt; that will let you get emails and parse them, but that was a lot of overhead to deal with (OAuth, filtering emails, …). The best solution would be to send notifications to a designated email address and parse them there.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://zapier.com" rel="noopener noreferrer"&gt;Zapier&lt;/a&gt; offers exactly this feature with their &lt;a href="http://parser.zapier.com" rel="noopener noreferrer"&gt;Parser&lt;/a&gt; product. They give you an email address where you can send all emails to be parsed. It includes a parsing UI where you define variables you want to extract.&lt;/p&gt;

&lt;p&gt;Finally, to have more flexibility on the message formatting we won’t plug directly Zapier to Slack but instead, use Zapier webhook action to send extracted data to an app hosted on &lt;a href="http://glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are building a complete serverless solution 😇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AEIYMhfIow0kHz_gmfOJyng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AEIYMhfIow0kHz_gmfOJyng.png"&gt;&lt;/a&gt;Webhook integration form on Slack&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup Slack 🤖💬
&lt;/h4&gt;

&lt;p&gt;To be able to send a message to your Slack team we would need to created an &lt;strong&gt;Incoming Webhook&lt;/strong&gt; integration. Follow this &lt;a href="https://my.slack.com/services/new/incoming-webhook/" rel="noopener noreferrer"&gt;link&lt;/a&gt;, it should guide you to configure the integration. There, You will define on which channel the notification will be sent. When you are done, keep the Webhook URL handy, we will need later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AZ7gQW0QMmxTHXulWtxRI0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AZ7gQW0QMmxTHXulWtxRI0g.png"&gt;&lt;/a&gt;Zapier parser UI&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup Zapier parser and trigger 📥⚙️
&lt;/h4&gt;

&lt;p&gt;On Zapier, we will start by configuring the email parser &lt;a href="http://parser.zapier.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Once you have an address, send there an example of your notification email so we can setup a template. In few seconds the email should be received by the parser and you should see it appeared. Then, highlight variables you want to extract from the email and give them names.&lt;/p&gt;

&lt;p&gt;Once template is defined, we will configure a &lt;em&gt;Zap&lt;/em&gt; to connect the email parser with our app. In the &lt;em&gt;Zap&lt;/em&gt;, select &lt;strong&gt;Email Parser&lt;/strong&gt; app to trigger with the &lt;strong&gt;New Email&lt;/strong&gt; action. If you test this step, you should be able to retrieve the message you previously sent to &lt;em&gt;Parser&lt;/em&gt; email address.&lt;/p&gt;

&lt;h4&gt;
  
  
  The app 🎏💻
&lt;/h4&gt;

&lt;p&gt;The app will expose a &lt;strong&gt;POST&lt;/strong&gt; route &lt;em&gt;/hook&lt;/em&gt;, where Zapier will send a request containing the extracted data. You can check &lt;a href="https://glitch.com/edit/#!/email-to-slack-notification" rel="noopener noreferrer"&gt;my example&lt;/a&gt; on Glitch and remix it with your own variables.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;.env&lt;/em&gt; file, you should add values to the variables. Get the Hook URL we previously created on Slack, and add some personality to your notifications adding a username and icon. The &lt;em&gt;ZAPIER_SECRET&lt;/em&gt; variable should be a random string, we will use it to identify that the request comes from Zapier webhook.&lt;/p&gt;

&lt;p&gt;The message formatting is happening on the &lt;em&gt;slack.js&lt;/em&gt; file. You can check the &lt;a href="https://api.slack.com/docs/messages/builder" rel="noopener noreferrer"&gt;Message Builder&lt;/a&gt; from Slack to run formatting tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AA5w8rg_IrlmAwKMWXlM5wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AA5w8rg_IrlmAwKMWXlM5wg.png"&gt;&lt;/a&gt;Webhook configuration on Zapier&lt;/p&gt;

&lt;h4&gt;
  
  
  Add webhook action to Zapier 🎣⚙️
&lt;/h4&gt;

&lt;p&gt;Now, that our app is up on Glitch we can add an action to our &lt;em&gt;Zap&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Add a Webhook action of type POST pointing to the URL &lt;a href="https://YOUR_GLITCH_APP_NAME.glitch.me/hook" rel="noopener noreferrer"&gt;https://YOUR_GLITCH_APP_NAME.glitch.me/hook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In should return a JSON payload. Then define the variables that will be sent to the app, and map them we the extracted ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AWwPma046NW1DY1kwvfX-Rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AWwPma046NW1DY1kwvfX-Rw.png"&gt;&lt;/a&gt;Secret header for security&lt;/p&gt;

&lt;p&gt;Finally, for security purpose, we will define a header named &lt;em&gt;X-zapier-secret&lt;/em&gt; with the same value as the &lt;strong&gt;ZAPIER_SECRET&lt;/strong&gt; environment variable we defined earlier.&lt;/p&gt;

&lt;h4&gt;
  
  
  Test and enjoy 🎉🎊
&lt;/h4&gt;

&lt;p&gt;And this it, you are done now 👍&lt;br&gt;&lt;br&gt;
Test the flow and see if the message renders the way you want. When you are happy with the result, turn the &lt;em&gt;Zap&lt;/em&gt; on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F452%2F1%2AVryUy0b0Gxr57rmceDHp1A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F452%2F1%2AVryUy0b0Gxr57rmceDHp1A.png"&gt;&lt;/a&gt;Expected result on Slack&lt;/p&gt;

&lt;p&gt;Now you can ignore email notifications as they are all sent to Slack in a beautiful and comprehensive way.&lt;/p&gt;

&lt;p&gt;If you want to enhance this flow we can later add &lt;a href="https://api.slack.com/docs/message-buttons" rel="noopener noreferrer"&gt;actionable buttons&lt;/a&gt;, but that needs a bit more work.&lt;/p&gt;

&lt;p&gt;Let me know what you think of such hacks!&lt;/p&gt;

</description>
      <category>zapier</category>
      <category>email</category>
      <category>hackathon</category>
      <category>glitch</category>
    </item>
  </channel>
</rss>
