<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Alexa Skills - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Alexa Skills - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:21:16 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/alexa-skills/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Alexa and Google Home: How to Build your own Voice Apps and Deploy Them to Millions of Devices Around the World ]]>
                </title>
                <description>
                    <![CDATA[ Voice apps completely change the way we interact with the digital world. Voice adds another dimension to human-computer interaction that developers are only beginning to explore. In this article, I will show you how you can use your existing backend ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/creating-deploying-voice-apps-for-alexa-google/</link>
                <guid isPermaLink="false">66d45d5fc17d4b8ace5b9eb0</guid>
                
                    <category>
                        <![CDATA[ Alexa Skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ google home ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Akash Joshi ]]>
                </dc:creator>
                <pubDate>Mon, 12 Aug 2019 22:03:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/08/4x3-2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Voice apps completely change the way we interact with the digital world. Voice adds another dimension to human-computer interaction that developers are only beginning to explore.</p>
<p>In this article, I will show you how you can use your existing backend architecture &amp; APIs, connecting them with your voice apps to offer a new experience to your customers. Voice apps borrow a lot from our general development process, not requiring separate development resources.</p>
<h1 id="heading-what-we-are-building">What we are building</h1>
<p>We are going to build a superhero search app using the <a target="_blank" href="https://akabab.github.io/superhero-api/api/all.json">Open Source Superhero API</a>.</p>
<p>I have added a wrapper around this API to make it accessible from our Voice App. You can find the code in this gist - <a target="_blank" href="https://gist.github.com/akash-joshi/476ead410a244a48e037c138ba2387b0">https://gist.github.com/akash-joshi/476ead410a244a48e037c138ba2387b0</a>.</p>
<p>Take a look at the completed app below:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5F20v5cIQts" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>We will build this for Voice apps (Alexa and Google). We will be using the platform <a target="_blank" href="http://voiceflow.com">VoiceFlow</a>, which allows us to build voice apps visually.</p>
<h1 id="heading-voiceflow-tutorial">Voiceflow Tutorial</h1>
<p>VoiceFlow is a visual way to create voice apps, and is very easy to use and understand.</p>
<p>Firstly, create an account there to get started.</p>
<p>After creating an account, create a new project, giving it an appropriate name. For the purpose of this tutorial, we have chosen all English regions as deployment regions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will end up on a blank canvas after this. Don't be overwhelmed by all the options present on the screen, this tutorial will guide you through all the relevant blocks required.</p>
<p>In the blocks submenu on the left, you will see several blocks which can be used to build an Alexa or Google skill. Each block performs a certain function, and Voiceflow is based on building Voice apps by combining these blocks.</p>
<h3 id="heading-1-speak-block">1. Speak Block</h3>
<p>The first block that we will use is the Speak Block. We will use it to make Alexa say something to the user. Drag a speak blog onto the canvas, rename it to Introduction and write a suitable introduction to your app in the text area. I will use "Welcome to Superhero! Say the name of a hero to search!".</p>
<p>At any point, test out your app by clicking on the Play Button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-2-capture-block">2. Capture Block</h3>
<p>The next block we will use is the Capture block. It is used to capture data from the user's voice and store it into a variable.</p>
<p>Firstly, create a new variable in the 'Variables' submenu on the left by typing a name and pressing enter. Use the name 'hero' for now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Adding a capture block, name "Input Type" as "Actor" and "Capture input To" as "hero".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Add a speech block after it, saying : "Searching for {hero}. ". We use curly brackets to use a variable in speech. Be sure to enter {hero} by hand so that Voiceflow detects it as a variable. The is a tag which is part of a language called Speech Synthesis Markup Language (SSML). You can read more about it on Amazon's <a target="_blank" href="https://developer.amazon.com/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html">official documentation page.</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-3-api-block">3. API Block</h3>
<p>Click on the Plus icon below your Speak block to add another step to the block. Add an Integration block from the list. After that, click on the integration block &amp; set up the options in this order:</p>
<ol>
<li>Choose an integration - "Custom API" since we will be using a custom API to get some data.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>I want to - "Make a GET request" since we are using a GET request to get JSON data from an API.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will use a custom API (<code>https://super-search-akashjoshi.flexiple.now.sh/?hero=</code>)to get the superhero data.</p>
<p>Try navigating to <code>https://super-search-akashjoshi.flexiple.now.sh/?hero=superman</code> in your browser to see what kind of data is returned by the API. Replace <em>superman</em> with any hero that you want to search for.</p>
<p>We replace the hero name with the {hero} variable so that the API fetches the desired hero correctly.</p>
<p>Paste</p>
<p><code>https://super-search-akashjoshi.flexiple.now.sh/?hero={hero}</code></p>
<p>into the URL bar. Be sure to type in {hero} by yourself so that Voiceflow detects it as a variable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_8.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>However, we aren't done yet. Click on Test Integration to test the API call.</p>
<p>The response from the API has to be mapped into output variables so that they are spoken to the user.</p>
<p>Add variables for name, fullName, born, alignment, work &amp; base from the variables side-bar.</p>
<p>Copy the output path of the JSON file by clicking on the response tab of the Test Integration tab and paste it into the output menu. Do this for all of the following - name, fullName, born, alignment, work &amp; base.</p>
<p>Check the short video below to understand how to map the JSON output with your Voiceflow variables:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fDY_klt08mg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In the image above, we can see that the Integration has 2 outputs, one without a prefix text, and one with fail as prefix. The one without the prefix text is a success state output, and the one with fail output is when our API call fails.</p>
<p>Add a speech block saying 'The hero was not found' connected to the fail state. If the API succeeds and a hero was found matching the {hero} variable, all the output variables will be set with the correct values. Otherwise, they will be to the default value of 0.</p>
<h3 id="heading-4-if-block">4. If Block</h3>
<p>Add an if block to the canvas, and check whether fullName = 0. If it is 0, connect it to the "Not Found" block.</p>
<p>Watch the short video below to understand how to add conditions to If blocks:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/gmS-NleBtl0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>Else, the hero was found. So, speak the hero name by writing in a speech block: "Their hero name is {name}. Their full name is {fullName}. They were born in {born}. They are {alignment}. They work as a {work} from {base}. Do you want to search another hero?"</p>
<p>Again, be sure to type in the variable names so that Voiceflow detects them as variables.</p>
<p>To clear out the variables after the skill completes, add a "Set" block to the canvas and set fullName to 0. This step is necessary, because if the variables are not cleared, the previous answer will be repeated by the skill!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-5-choice-block">5. Choice Block</h3>
<p>We shouldn't end the skill here. We should allow the user a choice on whether they want to search for another superhero. Change the text in the "Not Found" block to ask whether the user wants to search for more at the end.</p>
<p>Add a Choice block to the canvas. The choice block allows us to perform certain actions based on user voice. This block checks whether the user wants to search for another hero. Enter synonyms of Yes for searching further.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_11-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>For else, add a Flow block, selecting Stop Flow as a flow.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_12.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Connect the ' 1 ' output of the Choice block to a speech block asking user to say another Hero name, and connect it to the Capture block. Look at the image below to understand how it's done.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/08/FCC_13.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And we are done! Test out your app by clicking on the play button.</p>
<h3 id="heading-6-deployment">6. Deployment</h3>
<p><strong>a. Alexa</strong></p>
<p>To deploy your app to the Alexa platform, click on the Publish tab, connect your Amazon developer account and fill the form options according to relevance to your skill (like Description, Skill Name, etc.)</p>
<p>Be sure not to change any of the default invocations that may break your skill during deployment and cause you to resubmit it.</p>
<p>In case you get some part wrong while submitting, the review process is very helpful &amp; they will let you know what went wrong in the submission.</p>
<p><strong>b. Google</strong></p>
<p>Click on the instruction link to see <a target="_blank" href="https://learn.voiceflow.com/articles/2705386-uploading-your-project-to-google-assistant">instructions to add the Google Assistant file to Voiceflow</a>. After adding the file, follow the publish to production guide from <a target="_blank" href="https://learn.voiceflow.com/articles/2712178-deploying-your-google-assistant-project-to-production">here</a> . Few caveats in the Google deployment process:</p>
<ol>
<li><p>Your invocation name cannot have any keywords which may be used during invocation. Eg, you cannot name the action 'Superhero Search', because 'Search' may be used as a invocation name.</p>
</li>
<li><p>You need to add a custom privacy policy from Google. You can't use the one from Voiceflow as it has mentions of Alexa or skills, which will cause your action to be declined. You can use a template I built <a target="_blank" href="https://docs.google.com/document/d/1ZdI1m-6Vo46vSTeWs4pG8fDHV1n8McWgcZud3TGN5k0">here</a>. It has instructions on how to write your privacy policy and where to keep it.</p>
</li>
<li><p>The final point would be to not use the term 'Alexa' or 'skill' at any point in your action description or within the app. If there are any occurrences in the app, replace them with something more generic so you can use the same codebase for Alexa &amp; Google. Replace 'Alexa' &amp; 'skill' with 'Google' &amp; 'actions' in the description and similar places.</p>
</li>
</ol>
<h1 id="heading-what-next">What Next?</h1>
<p>App ideas:</p>
<p>The interesting point about voice apps is that you can use them as an extension for your existing apps. For example, If you have already built a messaging app like <a target="_blank" href="https://blog.flexiple.com/build-a-powerful-chat-application-using-react-hooks/">this one</a>, the voice platform can be an easy way of sending and reading messages on your app. For a blog writing platform, a voice app may be an easy way to take notes before actually sitting down to write an article. Even for a product posting platform like <a target="_blank" href="https://producthunt.com">ProductHunt</a> or <a target="_blank" href="https://remote.tools">Remote.tools</a>, you can easily integrate voice to read out description and other details on the products.</p>
<p>In such ways, voice apps can be used to enhance user experience.</p>
<p>Useful links:</p>
<p><a target="_blank" href="https://getvoiceflow.com">https://getvoiceflow.com</a></p>
<p><a target="_blank" href="https://learn.voiceflow.com/articles/2705386-uploading-your-project-to-google-assistant">https://learn.voiceflow.com/articles/2705386-uploading-your-project-to-google-assistant</a></p>
<p><a target="_blank" href="https://learn.voiceflow.com">https://learn.voiceflow.com</a></p>
<p><a target="_blank" href="https://developer.amazon.com/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html">https://developer.amazon.com/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html</a></p>
<p>Hope you liked this article. I have also written a <a target="_blank" href="https://blog.flexiple.com/building-a-web-and-voice-app-ecosystem-amazon-alexa-google-home-react-node/">more extensive article</a> which adds a web-based frontend to this app making it a complete ecosystem.</p>
<p>Happy Coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to improve the conversation flow of your Alexa skill ]]>
                </title>
                <description>
                    <![CDATA[ By Garrett Vargas Natural conversations are fluid. That’s one of the joys of face to face human conversation, you never know how the dialog will evolve. But sometimes, there is a natural flow to the conversation. Ask someone where they want to eat, a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-improve-the-conversation-flow-of-your-alexa-skill-1b6c6556f9a3/</link>
                <guid isPermaLink="false">66c352cbd58e4fdd567d519c</guid>
                
                    <category>
                        <![CDATA[ Alexa Skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Mar 2019 14:57:05 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*uQl2sV1anCMlYWFd" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Garrett Vargas</p>
<p>Natural conversations are fluid. That’s one of the joys of face to face human conversation, you never know how the dialog will evolve. But sometimes, there is a natural flow to the conversation. Ask someone where they want to eat, and you expect to hear a restaurant or type of food, not a response about a favorite movie.</p>
<p>One of the frustrations people have with voice assistants is that they sometimes do a poor job understanding what they’re saying. Amazon has a tool to help third party developers provide better recognition. <strong>Dialog Management</strong> lets you prompt for values to fulfill a request with increased accuracy.</p>
<p>For example, if you are creating a skill that searches for a car rental, Alexa can prompt the customer for a city and dates of travel after they say “find a car.” Alexa’s built-in functionality improves the accuracy of speech recognition in this case as it listens for specific values.</p>
<p>The problem is that the customer has to speak the appropriate words to trigger a Dialog-controlled intent. Amazon recently announced <a target="_blank" href="https://developer.amazon.com/blogs/alexa/post/9ffdbddb-948a-4eff-8408-7e210282ed38/intent-chaining-for-alexa-skill">intent chaining</a> as a solution to this problem.</p>
<p>In this blog I’m going to show you how I use this functionality with a skill that lets the user perform a car search. First, let’s review how Dialog Management works within Alexa. Let’s look at a CarSearchIntent that gathers the input needed to kick off a car search.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/fLRkwma7n9QfRGu2wv6bqzUZkahywAXANe-3" alt="Image" width="800" height="605" loading="lazy">
<em>CarSearchIntent with slots for location and travel dates</em></p>
<p>As you can see, we have several variations on how a customer can find a car, including slots for Location, PickUpDate, and DropOffDate. We want to make sure the customer provides all three of these slots before we start processing the request. We use Dialog Management to let Alexa handle prompting the customer to provide these.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/FCtaQRUn465AgEwF8Tyl0XcYk8UIVnOSS-O7" alt="Image" width="800" height="554" loading="lazy">
<em>Location as required slot with prompt</em></p>
<p>When in Dialog mode, Alexa has a higher chance of accuracy because it is trying to fill slots for this intent. But to get into this mode, the customer has to trigger this intent by saying “Find a car” or a similar phrase. Ideally, we’d drop the customer into this mode as soon as they launched the skill.</p>
<p>Enter Intent Chaining! We can add a <strong>Dialog Delegate</strong> directive to our response that puts the customer into the dialog flow of CarSearchIntent.</p>
<pre><code>canHandle(handlerInput) {  <span class="hljs-keyword">const</span> request = handlerInput.requestEnvelope.request;  <span class="hljs-keyword">return</span> handlerInput.requestEnvelope.session.new ||    (request.type === <span class="hljs-string">'LaunchRequest'</span>);},<span class="hljs-attr">handle</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">handlerInput</span>) </span>{  <span class="hljs-keyword">return</span> handlerInput.responseBuilder    .addDelegateDirective({      <span class="hljs-attr">name</span>: <span class="hljs-string">'CarSearchIntent'</span>,      <span class="hljs-attr">confirmationStatus</span>: <span class="hljs-string">'NONE'</span>,      <span class="hljs-attr">slots</span>: {}    })    .speak(<span class="hljs-string">"Welcome to car search."</span>)    .getResponse();}
</code></pre><p>The dialog directive allows us to pre-fill some of the slots (for example, we could default the location to the last used search location). What’s interesting to note is that we only specify “Welcome to car search” as the response for this handler. We don’t specify a reprompt. Alexa appends the dialog prompt for CarSearchIntent to our response and uses that as the reprompt. So in this case what the user will hear is “Welcome to car search. Where would you like to pick up the car?” If they don’t answer, they will hear a reprompt of “Where would you like to pick up the car?”</p>
<p>You also have the ability to direct the customer to fill out a specific slot when dropping them into a dialog. Let’s say that we want to guide the user to first specify the pick up date for their car. We can do that using an <strong>Elicit Slot</strong> directive, as shown in the following code.</p>
<pre><code>canHandle(handlerInput) {  <span class="hljs-keyword">const</span> request = handlerInput.requestEnvelope.request;  <span class="hljs-keyword">return</span> handlerInput.requestEnvelope.session.new ||    (request.type === <span class="hljs-string">'LaunchRequest'</span>);},<span class="hljs-attr">handle</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">handlerInput</span>) </span>{  <span class="hljs-keyword">return</span> handlerInput.responseBuilder    .addElicitSlotDirective(<span class="hljs-string">'PickUpDate'</span>, {      <span class="hljs-attr">name</span>: <span class="hljs-string">'CarSearchIntent'</span>,      <span class="hljs-attr">confirmationStatus</span>: <span class="hljs-string">'NONE'</span>,      <span class="hljs-attr">slots</span>: {}    })    .speak(<span class="hljs-string">"Welcome to car search. When would you like to pick up your car?"</span>)    .reprompt(<span class="hljs-string">"When would you like to pick up your car?"</span>)    .getResponse();}
</code></pre><p>In this case, we need to spell out the entire speech and reprompt that the customer will hear. We need to do this since we are controlling how we drop the customer into the dialog management flow.</p>
<p>Chaining intents lets you manage the conversation flow in a more natural way. Use it to make your skill more usable for your customers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use Alexa Presentation Language in your skill ]]>
                </title>
                <description>
                    <![CDATA[ By Garrett Vargas Amazon recently released the Alexa Presentation Language (APL). APL provides a richer display for multimodal skills. It is based on modern frameworks that separate display elements from data sources. It gives you the flexibility to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-alexa-presentation-language-in-your-skill-3c49961825c5/</link>
                <guid isPermaLink="false">66c355885b0262f172b2c7f4</guid>
                
                    <category>
                        <![CDATA[ Alexa Skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ UX ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 05 Feb 2019 17:08:32 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Yhxg6EjPOGffEe0-01U-RQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Garrett Vargas</p>
<p>Amazon recently released the Alexa Presentation Language (APL). APL provides a richer display for multimodal skills. It is based on modern frameworks that separate display elements from data sources. It gives you the flexibility to include many visual elements such as graphics, images, and slideshows and lets you tailor the display for different devices.</p>
<p>In this article, I’m going to walk through how I updated one of my skills to use APL. You can also use these tips and techniques if you are creating a new skill.</p>
<p>Most of my skills feature multimodal support using the <a target="_blank" href="https://developer.amazon.com/docs/custom-skills/display-interface-reference.html">Display Interface</a>. I decided to learn APL by updating one of my existing skills. I focused on my <a target="_blank" href="https://www.amazon.com/Garrett-Vargas-Video-Poker/dp/B07465B5ZK">Video Poker</a> skill because I wasn’t happy with the existing customer experience.</p>
<p>Video Poker presents users with a 5-card poker hand, with an ability to hold and discard cards before drawing to complete a hand. Users can do this by voice command (“keep the first card” or “keep the pair of jacks”), or by touching cards on a visual display. <strong>ListTemplate2</strong> was the best way to do this with the Display Interface. However, this came with the limitation of only allowing three cards on the screen at a time and putting numbers beneath each card in the list.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jMxKMUHlUnJBPaXP4c5kx7rCPL1WFe3DEqhJ" alt="Image" width="800" height="468" loading="lazy">
<em>Video Poker using ListTemplate2 Display Directive</em></p>
<p>Using APL, I modified a ListTemplate2 layout to shrink the size of list items, reduce the spacing between them, and fit a full five card hand on the screen. I was able to remove the numbers from items in the list and put text indicating which held cards in a bold, red font. I was able to optimize the layout for different screen dimensions, such as smaller displays like the Echo Spot.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jd4xu4HhI8hhfhPXvDtzJMByErFxomzeWU6r" alt="Image" width="800" height="464" loading="lazy">
<em>Video Poker using APL template modified from ListTemplate2</em></p>
<h4 id="heading-apl-authoring-tool">APL Authoring Tool</h4>
<p>The way I did this was through the <a target="_blank" href="https://developer.amazon.com/alexa/console/ask/displays">APL Authoring Tool</a>. This handy tool provides a list of different visual designs you can use as a baseline to create compelling visuals for your skill. It also allows you to save and upload layouts, so you can extract them to your skill code, or upload them if you make offline updates. For this use case, I started with the <strong>Image Forward List Sample</strong>, which is based on ListTemplate2.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Z2PFZCT6MUCN64bPTQ9qRs4XBXem42fTGEqB" alt="Image" width="800" height="295" loading="lazy">
<em>Selecting a visual design from the APL Authoring Tool</em></p>
<p>Once you select this visual design in the tool, you’ll see a generic example of a list with cheese samples. You’ll see the APL document at the bottom of the screen separated into two tabs:</p>
<ul>
<li>“Image Forward List Sample” which provides the layout</li>
<li>“Data JSON” tab which provides a view of the document data.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/AJFvDwilgG-7N3H4tH0f6tq73tvsNnr8lSGG" alt="Image" width="800" height="401" loading="lazy">
<em>Editing your APL Document in the Authoring Tool</em></p>
<p>Take a moment to look through the JSON on both the Image Forward List Sample tab (the layout code) and the Data JSON tab (the content code). You’ll notice in the layout that there are several references to values enclosed in <code>${}</code> such as <code>${payload.listTemplate2ListData.listPage.listItems.length}</code>. If you look in the content file, you’ll see that this is a path to a value within the content. This is how APL binds data to the presentation layer and lets you make changes.</p>
<h4 id="heading-updating-data-sources">Updating Data Sources</h4>
<p>As a first step, I wanted to update the data so it would show card images and text relevant to my skill. That way, as I started to update the layout itself, I would be able to see how it would look with my actual images. The Authoring Tool shows your rendered screen images in real time, making it convenient to use as you attempt to perfect your layout. To update the data, I took the following steps:</p>
<ul>
<li>Click on the Data JSON tab</li>
<li>In the <code>listTemplate2Metadata</code>, change the <code>title</code> and <code>logo</code> elements to something relevant to Video Poker</li>
<li>In this same element, change the <code>url</code> in the <code>backgroundImages.sources</code> fields to point to the background image I wanted to use</li>
<li>In <code>listTemplate2ListData.listPage</code>, I updated each of the items in the <code>listItems</code> array. Specifically, I updated this array to have 5 items (my cards), with <code>listItemIdentifier</code> and <code>token</code> set to “card.x” (where x ranged from 0–4). I removed the <code>secondaryText</code> since I only wanted one row of text (which would either be blank or say “HELD”). I updated the <code>image.sources</code> to point to URLs containing my card images. For now, I just selected some card images at random — my skill’s code will update the data during gameplay with the actual user’s hand</li>
<li>Update the hint text to use a transformation. Rather than hard-coding the hint string with the Alexa keyword, you can use a transform to change a hint into one that uses the wake word associated with the device, in case the user has changed it. You do this by removing the <code>hintText</code> from listTemplate2ListData and adding the following into your lastTemplate2Metadata:</li>
</ul>
<pre><code><span class="hljs-string">"properties"</span>: {    <span class="hljs-string">"hintText"</span>: <span class="hljs-string">"select number 1"</span>},<span class="hljs-string">"transformers"</span>: [    {        <span class="hljs-string">"inputPath"</span>: <span class="hljs-string">"hintText"</span>,        <span class="hljs-string">"transformer"</span>: <span class="hljs-string">"textToHint"</span>    }],
</code></pre><p>Once I had made these to the data sources, my image looked like this — pretty similar to the skill as it exists with the ListTemplate2 display which makes sense since at this point I’m still using the layout based on ListTemplate2 and have only made content changes.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2w4rK8o0mL8as6gmh7utg757rRzeYHfBWjVK" alt="Image" width="616" height="361" loading="lazy">
<em>Updated view with relevant Video Poker content</em></p>
<h4 id="heading-updating-the-layout">Updating the Layout</h4>
<p>Now for the fun part — updating the layout to get five images on the screen at one time. For this part, I made updates to the layout on the “Image Forward List Sample” tab. To make these changes, I clicked on the slider that lets you switch between a visual view of nested APL components to a raw JSON view. I find viewing the full document JSON easier to consume than clicking on each component and editing the JSON within the component. But you can play with it and follow whichever approach seems most natural to you.</p>
<p>Before talking through the changes I made, I wanted to point out some of the elements of this layout template:</p>
<ul>
<li>There is a <code>ListTemplate2</code> node in the JSON which provides two containers in an <code>items</code> node— one that applies to circular screens (like the Echo Spot) and the other for other screen types. In this blog, I’m going to focus on the non-Spot displays, but you should appreciate that you can also make changes specific to different screen layouts.</li>
<li>Looking at the second container that we’ll be changing, you‘ll see a set of <code>items</code> including an Image (the background image), an <strong>AlexaHeader</strong> (the title on the screen), a <strong>Sequence</strong> (which is the list of cards), and an <strong>AlexaFooter</strong> (the hint at the bottom of the screen)</li>
<li>You’ll see that the Sequence points to <code>HorizontalListItem</code>, which is another container in this JSON document. It contains items consisting of an Image and two Text elements (the primary text and the secondary text)</li>
</ul>
<p>With this context in mind, I made the following changes to this document:</p>
<ul>
<li>Within the <code>HorizontalListItem</code>, I changed the Image item dimensions — specifically I set <code>height</code> to 40vh and <code>width</code> to 17vw. This sets the height of each card to 40% of the viewport height, and the width to 17% of the viewport width.</li>
<li>I then updated <code>midWidth</code> to 100. This makes the width of each list item smaller and allows the five card images to appear on the screen</li>
<li>I changed <code>paddingLeft</code> and <code>paddingRight</code> to 6 to reduce the amount of space between elements</li>
<li>I added <code>paddingTop</code> and set it to 100 to add some separation between the header and the card images</li>
<li>I got rid of the secondary Text element since I don’t have two lines of text on my display</li>
<li>I changed the primary Text element so it doesn’t draw the ordinal. So <code>text</code> in this element changed from <code>&lt;b&gt;${ordinal}.&lt;/b&gt;${data.textContent.priam</code>ryTe<code>xt.text} to &lt;b&gt;${data.textContent.pri</code>maryText.text}.</li>
<li>Within this same element, I wanted the text to be red and centered. I achieved this by adding a <code>textAlign</code> field with a value of “center,” and a <code>color</code> field with a value of “red.”</li>
<li>In order to get the hint text from the appropriate location (now part of the metadata rather than the list data), I needed to update the AlexaFooter element to get the hint from <code>${payload.listTemplate2Metadata.properties.hintText}</code></li>
</ul>
<p>Finally, I needed to make the cards in my list selectable, so I could respond when the user touches one of them on the screen. To do this, I needed to change the items that were associated with the <code>Sequence</code> element from a <code>FullHorizontalListItem</code> to a <code>TouchWrapper</code> which in turn contained a <code>FullHorizontalListItem</code>. In code, that means that I changed this:</p>
<pre><code><span class="hljs-string">"item"</span>: [  {    <span class="hljs-string">"type"</span>: <span class="hljs-string">"FullHorizontalListItem"</span>,    <span class="hljs-string">"listLength"</span>: <span class="hljs-string">"${payload.listTemplate2ListData.listPage.listItems.length}"</span>  }]
</code></pre><p>to this:</p>
<pre><code><span class="hljs-string">"item"</span>: [  {    <span class="hljs-string">"type"</span>: <span class="hljs-string">"TouchWrapper"</span>,    <span class="hljs-string">"onPress"</span>: {      <span class="hljs-string">"type"</span>: <span class="hljs-string">"SendEvent"</span>,      <span class="hljs-string">"arguments"</span>: [        <span class="hljs-string">"${data.token}"</span>      ]    },    <span class="hljs-string">"item"</span>: {      <span class="hljs-string">"type"</span>: <span class="hljs-string">"FullHorizontalListItem"</span>,      <span class="hljs-string">"listLength"</span>: <span class="hljs-string">"${payload.listTemplate2ListData.listPage.listItems.length}"</span>    }  }]
</code></pre><p>Note the <code>onPress</code> element in this item. Specifically, the list of arguments. You can specify an array of different arguments to send to your skill when an item is selected. Because my existing code was processing the token of the selected card, I decided to continue to do the same to minimize the amount of code I needed to change. But you could also pass in <code>${ordinal}</code> which would tell you the index of the selected item without having to process the token.</p>
<h4 id="heading-updates-to-the-skill-code">Updates to the Skill Code</h4>
<p>Once you’ve made changes within the Authoring Tool, you can select the Export Code button which will package up your layout and data files into one JSON file for you. I chose to use two different JSON files in my code, one called main which I used for the layout and another called datasources which I used for the data. I like keeping the separation of layout and content in my source code as a general best practice. It was surprising that Amazon’s Authoring Tool didn’t encourage this too.</p>
<p>Now that we’ve downloaded the document and content, we need to make code changes to incorporate it and update the data as the user plays with our skill. We can do this by manipulating data elements and then passing them back to the skill. I used Alexa’s response interceptor functionality (which I talk about in a <a target="_blank" href="https://medium.freecodecamp.org/how-to-improve-your-code-with-alexa-response-interceptors-2b3e73721fc">separate blog post</a>). I load the data source in from a JSON file, then update the cards and text within the structure before sending it off to Alexa. I do that with the following code:</p>
<pre><code><span class="hljs-keyword">const</span> main = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./main.json'</span>);<span class="hljs-keyword">const</span> datasource = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./datasource.json'</span>);
</code></pre><pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawTable</span>(<span class="hljs-params">handlerInput</span>) </span>{  <span class="hljs-keyword">const</span> event = handlerInput.requestEnvelope;  <span class="hljs-keyword">const</span> attributes = handlerInput.attributesManager.getSessionAttributes();  <span class="hljs-keyword">const</span> game = attributes[attributes.currentGame];  <span class="hljs-keyword">let</span> i;  <span class="hljs-keyword">let</span> cardText;  <span class="hljs-keyword">let</span> url;
</code></pre><pre><code>  <span class="hljs-comment">// Update the images  for (i = 0; i &lt; game.cards.length; i++) {    const card = game.cards[i];    url = GetCardURL(card);    cardText = (card.hold) ? 'HELD' : '';    datasource.listTemplate2ListData.listPage.listItems[i]      .textContent.primaryText.text = cardText;    datasource.listTemplate2ListData.listPage.listItems[i]      .image.sources[0].url = url;    datasource.listTemplate2ListData.listPage.listItems[i]      .image.sources[1].url = url;  }  // Give an appropriate hint  if (game.state === 'FIRSTDEAL') {      if (game.cards[0].hold) {        datasource.listTemplate2ListData.hintText = 'discard the first card';      } else {        datasource.listTemplate2ListData.hintText = 'hold the first card';      }      datasource.listTemplate2Metadata.title = 'Select cards to hold or say Deal';    } else {      datasource.listTemplate2ListData.hintText = 'deal';      datasource.listTemplate2Metadata.title = 'Your last hand';    }  }  return handlerInput.responseBuilder    .addDirective({      type: 'Alexa.Presentation.APL.RenderDocument',      version: '1.0',      document: main,      datasources: datasource,    });}</span>
</code></pre><p>The second place I had to make a code change was to handle the user touching one of the items in my list. In my old code, I was parsing item tokens of the form “card.x” where x is the ordinal position of the card in the list. With a Display Interface, this meant looking for an <code>ElementSelected</code> request. In APL, your code will receive an <code>APL.Presentation.APL.UserEvent</code>, and you can process the request as follows to determine which card was selected:</p>
<pre><code><span class="hljs-built_in">module</span>.exports = {  canHandle(handlerInput) {    <span class="hljs-keyword">const</span> request = handlerInput.requestEnvelope.request;       <span class="hljs-comment">// Was this a touch item selected?    if (request.type === 'Alexa.Presentation.APL.UserEvent') {      return ((request.source.type === 'TouchWrapper')        &amp;&amp; (request.source.handler === 'Press'));    }    return false;  },  handle(handlerInput) {    let index;    const event = handlerInput.requestEnvelope;    // Was this a touch item selected?    if (event.request.type === 'Alexa.Presentation.APL.UserEvent') {      const cards = event.request.arguments[0].split('.');      if (cards.length === 2) {        index = cards[1];      }            // Do something with the selected card...</span>
</code></pre><pre><code>    }  },};
</code></pre><p>With these changes, I had a much cleaner looking Video Poker skill, which is sure to delight my customers more than the older format I was using. I’ve just started scratching the surface in terms of APL’s capabilities. But I can tell it will open up a new world of possibilities for voice-driven multimodal skills! Let me know in the comments about your own learnings with this new framework.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use a website to enhance your voice application ]]>
                </title>
                <description>
                    <![CDATA[ By Garrett Vargas Many of the most engaging smart speaker applications extend beyond the smart speaker itself. When in Rome is an example of an Alexa game that combines voice with a traditional board game. Users navigate the globe sending voice comma... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-a-website-to-enhance-your-voice-application-c3b0000c0444/</link>
                <guid isPermaLink="false">66c355827ef110ecbf367ad0</guid>
                
                    <category>
                        <![CDATA[ Alexa Skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ aws lambda ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Feb 2019 22:29:38 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*3FLFcFDSBHj15S2A" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Garrett Vargas</p>
<p>Many of the most engaging smart speaker applications extend beyond the smart speaker itself. <a target="_blank" href="https://www.amazon.com/Voice-Originals-Travel-Trivia-Powered/dp/B07CJ43R83">When in Rome</a> is an example of an Alexa game that combines voice with a traditional board game. Users navigate the globe sending voice commands to Alexa. Alexa asks questions from people in the countries players visit. But it also plays like a board game, with a physical playing board, tokens, and cards…</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Improve Your Code With Alexa Response Interceptors ]]>
                </title>
                <description>
                    <![CDATA[ By Garrett Vargas I’ve published over a dozen Alexa skills over the last few years. I have run across several patterns and best practices in that time. One of the more powerful but under-hyped features of the SDK that I’ve made extensive use of in my... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-improve-your-code-with-alexa-response-interceptors-2b3e73721fc/</link>
                <guid isPermaLink="false">66c352cdd58e4fdd567d519e</guid>
                
                    <category>
                        <![CDATA[ Alexa ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Alexa Skills ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 27 Dec 2018 16:39:57 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*d0I7athFoo0jgOpGMLPCKg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Garrett Vargas</p>
<p>I’ve published over a dozen Alexa skills over the last few years. I have run across several patterns and best practices in that time.</p>
<p>One of the more powerful but under-hyped features of the SDK that I’ve made extensive use of in my code is the Response Interceptor. It is part of the <a target="_blank" href="https://www.npmjs.com/package/ask-sdk">Alexa Node SDK</a>. This SDK simplifies Alexa skill development.</p>
<p>When using it you may find your code getting messy with redundant error handling and clean-up tasks. Response interceptors allow you to insert a hook into the flow of handling Alexa intents. This keeps your code clean by performing last-minute actions in one central location before passing the response back to Alexa. This is extremely useful for <strong>debugging</strong>, <strong>resolving common tasks</strong>, and generally <strong>cleaning up responses</strong> to avoid some common errors encountered when using the Alexa ecosystem.</p>
<h4 id="heading-debugging">Debugging</h4>
<p>To add a response interceptor with the Alexa SDK, you pass a class that implements a <strong>process</strong> function to the addResponseInterceptors function on your SkillBuilder object as shown in the code sample below. We’ll get to the implementation details of this class in a moment.</p>
<p>This snippet also shows setting a request interceptor function which will run <em>before</em> a request is passed to your Alexa handlers. For example, I find it helps debugging to log each incoming request and the outgoing response. You can do this with the request interceptor and response interceptor as demonstrated in this code snippet. The snippet also shows the syntax for the process function returning an empty Promise.</p>
<h4 id="heading-resolving-common-tasks">Resolving Common Tasks</h4>
<p>Many of my skills process AMAZON.RepeatIntent so the user can re-hear the last response. If you have a complex skill, especially one that maintains state engines, you should provide additional detail when the user asks Alexa to repeat herself so the user knows exactly where they are. But in simpler skills, it’s fine to just replay the previous response back to the user. A response interceptor allows you to save each outgoing speech and reprompt cue so that you can re-play them easily:</p>
<p>Another common task is handling attributes. The Alexa SDK has several layers of attributes.</p>
<ul>
<li>request attributes (only good during a single request)</li>
<li>session attributes (good for the length of a session)</li>
<li>persistent attributes (saved in a store like DynamoDB to be used across sessions).</li>
</ul>
<p>I find juggling all of these can be overwhelming. I structured my code to only use session attributes, which I save to persistent storage at the end of the session. But there are two problems with this as a blanket approach — there are attributes that you may not want to save and there are times you want a value to pass between handlers but not across the session (what request attributes aim to solve).</p>
<p>I get around these problems by using a <strong>session</strong> and <strong>request</strong> object off my attributes. You can see an example of the session field in the above code snippet saving lastResponse and lastReprompt. I don’t want to save these persistently, so I clear this entire object before persisting to storage at the end of the session. In a similar fashion, I clear the request object each time at the end of my response interceptor, so those attributes truly remain request-only.</p>
<h4 id="heading-avoiding-common-errors">Avoiding Common Errors</h4>
<p>One of the limitations that plague many developers is that responses can’t contain more than 5 audio tags. Sometimes it can be difficult to avoid this with dynamic content.</p>
<p>For example in my Blackjack skill, I play a sound for each card that is dealt. Normally not a problem. But when reading out the dealer’s hand, if they end up drawing several cards you can go over this limit. Sure, I could try to catch this when I’m generating the response, but that convolutes the code. Who’s to say whether it hits every edge case?</p>
<p>Far better to remove the excess sound effects as part of the response handler. For this skill, I just remove excess audio files from the end of the response to get the count down to 5.</p>
<p>Another problem that I’ve encountered is that you aren’t allowed to return directives along with the Dialog.Delegate directive if you are eliciting slots from the user. This can be annoying if you are handling button input or using display directives. You might have to check in multiple places before adding directives to your response to make sure you don’t clash with the Dialog.Delegate. Keep your code clean and use a responseInterceptor to filter through your directives before returning instead:</p>
<p>I hope you enjoyed these tips and see the power of using response interceptors. Let me know your own best practices and share your own tips in the comments section!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
