<?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>Forem: Harshil Agrawal</title>
    <description>The latest articles on Forem by Harshil Agrawal (@harshil1712).</description>
    <link>https://forem.com/harshil1712</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%2F124095%2Fa2c1f992-7929-49c3-bb84-25d458aa7d41.png</url>
      <title>Forem: Harshil Agrawal</title>
      <link>https://forem.com/harshil1712</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/harshil1712"/>
    <language>en</language>
    <item>
      <title>Implementing localization to your Svelte App: A step-by-step guide</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Mon, 24 Jun 2024 22:23:15 +0000</pubDate>
      <link>https://forem.com/harshil1712/implementing-localization-to-your-svelte-app-a-step-by-step-guide-4cf</link>
      <guid>https://forem.com/harshil1712/implementing-localization-to-your-svelte-app-a-step-by-step-guide-4cf</guid>
      <description>&lt;p&gt;In today's global market, making your web application accessible to a diverse audience is crucial. Localization enables apps to adapt to different languages and cultural contexts, enhancing user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tolgee.io"&gt;Tolgee&lt;/a&gt; simplifies localization with its open-source i18n tool, combining a localization platform and SDKs. It provides features like in-context translation and automatic screenshot generation, making translation easy for developers and translators. Svelte is an open-source frontend framework that compiles components into small, performant JavaScript modules.&lt;/p&gt;

&lt;p&gt;In this tutorial, you'll learn how to implement localization in your Svelte app using Tolgee. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This tutorial assumes that you have familiarity with JavaScript. Knowledge of Svelte is not required but is good to have. You will also need the following, to follow the tutorial.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js: Install &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; on your machine if you don’t already have it installed. Use a node version manager tool like &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt; to install Node.js.&lt;/li&gt;
&lt;li&gt;Tolgee account: You will be using Tolgee to implement localization. Hence, if you don’t have an account, please &lt;a href="https://app.tolgee.io/sign_up?utm_source=svelte-integration-blog"&gt;sign-up here&lt;/a&gt; to create an account.&lt;/li&gt;
&lt;li&gt;Git: Install Git for your machine. You will use Git for cloning the repo and version management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 - Setting up the Svelte App
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you will use the &lt;a href="https://github.com/harshil1712/svelte-tolgee-example"&gt;Svelte Tolgee example project&lt;/a&gt;. This project is a personal blogging website built using &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt;. If you want to create your own Svelte app, follow the official &lt;a href="https://svelte.dev/docs/introduction"&gt;Svelte documentation&lt;/a&gt;. While following the steps further down this tutorial, make sure to adapt to your app.&lt;/p&gt;

&lt;p&gt;To clone the project, run the following command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/harshil1712/svelte-tolgee-example.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, navigate into the project directory and run the following command to install the required dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;svelte-tolgee-example
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you have all the required dependencies installed, run the development server and check out the project. To start the development server, execute the following command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On your browser, navigate to &lt;code&gt;http://localhost:5137&lt;/code&gt;. You will see the sample app up and running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywvgptfod8mp0yovzpnh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywvgptfod8mp0yovzpnh.png" alt="Screenshot of the home page of the app listing two blog articles" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Getting started with Tolgee
&lt;/h2&gt;

&lt;p&gt;In the previous step you scaffolded the Svelte project. In this step you will learn how to get started with Tolgee to integrate it in your Svelte project.&lt;/p&gt;

&lt;p&gt;If you don’t have a Tolgee account, create one. After you sign-up/sign in for the first time, you will be presented with a demo project. While that is a good place to explore the platform in depth, for this tutorial, you will create a new project.&lt;/p&gt;

&lt;p&gt;To create a new project, click on the &lt;strong&gt;+ Add Project&lt;/strong&gt; button. Next, enter the name of your project in the &lt;strong&gt;Name&lt;/strong&gt; field and select the translation languages you. This tutorial implements English (en) and German (de). But you can select other languages as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t8bhj9ywkrwe9fgvc8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t8bhj9ywkrwe9fgvc8d.png" alt="Screenshot of the Projects page on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsbtelxa9znz2pju7u8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsbtelxa9znz2pju7u8s.png" alt="Screenshot of the Create Project page on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have the project setup on Tolgee, the next step is to generate the API key. This API key will allow your application to interact with the Tolgee platform. To generate the API key, select &lt;strong&gt;Integrate&lt;/strong&gt; from the left sidebar menu. Next, under the &lt;strong&gt;Choose your weapon&lt;/strong&gt; section, select &lt;strong&gt;&lt;em&gt;Svelte&lt;/em&gt;&lt;/strong&gt;. Click on the dropdown menu under the &lt;strong&gt;Select API key&lt;/strong&gt; section, and select &lt;strong&gt;&lt;em&gt;Create new +&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6q2ywp66r390nvcywo5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6q2ywp66r390nvcywo5.png" alt="Screenshot of the Integration page on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the name for your API key in the &lt;strong&gt;Description&lt;/strong&gt; field. Set the &lt;strong&gt;Expiration&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;Never expires&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For the purpose of this tutorial, the Expiration is set to Never expires. Please make sure you are following the best security practices and have set a proper expiration time for the API key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, under &lt;strong&gt;Scopes&lt;/strong&gt;, select &lt;strong&gt;&lt;em&gt;Admin&lt;/em&gt;&lt;/strong&gt;. This will give you all the permissions. Click on Save, and your API key will be generated. Scroll down to the Setup your environment (with SvelteKit) section. Copy the URL and the API Key. You will need these in the next step.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Before setting up the API key for production, carefully read and understand Scopes. You don’t want to give everyone the admin access.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcldsclkkfq11flgm4r1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcldsclkkfq11flgm4r1u.png" alt="Creating an API Key" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Integrating Tolgee in the Svelte app
&lt;/h2&gt;

&lt;p&gt;In the previous step, you configured the Tolgee platform by adding a new project and generating an API key. In this step, you will integrate Tolgee in your Svelte app.&lt;/p&gt;

&lt;p&gt;First, at the root of your project, create a &lt;code&gt;.env.development.local&lt;/code&gt; file. Paste the URL and the API key you copied in the previous step. Your file should contain the content as shown below, where &lt;code&gt;&amp;lt;YOUR_TOLGEE_API_KEY&amp;gt;&lt;/code&gt; is the API key you generated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_TOLGEE_API_URL=https://app.tolgee.io
VITE_TOLGEE_API_KEY=&amp;lt;YOUR_TOLGEE_API_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, to start using Tolgee and make use of its SDK, you need to install the Tolgee SDK for Svelte. To install this SDK, execute the following command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @tolgee/svelte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have installed the required SDK and also have the API key to connect to Tolgee. In the next step, you will initialize the Tolgee SDK for your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Initializing Tolgee for Svelte
&lt;/h2&gt;

&lt;p&gt;Tolgee comes with a &lt;a href="https://tolgee.io/js-sdk/integrations/svelte/api#tolgeeprovider"&gt;provider component&lt;/a&gt;. This component provides the required context to all the children components it gets wrapped on. You will use this provider component to wrap all the child components with some configurations.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;src &amp;gt; routes &amp;gt; +layout.svelte&lt;/code&gt; file and paste the following code under the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. This line of code imports the required methods from the Tolgee SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TolgeeProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tolgee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DevTools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormatSimple&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, to configure Tolgee, add the following code under the import statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tolgee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tolgee&lt;/span&gt;&lt;span class="p"&gt;()&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="nc"&gt;DevTools&lt;/span&gt;&lt;span class="p"&gt;())&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="nc"&gt;FormatSimple&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;availableLanguages&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;en&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;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;VITE_TOLGEE_API_URL&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;VITE_TOLGEE_API_KEY&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;In the above code, you initialize Tolgee passing on the DevTools and FormatSimple methods. You also configure the default and available languages for your app. Lastly, you configure your Tolgee credentials.&lt;/p&gt;

&lt;p&gt;Your updated &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag should be as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Navbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Navbar.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TolgeeProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tolgee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DevTools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormatSimple&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&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;tolgee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tolgee&lt;/span&gt;&lt;span class="p"&gt;()&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="nc"&gt;DevTools&lt;/span&gt;&lt;span class="p"&gt;())&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="nc"&gt;FormatSimple&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;VITE_TOLGEE_API_URL&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;VITE_TOLGEE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;availableLanguages&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;en&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;de&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="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;Now that you have imported the provider and configured it, the next step is to wrap the children components. In your &lt;code&gt;+layout.svelte file&lt;/code&gt;, update the HTML code as follows.&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;TolgeeProvider&lt;/span&gt; &lt;span class="na"&gt;tolgee=&lt;/span&gt;&lt;span class="s"&gt;"{tolgee}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"fallback"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"min-h-screen bg-gray-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Navbar&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto px-4 py-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/TolgeeProvider&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, you wrap the children components under the &lt;code&gt;&amp;lt;TolgeeProvider&amp;gt;&lt;/code&gt; component. You pass the &lt;code&gt;tolgee&lt;/code&gt; configuration and add a fallback component. While the translation gets loaded, the user will see this fallback component. You can modify this fallback component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Implementing localization
&lt;/h2&gt;

&lt;p&gt;In the previous step, you have initialized Tolgee. In this step, you will learn to implement localization using Tolgee. You will update the navigation bar option elements. These elements will render the localized content for the selected language.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;src &amp;gt; components &amp;gt; Navbar.svelte&lt;/code&gt; file, import the &lt;a href="https://tolgee.io/js-sdk/integrations/svelte/api#t-component"&gt;T component (Translation component)&lt;/a&gt; from the Tolgee SDK. Paste the following code in the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, replace the text for anchor tag with &lt;code&gt;&amp;lt;T keyName=”navbar_&amp;lt;VALUE&amp;gt;” defaultValue=”&amp;lt;VALUE&amp;gt;”/&amp;gt;&lt;/code&gt;. Here, &lt;code&gt;&amp;lt;VALUE&amp;gt;&lt;/code&gt; is the title of the page. The &lt;code&gt;T&lt;/code&gt; component takes &lt;code&gt;keyName&lt;/code&gt; and &lt;code&gt;defaultValue&lt;/code&gt; as parameters. The keyName parameter helps to identify the content. For each unique translating content, its value should be unique. The &lt;code&gt;defaultValue&lt;/code&gt; parameter takes the value that should be rendered by default. Your &lt;code&gt;+Navbar.svelte&lt;/code&gt; file should be as follows.&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&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white shadow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto px-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-between items-center py-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-semibold text-gray-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My Blog&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"space-x-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_home"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_about"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"About"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_contact"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"Contact"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the development server by executing the following command and navigate to &lt;code&gt;http://localhost:5137&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the features of Tolgee is in-context translation. In the previous step, you configured the Dev Tools provided by the Tolgee SDK. Press and hold the Option/ALT key on your keyboard and hover over the title. You will observe a red border around the title. If you click on the title holding the Option/ALT key, a Quick Translation window pops up. This is where you can add translation and screenshots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9topy4upbthicgptcfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9topy4upbthicgptcfi.png" alt="Screenshot of the Svelte app with a red outline on Home" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 - Using in-context Translation
&lt;/h2&gt;

&lt;p&gt;In the previous step, you implemented the &lt;code&gt;T&lt;/code&gt; component. This enabled you to use in-context translation for your app. In this step, you will use in context translation to add translation.&lt;/p&gt;

&lt;p&gt;To get started with in-context translation, press and hold the &lt;strong&gt;Option/ALT&lt;/strong&gt; key and click on &lt;strong&gt;Home&lt;/strong&gt;. It will open up a pop window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbrp5w3joz3ttnglzl59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbrp5w3joz3ttnglzl59.png" alt="Screenshot of the Translation pop-up window" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the English blog title in the &lt;strong&gt;English&lt;/strong&gt; field. Add the German translation of the title in the &lt;strong&gt;German&lt;/strong&gt; field. Optionally, you can add screenshots in the Screenshot section. Click on &lt;strong&gt;Save&lt;/strong&gt; to save your translation.&lt;/p&gt;

&lt;p&gt;You can view this translation on the Tolgee platform. You can also modify it via the platform or via in-context translation option.&lt;/p&gt;

&lt;p&gt;There might be scenarios where you want to use the platform to manage translations. In the next step, you will learn how to add translation on the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7 - Manage Translation on the Platform
&lt;/h2&gt;

&lt;p&gt;To use the platform to manage translation, make sure you are logged into the platform. Next, navigate to the project you created for this application. Click on &lt;strong&gt;Translations&lt;/strong&gt; from the left sidebar. You will see the translation for Home is already available there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxngt4ym4aryomtr449z6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxngt4ym4aryomtr449z6.png" alt="Screenshot showing the new created naviation_home key on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add translation for the About option, click on + on the right corner. Enter &lt;code&gt;navigation_about&lt;/code&gt; in the &lt;strong&gt;Key field&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The key must be unique. It should match the value you pass to the T component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enter the English translation in the &lt;strong&gt;English&lt;/strong&gt; field and click on &lt;strong&gt;Save&lt;/strong&gt;. This will generate the key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0h57coqkq3ern85pg72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0h57coqkq3ern85pg72.png" alt="Screenshot of the Create new key window on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add the German translation for this key, click on &lt;strong&gt;German&lt;/strong&gt; under &lt;strong&gt;navigation_about&lt;/strong&gt;. Tolgee uses various APIs to provide the translations. You can use one of the provided translations or add your own. To use the translation that Tolgee provides, select one of the translations from the &lt;strong&gt;Machine Translation&lt;/strong&gt; section. Click on &lt;strong&gt;Save&lt;/strong&gt;, to save the translation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w6qugeyxt3dot9d4or2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4w6qugeyxt3dot9d4or2.png" alt="Screenshot of the adding German translation for the navigation_about key window on the Tolgee platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have translations for Home and About. However, you can’t really view them in your app without changing the language. In the next step, you will add a language switcher for your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8 - Adding a Language Switcher
&lt;/h2&gt;

&lt;p&gt;Irrespective of where the user is based, you should give the user an option to view the content in the language of their choice. Adding a language switcher to your app can help the user select the language from available choices. In this step, you will add a language switcher.&lt;/p&gt;

&lt;p&gt;To add a language switcher, open the &lt;code&gt;Navbar.svelte&lt;/code&gt; file and update the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTolgee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTolgeeContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tolgee&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTolgeeContext&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;availableLanguages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tolgee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInitialOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;availableLanguages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, you import the required methods. You get the reference to the Tolgee instance you configured in Step 4. Next, you get the list of all the configured available languages for your app. You will use this list to provide options to the users.&lt;/p&gt;

&lt;p&gt;You also need to add a function that listens to the change of language. Paste the following in the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to add this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTolgee&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&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="nf"&gt;handleLanguageChange&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&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;currentTarget&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above subscription function listens for the change in language. When the language changes, it gets updated and the respective translated content is displayed to the user.&lt;/p&gt;

&lt;p&gt;The last step is to show the user a switch component. To add this component, paste the following code under the &lt;code&gt;&amp;lt;div id=”switch”&amp;gt;&lt;/code&gt; tag.&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;select&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{$t.getLanguage()}"&lt;/span&gt; &lt;span class="na"&gt;on:change=&lt;/span&gt;&lt;span class="s"&gt;"{handleLanguageChange}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {#each availableLanguages as lan}
  &lt;span class="nt"&gt;&amp;lt;option&amp;gt;&lt;/span&gt;{lan}&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  {/each}
&lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your finished &lt;code&gt;Navbar.svelte&lt;/code&gt; file should have the following code.&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&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTolgee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTolgeeContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tolgee/svelte&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tolgee&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTolgeeContext&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;availableLanguages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tolgee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInitialOptions&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;availableLanguages&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getTolgee&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&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="nf"&gt;handleLanguageChange&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&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;currentTarget&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="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white shadow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container mx-auto px-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-between items-center py-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-semibold text-gray-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My Blog&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"space-x-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_home"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_about"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"About"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 hover:text-gray-900"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&amp;lt;T&lt;/span&gt; &lt;span class="na"&gt;keyName=&lt;/span&gt;&lt;span class="s"&gt;"navigation_contact"&lt;/span&gt; &lt;span class="na"&gt;defaultValue=&lt;/span&gt;&lt;span class="s"&gt;"Contact"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&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;"switch"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{$t.getLanguage()}"&lt;/span&gt; &lt;span class="na"&gt;on:change=&lt;/span&gt;&lt;span class="s"&gt;"{handleLanguageChange}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          {#each availableLanguages as lan}
          &lt;span class="nt"&gt;&amp;lt;option&amp;gt;&lt;/span&gt;{lan}&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
          {/each}
        &lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file with the updated code. Start the development server, if it is not running already. The navigation bar should have a language switcher. Try changing the language, and you should see the respective translated content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec7ie1o8f8mzxrdrxj15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fec7ie1o8f8mzxrdrxj15.png" alt="Screenshot of the Svelte app with English language selected with the language switcher" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr60b7g5efxjoqd4wicb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr60b7g5efxjoqd4wicb.png" alt="Screenshot of the Svelte app with German language selected with the language switcher" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you have successfully implemented localization to your Svelte app using Tolgee.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Tolgee allows you to seamlessly implement localization to your app. It provides features like in-context translation and SDK that makes it easy for your team to manage translations.&lt;/p&gt;

&lt;p&gt;In this article, you learned about Tolgee and how to integrate it with Svelte. You implemented localization to the navigation bar. Which means, you only scratched the surface! The next step is to implement localization to the rest of your application.&lt;/p&gt;

&lt;p&gt;If you ran into issues while following this tutorial, feel free to hit me up on &lt;a href="http://linkedin.com/in/harshil1712"&gt;LinkedIn&lt;/a&gt;/&lt;a href="http://x.com/harshil1712"&gt;X (formerly Twitter)&lt;/a&gt;. I would be happy to help you. If you have more questions about Tolgee, I encourage you to join the official &lt;a href="https://Tolg.ee/slack"&gt;Slack workspace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am looking forward to seeing your localized apps!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>i18n</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Airtable automation: How I streamlined submissions to the Developer Showcase</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Thu, 13 Oct 2022 14:28:58 +0000</pubDate>
      <link>https://forem.com/contentful/airtable-automation-how-i-streamlined-submissions-to-the-developer-showcase-d40</link>
      <guid>https://forem.com/contentful/airtable-automation-how-i-streamlined-submissions-to-the-developer-showcase-d40</guid>
      <description>&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This post was &lt;a href="https://www.contentful.com/blog/2022/10/13/airtable-automation-developer-showcase-submissions/" rel="noopener noreferrer"&gt;first published&lt;/a&gt; on the Contentful Blog.&lt;/p&gt;

&lt;p&gt;In April 2022, we launched the &lt;a href="https://www.contentful.com/developers/showcase" rel="noopener noreferrer"&gt;Developer Showcase&lt;/a&gt; to highlight the work of the community. Developers share their projects, apps, videos, or blog posts they’ve created around Contentful. The developer showcase has become the go-to place to see what others are building and get inspired!&lt;/p&gt;

&lt;p&gt;If you’ve worked on a project that you believe can help the community, you can go to the Developer Showcase page, and submit the &lt;a href="https://www.contentful.com/developers/showcase/submit/" rel="noopener noreferrer"&gt;form&lt;/a&gt;. If your project meets the criteria, you get an email from us for the next step. In this step, you share more information about the project and yourself. This information is then used on the Developer Showcase page.&lt;/p&gt;

&lt;p&gt;The process seems straightforward, but there are a lot of repetitive tasks that are being performed behind the scenes. In this tutorial, I’ll share how automated processes using Airtable and a few other integrations  got myself some time back!&lt;/p&gt;

&lt;h2&gt;
  
  
  The manual process and challenges
&lt;/h2&gt;

&lt;p&gt;As mentioned above, if a developer is interested in adding their project to the showcase, they submit a form on the website with initial details. Once the form is submitted, the developer relations (DevRel) team gets a notification over email with the submission details. We then manually enter the details into a Google Sheet.&lt;/p&gt;

&lt;p&gt;Imagine, getting submissions every day, and you have to fill out entries in the Google Sheet manually! Yes, data entry is monotonous and time-consuming. I knew it could be automated and save us time.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ntlwddqrkb8yxo0wa5b.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ntlwddqrkb8yxo0wa5b.png" alt="Stickman Submit Entry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the details were entered in the Google Sheet, team members would review the submissions weekly. We’d check and decide if the submissions met the criteria. If the submission was a good fit, the developer would receive an email from us asking them to fill out another form with more details. The information shared via this form would get added to a Contentful space, which was being used to manage the content on the Developer Showcase page (yes, we use Contentful at Contentful!).&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh03hbv8wzqx233mrxn4.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh03hbv8wzqx233mrxn4.png" alt="Stickman Contentful"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above process was also manual. We had to manually add the relevant information shared via the form to the Contentful space. This again cost us time. I recognized this as another task that could be automated.&lt;/p&gt;

&lt;p&gt;Both the tasks were manual, which meant that the chances of human error were high. There were situations where I would enter the information in the wrong columns when I was in a hurry. This was also becoming monotonous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating the boring parts
&lt;/h2&gt;

&lt;p&gt;I take pride in being lazy! My laziness helps me find solutions that make my tasks joyful. Now that I recognized two tasks that could be automated, I started looking for solutions.&lt;/p&gt;

&lt;p&gt;My first step was to migrate to a spreadsheet-like tool that provided better features than Google Sheets. I was looking for a tool that would allow me to easily create automation workflows, configure different views, and also have an easy-to-use API.  &lt;/p&gt;

&lt;p&gt;Luckily for me, we already use &lt;a href="https://airtable.com/" rel="noopener noreferrer"&gt;Airtable&lt;/a&gt; at Contentful for various projects. I created a base in Airtable for the Developer Showcase which would contain all the details — from the initial form submission details to the final details.&lt;/p&gt;

&lt;p&gt;Everyone in the DevRel team is involved in the showcase. All of us decide if a submission should be added to the Developer Showcase. We handle this by voting. For every member of the team, I created a view that would list all the submissions that they haven’t viewed. Having an individual view made it easy for my team to go in, view the project, leave their thoughts, and vote. It hardly takes them 15 minutes now!&lt;/p&gt;

&lt;p&gt;The migration to Airtable also involved creating automation to handle the form submissions. After setting up the table and the individual views, I created an automation workflow in &lt;a href="https://zapier.com/" rel="noopener noreferrer"&gt;Zapier&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This workflow would get triggered whenever there was a submission made to the Developer Showcase form. The workflow would then add the new record to the Airtable base, and also send a Slack message to notify us. All I had to do now was to check if the submission was valid and if it was, update the Valid column in Airtable.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw78rjuubvnzevq99fa6n.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw78rjuubvnzevq99fa6n.png" alt="Zapier"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above workflow replaced the manual labor of entering the data into Google Sheets. The first task was now automated!&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Airtable to Contentful
&lt;/h2&gt;

&lt;p&gt;The other time-consuming task was entering the final details of the submissions to Contentful, and I wanted to automate it next. Now that we were using Airtable to manage the data, I re-created the template for the final submission form in Airtable. This enabled us to capture the data in Airtable itself. Whenever a developer submitted this form with the details, it now got saved in Airtable. There was no need to create an automation workflow to handle it!&lt;/p&gt;

&lt;p&gt;The data from the final form submission was in Airtable, and not Contentful, yet. To get this data added automatically to Contentful, I created a workflow in Airtable. If you’re using Airtable, you might know that Airtable doesn’t have webhooks (at the time of writing this article). This means that whenever data is created or updated, you can’t trigger external events. &lt;/p&gt;

&lt;p&gt;To overcome this, you can either create automation workflows that run at a certain interval of time, or check for new data and then process that data. A better and faster solution is to use automation within Airtable. It allows you to trigger actions when data is entered or updated.&lt;/p&gt;

&lt;p&gt;I created a workflow in Airtable to handle the above scenario. Every time a developer submitted the final form, this workflow would get triggered. It is out of the scope of this article to walk you through all the steps of creating the automation workflow. But, below I’m sharing the code snippet that populates Contentful with the data.&lt;/p&gt;

&lt;p&gt;Once the form is submitted, the workflow gets triggered. The next step is to create an action that will add the content to Contentful. Airtable doesn’t have an in-built action for Contentful, so there isn’t a no-code or even a low-code solution available just yet. However, it has an action that allows you to run custom JavaScript code. &lt;/p&gt;

&lt;p&gt;While working with this action, I learned that you can’t import npm packages. Hence, using the Contentful Management JavaScript SDK was not possible. Fortunately, Contentful has a REST API to interact with the &lt;a href="https://www.contentful.com/developers/docs/references/content-management-api/" rel="noopener noreferrer"&gt;Management API&lt;/a&gt;! I wrote the following code in the “Run a Script” action. This script populated the Contentful space with the data from Airtable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @ts-ignore&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SPACE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;SPACE_ID&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://api.contentful.com/spaces/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SPACE_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&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;AUTHORLINK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorLink&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;AUTHOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&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;ENTRY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entry&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;linkId&lt;/span&gt; &lt;span class="o"&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;authorId&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;makeCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&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;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&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="nx"&gt;method&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="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer MANAGEMENT_TOKEN&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;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/vnd.contentful.management.v1+json&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;X-Contentful-Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt;
  &lt;span class="p"&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;checkLinkType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;github&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;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Github&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;linkedin&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;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LinkedIn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter&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;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Twitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;youtube&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;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YouTube&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Website&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addAuthorLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="k"&gt;for &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;link&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&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;linkType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkLinkType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/environments/master/entries&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;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AUTHORLINK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&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="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fields&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;internalTitle&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'s &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;linkType&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="s2"&gt;type&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;linkType&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="s2"&gt;link&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;link&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="p"&gt;}))&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;linkId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;linkId&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;addAuthor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;linkId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sys&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="s2"&gt;Link&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="s2"&gt;linkType&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="s2"&gt;Entry&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="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;link&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/environments/master/entries&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;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AUTHOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fields&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="s2"&gt;name&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorName&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="s2"&gt;bio&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="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorBio&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="s2"&gt;links&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;links&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;authorId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&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;addEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makeCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/environments/master/entries&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;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ENTRY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fields&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectTitle&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="s2"&gt;description&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectDesc&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="s2"&gt;link&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;"&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;inputConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectLink&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="s2"&gt;author&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sys&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="s2"&gt;Link&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="s2"&gt;linkType&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="s2"&gt;Entry&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="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authorId&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en-US&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sys&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="s2"&gt;Link&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="s2"&gt;linkType&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="s2"&gt;Entry&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="s2"&gt;id&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="s2"&gt;FIELD_ID&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;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;json&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&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;async &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;await&lt;/span&gt; &lt;span class="nf"&gt;addAuthorLink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;addAuthor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;addEntry&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;
  
  
  Walking through the code
&lt;/h2&gt;

&lt;p&gt;Let’s break down the code to understand what is happening. The first few lines are defining some variables that we need later in the code. This includes the space ID, URL of the Management API, content type IDs, as well as the input object from Airtable.&lt;/p&gt;

&lt;p&gt;We then define a reusable function &lt;code&gt;makeCall&lt;/code&gt; that takes the API endpoint, HTTP method, content type, and the body as the parameters. We use this function to call the Management API.&lt;/p&gt;

&lt;p&gt;An author of a Developer Showcase submission can share social links. These links are displayed on the respective author page, e.g., &lt;a href="https://www.contentful.com/developers/showcase/author/teemu-tammela/" rel="noopener noreferrer"&gt;one of our top contributors Teemu Tammela&lt;/a&gt;. To identify the type of this link, we are using the &lt;code&gt;checkLinkType&lt;/code&gt; function. It returns the type that we have configured in Contentful.&lt;/p&gt;

&lt;p&gt;Next, we define the &lt;code&gt;addAuthorLink&lt;/code&gt; function. This function creates an array of links shared by the author, gets the link type, and adds them to Contentful. It also returns an array of link IDs that get used in the &lt;code&gt;addAuthor&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;addAuthor&lt;/code&gt; function adds all the information about the author, as well as adds references to the links. The final result, a new entry of the author, is now available with references to the author’s social media accounts.&lt;/p&gt;

&lt;p&gt;Lastly, the &lt;code&gt;addEntry&lt;/code&gt; function adds the project details and references the author. Since the type of project has not been asked in the form, it is hard-coded. The type is manually updated before the entries are published.&lt;/p&gt;

&lt;p&gt;The last action in this automation workflow is sending a message on Slack. Since Airtable has an built-in app for Slack, it was straightforward to set it up!&lt;/p&gt;

&lt;p&gt;To summarize the above workflow, every time the Airtable form was submitted, the automation would be triggered. It will execute the “Run a script” action, that runs the above code and adds the content to Contentful. Once the content is successfully added, a message is sent on Slack.&lt;/p&gt;

&lt;p&gt;All we have to do now is log in to the Contentful space, review the newly created entries, add the missing assets, and publish the changes!&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;These workflows have saved us a huge amount of time! We don’t have to manually add data, and we can focus more on highlighting the amazing work the community is doing!&lt;/p&gt;

&lt;p&gt;The code currently doesn’t handle images, however. We manually have to add them to Contentful. I couldn’t find a good solution to handle images in Airtable, and I am still on the lookout. If you have worked with images in Airtable and have a solution, please let me know!&lt;/p&gt;

&lt;p&gt;There are a lot of other tasks that can be automated in the whole process. But my experience with automation has taught me one thing — start small and automate the things you do often. It has helped me not over-engineer a simple solution.&lt;/p&gt;

&lt;p&gt;Now that I have more free time, why don’t you share what you’ve created with Contentful? I would love to see it and share it with the community. Also, let me know which Developer Showcase entries you find the most interesting!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>contentful</category>
      <category>airtable</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What is TypeScript and why should you use it?</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Thu, 01 Sep 2022 10:04:30 +0000</pubDate>
      <link>https://forem.com/contentful/what-is-typescript-and-why-should-you-use-it-3bj1</link>
      <guid>https://forem.com/contentful/what-is-typescript-and-why-should-you-use-it-3bj1</guid>
      <description>&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This article originally appeared on the &lt;a href="https://www.contentful.com/blog/2022/08/18/what-is-typescript-and-why-should-you-use-it/"&gt;Contentful Blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been learning and using TypeScript for the past year for various projects, and I have been enjoying it. TypeScript provides a great developer experience, and I believe that it has increased my productivity. I don’t have to manually check for errors every time a change gets made, and the inline documentation helps me ship faster. In this article, I will give you an overview of TypeScript, share some of its features, and help you get started.&lt;/p&gt;

&lt;p&gt;Before learning about TypeScript, let’s take a step back and revisit JavaScript. Since the earliest days of the World Wide Web, JavaScript has been used to make websites interactive – handle mouse and keyboard events, validate forms, and so on. With time, the language evolved. You can now use JavaScript to build websites and apps for any platform. It can be used to code both the frontend and backend of your website/app. You can build cross-platform apps using React Native and desktop apps with Electron, and you can even use JavaScript for your next IoT project!&lt;/p&gt;

&lt;p&gt;With these extensive use cases, the complexity in the codebase increased. For smaller projects, using JavaScript is still fine. However, for larger projects, it became difficult to debug the code and catch errors.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is the difference between TypeScript and JavaScript?
&lt;/h1&gt;

&lt;p&gt;TypeScript is a superset of JavaScript. It means that TypeScript provides all the features and functionalities of JavaScript with some added features. TypeScript compiles to JavaScript, which the browser understands. TypeScript provides “type safety” (hence the name!) to JavaScript. It was created by Microsoft and is open source. If you’re interested in contributing or just going through the source code, you can find the repository on &lt;a href="https://github.com/Microsoft/TypeScript"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To understand type safety, consider an example where you define a variable name. In JavaScript, you would use a similar code as below:&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Harshil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this is a variable name and we haven’t defined its type, this variable can have any value. It doesn’t matter if it’s a string, number, boolean, or object. Hence, the below code will execute without errors:&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;

&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="nx"&gt;name&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&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Harshi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Agrawal:
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using TypeScript, you can define the type string for the variable name, as below:&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;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Harshil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you change its value to any other type, the compiler returns an error. Type safety saves a lot of debugging time and helps in keeping the code consistent.&lt;/p&gt;

&lt;h1&gt;
  
  
  Features of TypeScript
&lt;/h1&gt;

&lt;p&gt;TypeScript extends JavaScript and improves the developer experience. It enables developers to add type safety to their projects. Moreover, TypeScript provides various other features, like interfaces, type aliases, abstract classes, function overloading, tuple, generics, etc. Explaining all the features is out of the scope of this article. However, I will present two that I find useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interface
&lt;/h2&gt;

&lt;p&gt;You receive an object when you call any Contentful API. This object response contains the necessary data that you need. Similar to the Contentful API, other APIs also send an object as a response.&lt;/p&gt;

&lt;p&gt;Interfaces get used to ensure that the object contains the required data with the correct data type. This object can be a response or request body or parameters for a function.&lt;/p&gt;

&lt;p&gt;An interface has the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;interfaceName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;variableOne&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;variableTwo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;type&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 the above syntax, we can create an interface Profile with the properties name and social.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;social&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;The above interface can be used as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Profile&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Find &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; here &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;social&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is a simple example of interfaces. There are various other functionalities that interfaces provide. You can set optional properties, extend interfaces to add new properties, and more. To learn more about interfaces, refer to the &lt;a href="https://www.typescriptlang.org/docs/handbook/interfaces.html"&gt;TypeScript documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Literal Types
&lt;/h2&gt;

&lt;p&gt;Another feature that I find useful is Literal Types. Though, by themselves, they’re not so useful. But one can combine them into unions, which makes the Literal Types useful.&lt;/p&gt;

&lt;p&gt;The following example demonstrates the syntax of Literal Types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;social&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;twitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;harshil1712&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the variable social has the type “twitter.” However, this isn’t useful on its own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&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="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hey&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="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hey&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="s2"&gt;Max&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Argument of type '"Max"' is not assignable to parameter of type '"Alice" | "Bob"'.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above function, the second parameter can only take values that have the type of either “Alice” or “Bob.” This helps us in writing functions that only accept a certain set of known values. They can do much more with Literal Types. Read the &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types"&gt;official documentation&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to use TypeScript?
&lt;/h1&gt;

&lt;p&gt;Now that you have a basic understanding of what TypeScript is, in this section, you will learn how to use TypeScript.&lt;/p&gt;

&lt;p&gt;Browsers don’t understand TypeScript. They understand JavaScript code. Hence, the TypeScript code needs to get compiled into JavaScript, and for that, you need the TypeScript compiler.&lt;/p&gt;

&lt;p&gt;You can install TypeScript globally using the following npm command. The global installation allows you to run the tsc command anywhere from your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have installed TypeScript, create an index.ts file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;greeting&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code declares a variable message and creates a function that logs the message to the console. To run this code, you have to compile it to JavaScript. Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tsc index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll observe that the compiler creates an index.js file with the compiled code.&lt;/p&gt;

&lt;p&gt;The TypeScript compiler is flexible and allows you to configure options like the target JavaScript version. At the time of writing this article, the default target is es3.&lt;/p&gt;

&lt;p&gt;To configure the compiler options, you can either pass them with the CLI command or create a tsconfig.json. You can learn more about the various configuration options on the &lt;a href="https://www.typescriptlang.org/tsconfig/"&gt;TSConfig Reference documentation&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;If you want to use TypeScript in your next Contentful project, we released &lt;a href="https://www.npmjs.com/package/contentful"&gt;contentful.js&lt;/a&gt; v10 in Beta with enhanced TypeScript support. Check out the &lt;a href="https://www.contentful.com/developers/changelog/#beta-release-contentfuljs-v10-with-enhanced-typescript-support"&gt;changelog&lt;/a&gt; and let us know what you think!&lt;/p&gt;

&lt;h1&gt;
  
  
  Advantages of using TypeScript
&lt;/h1&gt;

&lt;p&gt;TypeScript extends JavaScript, providing a better developer experience. The benefits of using TypeScript over JavaScript include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Static typing – TypeScript comes with optional static typing and a type inference system, which means that a variable, declared with no type may be inferred by TypeScript based on its value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Object oriented programming – TypeScript supports object-oriented programming concepts like classes, inheritance, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compile time checks – JavaScript is an interpreted programming language. There is no compilation involved. Hence, the errors get caught during the runtime. Since TypeScript compiles into JavaScript, errors get reported during the compile time rather than the runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code editor support – IDEs or code editors like VS Code support autocomplete for a TypeScript codebase. They also provide inline documentation and highlight the errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use existing packages – You might want to use an npm package that is written in JavaScript. Since TypeScript is a superset of JavaScript, you can import and use that package. Moreover, the TypeScript community creates and maintains type definitions for popular packages that can be utilized in your project. You can learn more about it here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What is the best way to learn TypeScript?
&lt;/h1&gt;

&lt;p&gt;TypeScript comes with tons of features, and learning and implementing them all together might get overwhelming. I started learning TypeScript by refactoring my JavaScript codebase to TypeScript one line at a time. This helped me to migrate my codebase to TypeScript with minimal effort and helped me dive deeper into the concepts.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.typescriptlang.org/docs/handbook/intro.html"&gt;TypeScript Handbook&lt;/a&gt; is a great place to learn about TypeScript. It explains the concepts well and contains relevant examples. The handbook is also regularly updated with new features.&lt;/p&gt;

&lt;p&gt;There are also tutorials available that will help you with &lt;a href="https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html"&gt;migrating your JavaScript project&lt;/a&gt; to TypeScript or help you learn about &lt;a href="https://www.typescriptlang.org/docs/handbook/dom-manipulation.html"&gt;DOM manipulation&lt;/a&gt; in TypeScript.&lt;/p&gt;

&lt;p&gt;The Contentful community members have also created apps and tools that can help &lt;a href="https://github.com/marcolink/cf-content-types-generator-app"&gt;generate type declarations for your content types&lt;/a&gt; and &lt;a href="https://www.modelberry.com/"&gt;sync TypeScript with your content model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re looking for your next TypeScript project, why don’t you create an app for your Contentful space with &lt;a href="https://www.contentful.com/developers/docs/extensibility/app-framework/"&gt;App Framework&lt;/a&gt;? The boilerplate is available in TypeScript, where you can learn or brush up your TypeScript knowledge. Happy type checking!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to automatically manage contributions to open-source projects 🏷️</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 26 Nov 2021 08:05:18 +0000</pubDate>
      <link>https://forem.com/n8n/how-to-automatically-manage-contributions-to-open-source-projects-4njl</link>
      <guid>https://forem.com/n8n/how-to-automatically-manage-contributions-to-open-source-projects-4njl</guid>
      <description>&lt;p&gt;October is an exciting month, with people across the world looking forward to Halloween or Oktoberfest. But for me, I'm most excited about &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;&lt;strong&gt;Hacktoberfest&lt;/strong&gt;&lt;/a&gt;–the month-long celebration of open-source projects. DigitalOcean has been organizing this event for the past eight years with the goal of encouraging the global tech community to support open-source projects.&lt;/p&gt;

&lt;p&gt;Hacktoberfest provides a great opportunity on one side for individual developers to apply their skills on real-world projects, and on the other side for organizations to extend their projects with the help of contributors.&lt;/p&gt;

&lt;p&gt;However, the popularity of Hacktoberfest also creates spam, unnecessary pull requests, and loads of comments on GitHub issues, which can become overwhelming for the project owners and maintainers.&lt;/p&gt;

&lt;p&gt;Our solution to this problem? &lt;strong&gt;Automation&lt;/strong&gt;! In this tutorial, you will learn how to create a no-code workflow that automatically assigns an open GitHub issue to a contributor interested in working on it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Table of contents
&lt;/h4&gt;

&lt;p&gt;Prerequisites for building the workflow&lt;br&gt;&lt;br&gt;
Workflow for assigning GitHub issues to contributors&lt;br&gt;
    1. Trigger the workflow on GitHub events &lt;br&gt;
    2. Route the workflow on specific events &lt;br&gt;
    3. Handle new GitHub issues &lt;br&gt;
    4. Assign the issue&lt;br&gt;
    5. Handle new comments on GitHub issues &lt;br&gt;
    6. Check if the issue is already assigned&lt;br&gt;
    7. Assign an issue to a contributor &lt;br&gt;
    8. Add a comment to the issue&lt;br&gt;
What's next?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z8bCUKBn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/88uNfhZL9pgwWQbszoOlkwzPNWmMkW9pRJRCYYjzQyAzyyChi05EMW92UJHiQYOC-yWyc-cS882JRmgSZir7Q7qyv-rAC_Mg5qOHBEqM3deTt6w8CEZQPAJzXAAFnNA4yolG0tUD%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z8bCUKBn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/88uNfhZL9pgwWQbszoOlkwzPNWmMkW9pRJRCYYjzQyAzyyChi05EMW92UJHiQYOC-yWyc-cS882JRmgSZir7Q7qyv-rAC_Mg5qOHBEqM3deTt6w8CEZQPAJzXAAFnNA4yolG0tUD%3Ds1600" alt="Workflow for assigning GitHub issues to contributors"&gt;&lt;/a&gt;Workflow for assigning GitHub issues to contributors&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites for building the workflow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;n8n&lt;/strong&gt;: Sign up for &lt;a href="https://www.n8n.cloud/"&gt;n8n.cloud&lt;/a&gt; to quickly get started or use n8n on your own servers. Refer to the &lt;a href="https://docs.n8n.io/getting-started/installation/"&gt;installation&lt;/a&gt; guide to learn more.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GitHub account&lt;/strong&gt;: To connect the workflow with your GitHub account, follow the steps mentioned in the &lt;a href="https://docs.n8n.io/credentials/github"&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Workflow for assigning GitHub issues to contributors
&lt;/h2&gt;

&lt;p&gt;The general idea of &lt;a href="https://n8n.io/workflows/1274"&gt;this workflow&lt;/a&gt; is to assign an issue to the contributor who is interested in working on it. There are four scenarios that you need to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; A contributor creates an issue and wants to work on it.&lt;/li&gt;
&lt;li&gt; A contributor creates a new issue and doesn't want to work on it.&lt;/li&gt;
&lt;li&gt; A contributor is interested in working on an issue reported by another contributor and no one got assigned to it.&lt;/li&gt;
&lt;li&gt; A contributor is interested in working on an issue opened by another contributor, but someone else has already been assigned to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In popular open-source projects, you usually meet all these scenarios. If you're a project maintainer, you know it can become difficult to manage the contributions efficiently, especially during events like Hacktoberfest.&lt;/p&gt;

&lt;p&gt;The visual builder that n8n provides helps you classify and handle issues automatically. Let's dive into it!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Trigger the workflow on GitHub events
&lt;/h3&gt;

&lt;p&gt;The workflow should run every time someone opens a  new issue or comments on an issue. For this, add the GitHub Trigger node and configure the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Authentication:&lt;/em&gt;&lt;/strong&gt; If you're using n8n.cloud, I suggest you select the OAuth2 authentication method. This option allows you to connect the node with your GitHub account without the need to create credentials. Otherwise, you can learn how to create the credentials from our &lt;a href="https://docs.n8n.io/credentials/github"&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Repository Owner:&lt;/em&gt;&lt;/strong&gt; Enter your GitHub username.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Repository Name:&lt;/em&gt;&lt;/strong&gt; Enter the name of your repository.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Events:&lt;/em&gt;&lt;/strong&gt; Select &lt;code&gt;issue_comment&lt;/code&gt; and &lt;code&gt;issues&lt;/code&gt; from the dropdown menu.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d6y_HXr3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/1V_dcj27abNeaRXwpMZ064kBW0MP8kuIiAiFhIb1qMCy-eaR7B2Zes35bKOAZ4VNuOd2NvwyHrqLjgkP5cFS2snGGWmRIM71OiM2Cn5o7qrpnnt-gmLnilgyT80fO6JVrtobm1SK%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d6y_HXr3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/1V_dcj27abNeaRXwpMZ064kBW0MP8kuIiAiFhIb1qMCy-eaR7B2Zes35bKOAZ4VNuOd2NvwyHrqLjgkP5cFS2snGGWmRIM71OiM2Cn5o7qrpnnt-gmLnilgyT80fO6JVrtobm1SK%3Ds1600" alt="Configuration of GitHub Trigger node"&gt;&lt;/a&gt;Configuration of GitHub Trigger node&lt;/p&gt;

&lt;p&gt;Now the workflow will run when a new issue gets created, closed, or edited, or when a comment gets posted, removed, or edited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you want to use this workflow for a repository that belongs to an organization, you will have to use the Webhook Trigger node. Refer to the &lt;a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#setting-up-a-webhook"&gt;GitHub documentation&lt;/a&gt; to learn to add webhooks to your repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Route the workflow on specific events
&lt;/h3&gt;

&lt;p&gt;The workflow should continue only when a new issue gets created or a new comment gets posted. To identify these events, add a Switch node and set the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Data Type:&lt;/em&gt;&lt;/strong&gt; String&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 1:&lt;/em&gt;&lt;/strong&gt; Use the expression &lt;code&gt;{{$json["body"]["action"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on the &lt;strong&gt;&lt;em&gt;Add Routing Rules&lt;/em&gt;&lt;/strong&gt; button. For this workflow, you need two different routes, one to handle each event mentioned above.&lt;/p&gt;

&lt;p&gt;The first routing rule handles the scenario where a new issue gets created. For this, configure the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Equal&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 2:&lt;/em&gt;&lt;/strong&gt; opened&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;/strong&gt; 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second routing rule will navigate the data to output 1 of the Switch node when a new comment gets posted on an issue. For this, use the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Equal&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 2:&lt;/em&gt;&lt;/strong&gt; created&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;/strong&gt; 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1N1Dte7n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/gJ-QoHkUjrtSUQjkFzHwrQZioJbUI3Q1PPomjsT7gceWT2sEM8zGRqHnXaP53IbhquqfCLpWk6lpseyFsjBllhA-ojgv1rwwCDNhkk4vcc_IRqPZ-9hogtAYGk-1NmHnkSQakV_U%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1N1Dte7n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/gJ-QoHkUjrtSUQjkFzHwrQZioJbUI3Q1PPomjsT7gceWT2sEM8zGRqHnXaP53IbhquqfCLpWk6lpseyFsjBllhA-ojgv1rwwCDNhkk4vcc_IRqPZ-9hogtAYGk-1NmHnkSQakV_U%3Ds1600" alt="Configuration of Switch node"&gt;&lt;/a&gt;Configuration of Switch node&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Handle new GitHub issues
&lt;/h3&gt;

&lt;p&gt;Contributors who open a new issue may or may not want to contribute to it. To make sure that you assign the contributor only if they're interested in working on it, add an IF node connected to the output 0 of the Switch node.&lt;/p&gt;

&lt;p&gt;Configure the IF node as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 1:&lt;/em&gt;&lt;/strong&gt; Add the expression &lt;code&gt;{{$json["body"]["issue"]["body"]}}&lt;/code&gt; in the Expression Editor.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Regex&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Regex:&lt;/em&gt;&lt;/strong&gt; /[a,A]ssign[\w*\s*]*me/gm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above condition checks if the user wants you to assign them the issue or not.&lt;/p&gt;

&lt;p&gt;The workflow should also check if the issue has already been assigned to a contributor or not. For this, add another condition in the IF node. This condition should be of the type Number. Set the following parameters for this condition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 1:&lt;/em&gt;&lt;/strong&gt; Use the expression &lt;code&gt;{{$json["body"]["issue"]["assignees"].length}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Equal&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 2:&lt;/em&gt;&lt;/strong&gt; 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V5liS2Gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/gMLzYulOUY_QY67YusMtV3Ug5lIwNwjuS_46PnmWLsVWbzR9hiczTUMbaq0xDyGAFVO9RaWJLxUNgRC5ZYdI01TNrKErRDm0a7Sr-nC-E-RPYopBuaultdx5-zSDga7XOcXxb2wD%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V5liS2Gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/gMLzYulOUY_QY67YusMtV3Ug5lIwNwjuS_46PnmWLsVWbzR9hiczTUMbaq0xDyGAFVO9RaWJLxUNgRC5ZYdI01TNrKErRDm0a7Sr-nC-E-RPYopBuaultdx5-zSDga7XOcXxb2wD%3Ds1600" alt="Configuration of IF node for new GitHub issues"&gt;&lt;/a&gt;Configuration of IF node for new GitHub issues&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Assign the issue
&lt;/h3&gt;

&lt;p&gt;The next step is assigning the issue to the interested contributor and label the issue as &lt;code&gt;assigned&lt;/code&gt;. To do this, connect a GitHub node to the true output of the IF node and&lt;/p&gt;

&lt;p&gt;Configure the parameters of the node as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Authentication:&lt;/em&gt;&lt;/strong&gt; Use the authentication that you used in the GitHub Trigger node&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Resource:&lt;/em&gt;&lt;/strong&gt; Issue&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation&lt;/em&gt;&lt;/strong&gt;: Edit&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Repository Owner:&lt;/em&gt;&lt;/strong&gt; Enter your GitHub username or use the following expression: &lt;code&gt;{{$node["Switch"].json["body"]["repository"]["owner"]["login"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Repository Name:&lt;/em&gt;&lt;/strong&gt; Enter the name of the repository you previously used, or use the following expression: &lt;code&gt;{{$node["Switch"].json["body"]["repository"]["name"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Issue Number:&lt;/em&gt;&lt;/strong&gt; Use the expression &lt;code&gt;{{ $json["body"]["issue"]["number"] }}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on &lt;strong&gt;&lt;em&gt;Choose Option To Add&lt;/em&gt;&lt;/strong&gt;, and select &lt;em&gt;Labels&lt;/em&gt;. Similarly, add the &lt;em&gt;Assignees&lt;/em&gt; option. Configure these parameters as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;em&gt;Label:&lt;/em&gt; Enter &lt;code&gt;assigned&lt;/code&gt; or any other label you want to add to the issue.&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Assignees:&lt;/em&gt; Enter the following expression: &lt;code&gt;{{$json.body.issue["user"]["login"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FhQQP_yj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/bx_vDtHWhHYUeFfQnZLvMU9i2JLkphGcY7nY-KpXe_CutPFr8kfn5Jbki0XZf_T6z1EhXOlxC8ptTIhPdVB-CzOjTbQeFDHSaTnSsElEbhMzB4oTaquXRGuPBTfW76ElctlZ2_Hj%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FhQQP_yj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/bx_vDtHWhHYUeFfQnZLvMU9i2JLkphGcY7nY-KpXe_CutPFr8kfn5Jbki0XZf_T6z1EhXOlxC8ptTIhPdVB-CzOjTbQeFDHSaTnSsElEbhMzB4oTaquXRGuPBTfW76ElctlZ2_Hj%3Ds1600" alt="Configuration of GitHub node for issue assignment"&gt;&lt;/a&gt;Configuration of GitHub node for issue assignment&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Handle new comments on GitHub issues
&lt;/h3&gt;

&lt;p&gt;Your workflow currently handles the following situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Assigning the issue to the contributor who opened the issue if the contributor is interested in working on it&lt;/li&gt;
&lt;li&gt; Stopping the workflow if the contributor who opened the issue is not interested in working on it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You now have to design the workflow that handles the other two scenarios. For this, add an IF node connected to output 1 of the Switch node. This node will check if the contributor is interested in working on the issue. Set the following parameters for the IF node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 1:&lt;/em&gt;&lt;/strong&gt; Use the expression &lt;code&gt;{{$json["body"]["comment"]["body"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Regex&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Regex:&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;/[a,A]ssign[\w*\s*]*me/gm&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sm76CC-1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/UO42hKRGCuOaa2UJJzBHkvDdec-kkGlkC6BG0SUM4E5ApReED_UP_1yVRQ1WBHTfhIPmpg6kcWjKVcB6Yg_aWBfGIEPrtO_onM8HpOPqkHd2sAFZ6tbqrmv_m_JwzI7eQi-7cDSQ%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sm76CC-1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/UO42hKRGCuOaa2UJJzBHkvDdec-kkGlkC6BG0SUM4E5ApReED_UP_1yVRQ1WBHTfhIPmpg6kcWjKVcB6Yg_aWBfGIEPrtO_onM8HpOPqkHd2sAFZ6tbqrmv_m_JwzI7eQi-7cDSQ%3Ds1600" alt="Configuration of IF node for interested contributors"&gt;&lt;/a&gt;Configuration of IF node for interested contributors&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Check if the issue is already assigned
&lt;/h3&gt;

&lt;p&gt;If a contributor is interested in working on an issue, the workflow should assign them to the issue, but it should also check if someone has previously been assigned to the issue or not. To check this, connect an IF node to the true output of the previous IF node. Set the IF node as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 1:&lt;/em&gt;&lt;/strong&gt; Enter the expression &lt;code&gt;{{$json["body"]["issue"]["assignees"].length}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Equal&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Value 2:&lt;/em&gt;&lt;/strong&gt; 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If no one is assigned to the issue, this node returns true, otherwise false.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h31L89xC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/XBawrwEP-EgWXjv4j2NDFUbfsmNVZmNYfvc0VuzODxxs_dBJ_G-vUrBUFcgXWXjn6fqFAkdTaNnY4jn5DebNYwHQ9kyrywH5on44IYIJppwiRm8-ZlApiFUTODXcI2VLaqBpzaP4%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h31L89xC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/XBawrwEP-EgWXjv4j2NDFUbfsmNVZmNYfvc0VuzODxxs_dBJ_G-vUrBUFcgXWXjn6fqFAkdTaNnY4jn5DebNYwHQ9kyrywH5on44IYIJppwiRm8-ZlApiFUTODXcI2VLaqBpzaP4%3Ds1600" alt="Configuration of IF node for assigned issues"&gt;&lt;/a&gt;Configuration of IF node for assigned issues&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Assign an issue to a contributor
&lt;/h3&gt;

&lt;p&gt;To assign available issues to an interested contributor, connect a GitHub node to the true branch of the previous IF node.&lt;/p&gt;

&lt;p&gt;Configure the parameters similarly to the previous GitHub node. In the &lt;strong&gt;&lt;em&gt;Assignees&lt;/em&gt;&lt;/strong&gt; fields, use the expression &lt;code&gt;{{$json["body"]["comment"]["user"]["login"]}}&lt;/code&gt;. The rest of the parameters should stay the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Add a comment to the issue
&lt;/h3&gt;

&lt;p&gt;If the issue has already been assigned to a contributor, you should the interested contributor know about it. For this, connect a new GitHub node to the false branch of the IF node. This node will add a comment to the issue.&lt;/p&gt;

&lt;p&gt;Set the node parameters as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Authentication:&lt;/em&gt;&lt;/strong&gt; Similar to the previous GitHub node&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Resource:&lt;/em&gt;&lt;/strong&gt; Issue&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Operation:&lt;/em&gt;&lt;/strong&gt; Create Comment&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Repository Owner&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Repository Name&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;Issue Number:&lt;/em&gt;&lt;/strong&gt; Similar to the previous GitHub node&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;em&gt;Body:&lt;/em&gt;&lt;/strong&gt; Enter the comment body in this field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6_okXYh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/Xw_WTysQ2JqGR6IepryBP9OM8oLBe7XDEzrPXGclgGYchpd38frV1xoKtxGEMHsZQVXGsPBHeDKjp_n_pF0U8FMDFJK9ddRH4zDio3qHeUObSxTk8cFri2WolUHxZXUXVxEdn82T%3Ds1600" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6_okXYh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/Xw_WTysQ2JqGR6IepryBP9OM8oLBe7XDEzrPXGclgGYchpd38frV1xoKtxGEMHsZQVXGsPBHeDKjp_n_pF0U8FMDFJK9ddRH4zDio3qHeUObSxTk8cFri2WolUHxZXUXVxEdn82T%3Ds1600" alt="Configuration of GitHub node for commenting on issues"&gt;&lt;/a&gt;Configuration of GitHub node for commenting on issues&lt;/p&gt;

&lt;p&gt;This is the last node in the workflow. Now you only need to activate the workflow by clicking on the toggle in the top right corner of the Editor UI. The active workflow will run automatically in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;In this article, you learned to create a no-code workflow that automatically assigns GitHub issues to interested contributors. This kind of automation will help you and our organization maintain your open-source projects–just in time for Hacktoberfest!&lt;/p&gt;

&lt;p&gt;Here's what you can do next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Build more workflows:&lt;/strong&gt; There are many other possible automation workflows that could improve your work as a project maintainer and the experience for your contributors. For example, you can build a workflow that checks the progress on an assigned issue to  see if the contributor needs help.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Contribute to n8n:&lt;/strong&gt; You can work on &lt;a href="https://github.com/n8n-io/n8n/issues"&gt;open issues&lt;/a&gt;, &lt;a href="https://docs.n8n.io/nodes/creating-nodes/create-node.html#prerequisites"&gt;create nodes&lt;/a&gt;, &lt;a href="https://github.com/n8n-io/n8n-docs/blob/master/CONTRIBUTING.md"&gt;improve our docs&lt;/a&gt;, or &lt;a href="https://docs.n8n.io/reference/contributing.html#write-a-blogpost-%E2%9C%8D%EF%B8%8F"&gt;write a blog post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Read more tutorials:&lt;/strong&gt; Learn how to build workflows for other automation use cases, for example a no-code &lt;a href="https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/"&gt;CI/CD pipeline with GitHub and TravisCI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd like to know how you are using automation to manage your open-source projects! Feel free to message me on &lt;a href="https://twitter.com/harshil1712"&gt;Twitter&lt;/a&gt; or discuss in the &lt;a href="https://community.n8n.io/c/docs-and-tutorials/6"&gt;community forum&lt;/a&gt; 🧡 And if you want to get the latest content on automation, &lt;a href="https://n8n.io/blog/#subscribe"&gt;subscribe to our newsletter&lt;/a&gt; 💌&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://n8n.io/blog/automation-for-maintainers-of-open-source-projects/"&gt;post&lt;/a&gt; originally appeared on the n8n.io &lt;a href="https://n8n.io/blog"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>tutorial</category>
      <category>github</category>
      <category>hacktoberfest</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Creating triggers for n8n workflows using polling ⏲</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Thu, 14 Jan 2021 12:35:39 +0000</pubDate>
      <link>https://forem.com/n8n/creating-triggers-for-n8n-workflows-using-polling-17kf</link>
      <guid>https://forem.com/n8n/creating-triggers-for-n8n-workflows-using-polling-17kf</guid>
      <description>&lt;p&gt;One of the key features of n8n is the ability to use &lt;a href="https://docs.n8n.io/nodes/node-basics.html#trigger-nodes" rel="noopener noreferrer"&gt;Trigger nodes&lt;/a&gt;. Trigger nodes are special nodes that listen for events and then start a workflow. For example, you can build a workflow using the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.clickUpTrigger/#clickup-trigger" rel="noopener noreferrer"&gt;&lt;em&gt;ClickUp Trigger&lt;/em&gt;&lt;/a&gt; node and a &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.googleSheets/#google-sheets" rel="noopener noreferrer"&gt;&lt;em&gt;Google Sheets&lt;/em&gt;&lt;/a&gt; node. Whenever a new task gets created in ClickUp, the workflow would execute, and the data gets added to the Google Sheet. This makes Trigger nodes extremely useful, as you can monitor events across different services using them.&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%2AG02tszmJsR5GNk5agiXtEw.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%2AG02tszmJsR5GNk5agiXtEw.jpeg"&gt;&lt;/a&gt;Creating triggers for n8n workflows using polling&lt;/p&gt;

&lt;p&gt;Once you start using several of these different Trigger nodes, you wonder what happens when you want to listen for an event from a service that does not have a Trigger node. For example, Google Sheets and Twitter (at the time of writing this tutorial — &lt;code&gt;n8n@0.101.0&lt;/code&gt;) don’t have a Trigger node.&lt;/p&gt;

&lt;p&gt;In this article, we are going to discuss how you can monitor changes and execute workflows for services that do not support &lt;a href="https://docs.n8n.io/reference/glossary.html#webhook" rel="noopener noreferrer"&gt;webhooks&lt;/a&gt; and don’t have Trigger nodes in n8n.&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%2F0%2AAkQAL3ma93L9lZ4X" 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%2AAkQAL3ma93L9lZ4X" alt="Monitoring changes in Google Sheets every 45 mins"&gt;&lt;/a&gt;Monitoring changes in Google Sheets every 45 mins&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to polling
&lt;/h3&gt;

&lt;p&gt;In a conventional n8n Trigger node, the node listens for events using a webhook. In this method, the service sends an update to the Trigger node when an event occurs. While polling works by periodically checking for new data by connecting to the server.&lt;/p&gt;

&lt;p&gt;In this process, n8n will connect to the server every X time (every second/minute, etc) and check if there is any new data.&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%2F0%2AuYi8hOzlzeRg3dpw" 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%2AuYi8hOzlzeRg3dpw" alt="Difference between polling and webhook"&gt;&lt;/a&gt;Difference between polling and webhook&lt;/p&gt;

&lt;p&gt;Not every platform supports sending updates via a webhook and this is where polling comes to the rescue. Using polling we can check for updates and execute our workflow if data gets added or updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to poll using n8n?
&lt;/h3&gt;

&lt;p&gt;If you break down the polling process, as described in the image above, you realize that it is possible to replicate the same functionality in n8n. The &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.interval/#interval" rel="noopener noreferrer"&gt;&lt;em&gt;Interval&lt;/em&gt;&lt;/a&gt; node or the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.cron/#cron" rel="noopener noreferrer"&gt;&lt;em&gt;Cron&lt;/em&gt;&lt;/a&gt; node triggers the workflow periodically to fetch data from a service. We pass this data to the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.function/" rel="noopener noreferrer"&gt;&lt;em&gt;Function&lt;/em&gt;&lt;/a&gt; node, where all the magic happens.&lt;/p&gt;

&lt;p&gt;In n8n, the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.function/#method-getworkflowstaticdata-type" rel="noopener noreferrer"&gt;getWorkflowStaticData()&lt;/a&gt; method allows access to the static workflow data. We can save the data directly with the workflow, but this data has to be small. On every execution, the Function node compares the incoming data with the data from the previous execution. If the data got changed, we pass it to the next node in the workflow. We also update the static data with this new data so that the next execution knows what data gets stored in the previous node. If the data did not get changed, you may return a message based on our use-case.&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%2F0%2ALyV9p3fJq5f5aHEP" 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%2ALyV9p3fJq5f5aHEP" alt="Polling in n8n"&gt;&lt;/a&gt;Polling in n8n&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger a workflow when new data gets added to your Google Sheets
&lt;/h3&gt;

&lt;p&gt;I wanted to run a workflow every time there was new data added in Google Sheets, so I created a polling workflow. Follow along the steps mentioned below to learn to create a polling workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Set up n8n
&lt;/h4&gt;

&lt;p&gt;Follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/getting-started/quickstart.html#quickstart" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to install and spin-up an n8n instance on your machine. You can also sign-up for &lt;a href="https://n8n.io/cloud" rel="noopener noreferrer"&gt;n8n.cloud&lt;/a&gt; to get access to our hosted service.&lt;/p&gt;

&lt;h4&gt;
  
  
  Set up a Google Sheet
&lt;/h4&gt;

&lt;p&gt;Create a Google Sheet like &lt;a href="https://docs.google.com/spreadsheets/d/1PyC-U1lXSCbxVmHuwFbkKDF9e3PW_iUn8T-iAd_MYjQ/edit?usp=sharing" rel="noopener noreferrer"&gt;this Google Sheet&lt;/a&gt;. We will monitor this sheet for new data that gets added. Feel free to make a copy of my Sheet.&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%2F0%2AZ0KpvBzTdDEYWb5u" 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%2AZ0KpvBzTdDEYWb5u" alt="Google Sheet used in this tutorial"&gt;&lt;/a&gt;Google Sheet used in this tutorial&lt;/p&gt;

&lt;p&gt;We will also need to configure credentials for the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.googleSheets/#google-sheets" rel="noopener noreferrer"&gt;&lt;em&gt;Google Sheets&lt;/em&gt;&lt;/a&gt; node. For this tutorial, we will use the OAuth authentication method. You can learn to configure the OAuth credentials by following the steps mentioned in the &lt;a href="https://docs.n8n.io/credentials/google/#using-oauth" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Set up Mattermost
&lt;/h4&gt;

&lt;p&gt;We will send a message to a channel in a Mattermost team if new data gets added. Create a Mattermost team if you don’t have one already.&lt;/p&gt;

&lt;p&gt;You will also have to configure the credentials for the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.mattermost" rel="noopener noreferrer"&gt;&lt;em&gt;Mattermost&lt;/em&gt;&lt;/a&gt; node. Follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/credentials/mattermost/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to configure the credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;If you don’t want to get into the details and have experience building workflows in n8n, you can follow the quick-start instructions below. If something is unclear or you want to learn more about how it works, feel free to dig deeper into the sections that follow.&lt;/p&gt;

&lt;p&gt;Access your n8n instance, and copy and paste the workflow from the &lt;a href="https://n8n.io/workflows/864" rel="noopener noreferrer"&gt;workflow&lt;/a&gt; page. Configure the following nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Google Sheets node&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Use the credentials that you configured earlier.&lt;/li&gt;
&lt;li&gt;Enter the Sheet ID of your Sheet in the &lt;strong&gt;&lt;em&gt;Sheet ID&lt;/em&gt;&lt;/strong&gt; field. If you’re not sure how to find the Sheet ID, refer to the section Google Sheets section below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : If you change a column name in your Google Sheet, make sure to configure the &lt;em&gt;Function&lt;/em&gt; node accordingly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Mattermost node&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Use the credentials that you configured earlier.&lt;/li&gt;
&lt;li&gt;If you’re not the system administrator, enter the channel ID where you want the app to send the message in the &lt;strong&gt;&lt;em&gt;Channel ID&lt;/em&gt;&lt;/strong&gt; field. Otherwise, select the channel from the &lt;strong&gt;&lt;em&gt;Channel ID&lt;/em&gt;&lt;/strong&gt; dropdown list. Refer to the Mattermost section below, to learn more about the steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save and execute the workflow!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Activate the workflow to run it in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Workflow
&lt;/h3&gt;

&lt;p&gt;This workflow can be divided into three stages, as it progresses from start to finish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read Data&lt;/li&gt;
&lt;li&gt;Extract New Data&lt;/li&gt;
&lt;li&gt;Communication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stage 1 — Read Data
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Interval node (Execute every 45 mins)
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Interval&lt;/em&gt; node triggers the workflow at a regular interval of time. For this tutorial, we want to execute the workflow every 45 minutes.&lt;/p&gt;

&lt;p&gt;Click on the ‘ &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; ’ button on the top right corner and click on the &lt;strong&gt;&lt;em&gt;Trigger&lt;/em&gt;&lt;/strong&gt; tab. Select the &lt;em&gt;Interval&lt;/em&gt; node from the list to add the node.&lt;/p&gt;

&lt;p&gt;Select ‘Minutes’ from the &lt;strong&gt;&lt;em&gt;Unit&lt;/em&gt;&lt;/strong&gt; dropdown list and set the value of &lt;strong&gt;&lt;em&gt;Interval&lt;/em&gt;&lt;/strong&gt; to 45.&lt;/p&gt;

&lt;p&gt;Rename the node’s headline from “Interval” to “Execute every 45 mins” by clicking the name, editing it, and clicking the ✔ (checkmark) to the right of the name. This will finish the configuration of the node and close the parameters window. Select ‘Save As’ from the &lt;strong&gt;&lt;em&gt;Workflow&lt;/em&gt;&lt;/strong&gt; menu on the left sidebar. Once you save the workflow, click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; button to execute the node.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Google Sheets node (Read data)
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Google Sheets&lt;/em&gt; node in n8n allows you to create new sheets and read, lookup, append, delete, and update data from a sheet. Our workflow will read the data from a Google Sheet every 45 minutes.&lt;/p&gt;

&lt;p&gt;To add the &lt;em&gt;Google Sheets&lt;/em&gt; node, click on the ‘ &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; ’ button, and select the &lt;em&gt;Google Sheets&lt;/em&gt; node from the &lt;strong&gt;&lt;em&gt;Regular&lt;/em&gt;&lt;/strong&gt; section. Use the credentials that you configured earlier.&lt;/p&gt;

&lt;p&gt;Copy the string of characters located between /d/ and /edit in your spreadsheet URL. This string is the Sheet ID. For example, for the URL &lt;a href="https://docs.google.com/spreadsheets/d/1PyCgaglXSCbxVmHuwFbkKDF9e3PW%5C_iUn8T-iAd%5C_MYjQ/edit#gid=0" rel="noopener noreferrer"&gt;https://docs.google.com/spreadsheets/d/1PyCgaglXSCbxVmHuwFbkKDF9e3PW\_iUn8T-iAd\_MYjQ/edit#gid=0&lt;/a&gt; the Sheet ID is 1PyCgaglXSCbxVmHuwFbkKDF9e3PW_iUn8T-iAd_MYjQ. Enter this Sheet ID in the &lt;strong&gt;&lt;em&gt;Sheet ID&lt;/em&gt;&lt;/strong&gt; field in the &lt;em&gt;Google Sheet&lt;/em&gt; node. Enter the range of the columns in the &lt;strong&gt;&lt;em&gt;Range&lt;/em&gt;&lt;/strong&gt; field. The range contains the column references corresponding to those on the spreadsheet. The range tells the &lt;em&gt;Google Sheets&lt;/em&gt; node from which columns to read the data.&lt;/p&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;&lt;em&gt;Read data&lt;/em&gt;&lt;/strong&gt; and click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; button. The node will return the data from the Google Sheet.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Stage 2- Extract new data
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Function node (Check if new data)
&lt;/h4&gt;

&lt;p&gt;Our workflow reads the data from a Google Sheet and returns all the data. However, we only want the data that was recently added. We will use the &lt;em&gt;Function&lt;/em&gt; node to return only the data that was added after the previous execution.&lt;/p&gt;

&lt;p&gt;To help you understand this better, let us take a look at an example. Our workflow ran at 1:00 PM and returned the following data:&lt;/p&gt;

&lt;p&gt;New data was added to our Google Sheet at 1:20 PM. When your workflow will execute next, we only want this new data. Using the &lt;em&gt;Function&lt;/em&gt; node we will return this new data. n8n has a getWorkflowStaticData() method that gives access to the static workflow data. We can save data directly with the workflow, however, this data should be very small. When the workflow execution succeeds, n8n will check automatically if the data has changed and will save it, if necessary.&lt;/p&gt;

&lt;p&gt;Click on the ‘ &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; ’ icon and select the &lt;em&gt;Function&lt;/em&gt; node from the list. In the &lt;strong&gt;&lt;em&gt;Javascript Code&lt;/em&gt;&lt;/strong&gt; editor, paste the following code snippet.&lt;/p&gt;

&lt;p&gt;The above code snippet gets the static workflow data and checks for new items. If new items are found, it is added to an array and gets returned by the node. If the data remains unchanged, an empty array is returned by the node.&lt;/p&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;&lt;em&gt;Check if new data&lt;/em&gt;&lt;/strong&gt; and click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt;  button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : The static data can not be read and written when we’re building the workflow. Hence, on every execution, the node will return all the data. When the workflow is set to active and triggered by a Trigger node, the node will save the static data and return only the new data that was added (if any).&lt;/p&gt;

&lt;p&gt;The following image shows the output returned by the node when the workflow is not active.&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%2F0%2ABn8QcRdpxQxypJ3E" 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%2ABn8QcRdpxQxypJ3E" alt="Output returned by the Function node when the workflow is not active"&gt;&lt;/a&gt;Output returned by the Function node when the workflow is not active&lt;/p&gt;

&lt;p&gt;The following image shows the output returned by the node when the workflow is active.&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%2F0%2A2KJzyq5WQaBBxOk-" 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%2A2KJzyq5WQaBBxOk-" alt="Output returned by the Function node when the workflow is active"&gt;&lt;/a&gt;Output returned by the Function node when the workflow is active&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Stage 3- Communication
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Mattermost node (Send message)
&lt;/h4&gt;

&lt;p&gt;If new data was added to the Google Sheet we will send a message to Mattermost along with the new data. We will send a message to the updates channel. But you can select a different channel to send the message.&lt;/p&gt;

&lt;p&gt;Click on the ‘ &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; ’ button and select the &lt;em&gt;Mattermost&lt;/em&gt; node. Connect the node to the &lt;strong&gt;&lt;em&gt;true&lt;/em&gt;&lt;/strong&gt; branch of the &lt;em&gt;Is new item?&lt;/em&gt; node. Use the credentials you configured earlier.&lt;/p&gt;

&lt;p&gt;If you are not the system administrator of the Mattermost team, navigate to Mattermost and select the ‘updates’ channel from the left sidebar. Click on the caret next to ‘updates’ and select ‘View Info’ from the dropdown list. Copy and paste the displayed ID in the &lt;strong&gt;&lt;em&gt;Channel ID&lt;/em&gt;&lt;/strong&gt; field in the Mattermost node.&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%2F0%2ARLfOtAjF0hvzz9rk" 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%2ARLfOtAjF0hvzz9rk" alt="Finding channel ID of a Mattermost channel"&gt;&lt;/a&gt;Finding channel ID of a Mattermost channel&lt;/p&gt;

&lt;p&gt;If you’re the system administrator, select the ‘updates’ channel from the &lt;strong&gt;&lt;em&gt;Channel ID&lt;/em&gt;&lt;/strong&gt; dropdown list.&lt;/p&gt;

&lt;p&gt;Click on the gears icon next to the &lt;strong&gt;&lt;em&gt;Message&lt;/em&gt;&lt;/strong&gt; field and select ‘Add Expression’. Enter the following expression in the &lt;strong&gt;&lt;em&gt;Expression Editor&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;&lt;em&gt;Send message&lt;/em&gt;&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  What’s next?
&lt;/h3&gt;

&lt;p&gt;Currently, the &lt;em&gt;Check if new data&lt;/em&gt; node in our workflow returns all the items since the static data is not getting saved. Save the workflow and toggle the Active, on the top right, to true. This will set our workflow to active and our workflow will execute every 45 mins. Add new data to the Google Sheets, and after 45 mins (for testing you can set the time to 2 mins!) you will receive a message on Mattermost.&lt;/p&gt;

&lt;p&gt;Such polling workflows can be used for various use-cases. If you’re using Google Forms to collect data, and if the form adds the data to a Google Sheet, you can build a workflow that will trigger the workflow whenever there is a new form response.&lt;/p&gt;

&lt;p&gt;Another interesting use-case can be for Twitter. You can build a polling workflow that executes every 10 mins. This workflow would fetch Tweets for your search criteria using the Twitter node and return the most recent tweets. At n8n, we use a similar workflow that sends a message to Mattermost with the recent Tweets. You can find the workflow on the &lt;a href="https://n8n.io/workflows/875" rel="noopener noreferrer"&gt;workflow page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few more examples where polling can help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger a workflow when an event gets added to your Google Calendar using the Google Calendar node&lt;/li&gt;
&lt;li&gt;Trigger a workflow when price changes for a cryptocurrency using the CoinGecko node&lt;/li&gt;
&lt;li&gt;Trigger a workflow when new data gets added to your database (MongoDB, Postgres, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this tutorial, we learned how polling can help us overcome a barrier for the nodes that do not have a Trigger node. We can use polling with the nodes that do not have a default Trigger node and build a workflow based to trigger actions when new data is added or updated.&lt;/p&gt;

&lt;p&gt;We built a polling workflow that executes every 45 mins and reads data from a Google Sheet. If the data has been updated or new data has been added, the workflow sends a message to Mattermost.&lt;/p&gt;

&lt;p&gt;I’d like to know about how you are using the concept of polling and building workflows with n8n! If you run into any issues while following the tutorial, feel free to message me on &lt;a href="https://twitter.com/harshil1712" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or ask for help on our&lt;a href="https://community.n8n.io" rel="noopener noreferrer"&gt;forum&lt;/a&gt; 🧡&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://n8n.io/blog/creating-triggers-for-n8n-workflows-using-polling/" rel="noopener noreferrer"&gt;post&lt;/a&gt; originally appeared on the n8n.io &lt;a href="https://n8n.io/blog/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>googlesheets</category>
      <category>mattermost</category>
      <category>automation</category>
      <category>polling</category>
    </item>
    <item>
      <title>Migrating Community Metrics to Orbit using n8n 📈</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 18 Dec 2020 16:04:36 +0000</pubDate>
      <link>https://forem.com/n8n/migrating-community-metrics-to-orbit-using-n8n-5d5i</link>
      <guid>https://forem.com/n8n/migrating-community-metrics-to-orbit-using-n8n-5d5i</guid>
      <description>&lt;p&gt;It has been more than two years since I have been involved in the community as an organizer. My journey started as a &lt;a href="https://education.github.com/experts"&gt;GitHub Campus Expert&lt;/a&gt;. My love for privacy and the open internet helped me become a Mozilla Representative, and I am now an &lt;a href="https://auth0.com/ambassador-program/"&gt;Auth0 Ambassador&lt;/a&gt; too. This journey is teaching me new skills and pushes me to do better. This is the aim I have for the community as well. Every member should get the opportunity to grow, showcase their skills, and achieve their goals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DN1keHUX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AX0lQK1vlnr7CXKUDKRdSnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DN1keHUX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AX0lQK1vlnr7CXKUDKRdSnw.png" alt=""&gt;&lt;/a&gt;Migrating Community Metrics to Orbit using n8n&lt;/p&gt;

&lt;p&gt;To know what everyone was up to, I started keeping records of the activities of the community members using Google Sheets. But with an ever-growing community, it became difficult. Every time a community member contributed, I manually added these records to a Google Sheet. The members of the community are very active, and it became difficult to keep up with the pace. Structuring data in Google Sheets for community metrics was also a painful task. The biggest challenge was making sense of these metrics. So I started using Orbit and connected my Google Sheets to it using &lt;a href="https://n8n.io"&gt;n8n&lt;/a&gt; to transfer data automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is Orbit?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/orbit-love/orbit-model"&gt;Orbit model&lt;/a&gt; is a framework for building communities. &lt;a href="https://orbit.love/"&gt;Orbit&lt;/a&gt; makes it easy for community leaders and Developer Relations (DevRel) Leadership to easily keep track of the DevRel metrics and quantify the business impact.&lt;/p&gt;

&lt;p&gt;I started at &lt;a href="https://n8n.io/"&gt;n8n&lt;/a&gt; as a Developer Advocate Intern and was excited to learn that we use Orbit for DevRel metrics. I had read about Orbit and was eager to know more about it. I explored Orbit for a while and ended up creating an n8n workflow that moved the metrics from Google Sheets to Orbit.&lt;/p&gt;

&lt;p&gt;Like me, if you too manage DevRel metrics in Google Sheets (or Airtable), follow along the article to learn how you can move these metrics to Orbit using n8n.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Orbit account&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You can request access to Orbit by filling a form on their &lt;a href="https://orbit.love/"&gt;website&lt;/a&gt;. Once you have access to Orbit, create a workspace for your community.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Google account&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;I used Google Sheets to keep a record of the metrics in this &lt;a href="https://docs.google.com/spreadsheets/d/1GiR5glinWBUJ-pw3w8LpcuwyOXst2z5nnFSak8DQrMQ/edit?usp=sharing"&gt;spreadsheet&lt;/a&gt;. You will need a Google account to create a Google Sheet. Sign in to your Google account and open this &lt;a href="https://docs.google.com/spreadsheets/d/1GiR5glinWBUJ-pw3w8LpcuwyOXst2z5nnFSak8DQrMQ/edit?usp=sharing"&gt;sheet&lt;/a&gt;. Click on the &lt;strong&gt;&lt;em&gt;File&lt;/em&gt;&lt;/strong&gt; and select ‘Make a Copy’ from the dropdown list to copy the sheet in your account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you change the name of the columns or the name of the sheet, make sure to make the changes in the n8n workflow accordingly.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;n8n&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We will connect Google Sheets to Orbit using n8n. Follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/getting-started/quickstart.html#quickstart"&gt;documentation&lt;/a&gt; to install and spin-up an n8n instance on your machine. You can also sign-up for &lt;a href="https://n8n.cloud/"&gt;n8n.cloud&lt;/a&gt; to get access to our hosted service (in beta).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Quickstart&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you don’t want to get into the details and have a bit of experience with n8n, you can follow the quick-start instructions below to get to the endgame. If something is unclear or you want to learn more about how it works, feel free to dig deeper into the sections that follow.&lt;/p&gt;

&lt;p&gt;Access your n8n instance, and copy and paste the workflow from the &lt;a href="https://n8n.io/workflows/829"&gt;workflow&lt;/a&gt; page. Configure the credentials for the following nodes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Sheets node&lt;/strong&gt; : &lt;a href="https://docs.n8n.io/credentials/google/#using-oauth"&gt;configure the OAuth credentials&lt;/a&gt; and make sure you enter the correct Sheet ID in the &lt;strong&gt;&lt;em&gt;Sheet ID&lt;/em&gt;&lt;/strong&gt;  field.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Get Members&lt;/strong&gt; : This Google Sheet node fetches the data from the Members sheet. If your sheet has a different name, modify the &lt;strong&gt;&lt;em&gt;Range&lt;/em&gt;&lt;/strong&gt; field accordingly. If you’re using the Google Sheet shared earlier, enter the following range: Members!A:F.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get Activities&lt;/strong&gt; : We fetch the activities of our members from the Activities sheet. If you are using a different name for your sheet, modify the &lt;strong&gt;&lt;em&gt;Range&lt;/em&gt;&lt;/strong&gt; field accordingly. For the spreadsheet I shared earlier, enter the following range: Activities!A:D.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Orbit node&lt;/strong&gt; : &lt;a href="https://docs.n8n.io/credentials/orbit/#orbit"&gt;configure the credentials&lt;/a&gt; and select your workspace from the &lt;strong&gt;&lt;em&gt;Workspace&lt;/em&gt;&lt;/strong&gt; field.&lt;/p&gt;

&lt;p&gt;Save and execute the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WBxApxLg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A7OgrdvP_nbB0_OdX" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WBxApxLg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A7OgrdvP_nbB0_OdX" alt=""&gt;&lt;/a&gt;The final workflow in n8n&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Moving data from Google Sheets to Orbit automatically&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our workflow will fetch the data of our community members and their activities from a Google Sheet and add the information in our Orbit workspace automatically. The workflow uses the following nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get Members (&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.googleSheets/#google-sheets"&gt;Google Sheets node&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add Members (&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.orbit/#orbit"&gt;Orbit node&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Get Activities (Google Sheets node)&lt;/li&gt;
&lt;li&gt;Get all members (Orbit node)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.merge/#merge"&gt;Merge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add Activities (Orbit node)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Get Members (Google Sheets node)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We are storing our members’ information like their name, GitHub username, Twitter handle, etc. in a Google Sheet. We will use the Google Sheet node to fetch this information.&lt;/p&gt;

&lt;p&gt;The following image shows the Members sheet in my Google Sheet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sA-uAZ7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARgbtItWePZ6O13mS" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sA-uAZ7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARgbtItWePZ6O13mS" alt="Storing members’ information in Google Sheet"&gt;&lt;/a&gt;Storing members’ information in Google Sheet&lt;/p&gt;

&lt;p&gt;Follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/credentials/google/#prerequisites"&gt;documentation&lt;/a&gt; to configure the credentials for the Google Sheets node. Enter your Sheet ID in the &lt;strong&gt;&lt;em&gt;Sheet ID&lt;/em&gt;&lt;/strong&gt; field and enter a range in the &lt;strong&gt;&lt;em&gt;Range&lt;/em&gt;&lt;/strong&gt; field. If you’re using the Google Sheet shared earlier, enter the following range: Members!A:F.&lt;/p&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;Get Members&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;The following image shows the output of the Get Members node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0epWl4kq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AJvabJNqLiL33A7Rv" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0epWl4kq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AJvabJNqLiL33A7Rv" alt="Fetching members’ data using Google Sheets node"&gt;&lt;/a&gt;Fetching members’ data using Google Sheets node&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Add Members (Orbit node)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We will use the members’ data that we received from the previous node and pass it on to the Orbit node. To configure the credentials of the Orbit node, follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/credentials/orbit/#orbit"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Select the ‘Upsert’ operation and your workspace in the Orbit node. We are using the GitHub identity to add the members. Select ‘GitHub’ from the &lt;strong&gt;&lt;em&gt;Source&lt;/em&gt;&lt;/strong&gt; dropdown list and ‘Username’ from the &lt;strong&gt;&lt;em&gt;Search By&lt;/em&gt;&lt;/strong&gt; dropdown list. In the username parameter of the node, use the following expression: &lt;code&gt;{{$json["GitHub"]}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In our Google Sheet, we also have information like Location, Tags, Name, and T-shirt size. We will add this information to Orbit as well. You can add this information by selecting them from the &lt;strong&gt;&lt;em&gt;Add Field&lt;/em&gt;&lt;/strong&gt; dropdown list. Enter the following expression in the Expression Editor of the respective fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Location&lt;/strong&gt; : &lt;code&gt;{{$json["Location"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : &lt;code&gt;{{$json["Name"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags to Add&lt;/strong&gt; : &lt;code&gt;{{$json["Tags']}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;T-Shirt&lt;/strong&gt; : &lt;code&gt;{{$json["T-Shirt Size"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;Add Members&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;The following image shows the output of the Add Members node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jhUsrcPR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AXkGkTUKEbAY_LyaB" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jhUsrcPR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AXkGkTUKEbAY_LyaB" alt="Adding members to Orbit"&gt;&lt;/a&gt;Adding members to Orbit&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Get Activities (Google Sheets node)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Keeping only the data of the community members is not that useful. We also need to keep records of their activities. This record helps us understand the contributions the community members make, the type of content they are involved with, and other critical insights.&lt;/p&gt;

&lt;p&gt;The following image shows the Activities sheet in my Google Sheet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HuxfLJFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AHqrwSNK7YMGnBfqY" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HuxfLJFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AHqrwSNK7YMGnBfqY" alt="Storing members’ activities in Google Sheet"&gt;&lt;/a&gt;Storing members’ activities in Google Sheet&lt;/p&gt;

&lt;p&gt;We will get the records of the activities of our community members from the Google sheet and add them to Orbit.&lt;/p&gt;

&lt;p&gt;Select the credentials that we used in the Get Members node. Our Google Sheet uses the members’ GitHub username to associate them with their activities. We will use the ‘Lookup’ operation to get this information. Enter the following in the expression editor for the &lt;strong&gt;&lt;em&gt;Sheet ID&lt;/em&gt;&lt;/strong&gt; parameter: &lt;code&gt;{{$node["Get Members"].parameter["sheetId"]}}&lt;/code&gt;. Enter the range for our Google Sheet in the &lt;strong&gt;&lt;em&gt;Range&lt;/em&gt;&lt;/strong&gt; field. If you’re using the Google Sheet shared earlier, enter the following range: Activities!A:D.&lt;/p&gt;

&lt;p&gt;Enter ‘GitHub Username’ in the &lt;strong&gt;&lt;em&gt;Lookup Column&lt;/em&gt;&lt;/strong&gt; field. If you are using a different column name, enter that instead.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;Lookup Value&lt;/em&gt;&lt;/strong&gt; field, we pass the GitHub username of all our members that we got from the Get Members node. Enter the following expression in the Lookup Value field: &lt;code&gt;{{$node["Get Members"].json["GitHub"]}}&lt;/code&gt;. Toggle &lt;strong&gt;&lt;em&gt;Return All Match&lt;/em&gt;&lt;/strong&gt; to true. This will check for the activities of all the members and return all their activities if it exists.&lt;/p&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;Get Activities&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;The following image shows the output from the Get Activities node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WIDY5qol--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Az7GcVUihyn7KscFq" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WIDY5qol--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Az7GcVUihyn7KscFq" alt="Getting members’ activities using the Google Sheet node"&gt;&lt;/a&gt;Getting members’ activities using the Google Sheet node&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Get all members (Orbit node)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To add the activities that we got from the previous node, we need the ID of the members that were generated by Orbit. This node will get the ID of the members along with other information.&lt;/p&gt;

&lt;p&gt;Create a new Orbit node and select the credentials that we used in the Add Members node. Select ‘Get All’ from the &lt;strong&gt;&lt;em&gt;Operation&lt;/em&gt;&lt;/strong&gt; dropdown list. Select your workspace and toggle &lt;strong&gt;&lt;em&gt;Return All&lt;/em&gt;&lt;/strong&gt; to true.&lt;/p&gt;

&lt;p&gt;Rename the node to Get all members and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt; Depending on the amount of data we have, the Orbit node might take some time to add the new members to the workspace.&lt;/p&gt;

&lt;p&gt;The following image shows the output from the Get all members node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ObHbWANY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ALa22TOQg--fO4Xs2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ObHbWANY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ALa22TOQg--fO4Xs2" alt="Getting all members using the Orbit node"&gt;&lt;/a&gt;Getting all members using the Orbit node&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;5. Merge information Google Sheets and Orbit&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We now have all the activities of our members from Google Sheet and their member ID from Orbit. We need to merge this information to map the activities to their respective member IDs.&lt;/p&gt;

&lt;p&gt;We are using the Merge node to merge this information. Connect one input of the node with the &lt;strong&gt;&lt;em&gt;Get Activities&lt;/em&gt;&lt;/strong&gt; node and the other input with the &lt;strong&gt;&lt;em&gt;Get all members&lt;/em&gt;&lt;/strong&gt;  node.&lt;/p&gt;

&lt;p&gt;Select ‘Merge By Key’ from the &lt;strong&gt;&lt;em&gt;Mode&lt;/em&gt;&lt;/strong&gt; dropdown list. This option will merge the information using the GitHub username as the key. Enter ‘GitHub Username’ in the &lt;strong&gt;&lt;em&gt;Property Input 1&lt;/em&gt;&lt;/strong&gt; field and ‘attributes.slug’ in the &lt;strong&gt;&lt;em&gt;Property Input 2&lt;/em&gt;&lt;/strong&gt;  field.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;The following image shows the output from the Merge node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vs1OZbc---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AdnhrI6tes8oK9FDn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vs1OZbc---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AdnhrI6tes8oK9FDn" alt="Merging data from Google Sheets and Orbit"&gt;&lt;/a&gt;Merging data from Google Sheets and Orbit&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;6. Add Activities (Orbit node)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Merge node returns all the necessary data that we need. Using the Add Activities node, we will add the activities of our community members to Orbit.&lt;/p&gt;

&lt;p&gt;In our new Orbit node, select the credentials that we used for the Get all members node. Select ‘Activity’ from the &lt;strong&gt;&lt;em&gt;Resource&lt;/em&gt;&lt;/strong&gt; dropdown list and ‘Create’ from the &lt;strong&gt;&lt;em&gt;Operation&lt;/em&gt;&lt;/strong&gt; dropdown list.&lt;/p&gt;

&lt;p&gt;In the expression editor for the &lt;strong&gt;&lt;em&gt;Member ID&lt;/em&gt;&lt;/strong&gt; field, enter the following expression: &lt;code&gt;{{$json["id"]}}&lt;/code&gt;. Enter the following expression in the expression editor of the &lt;strong&gt;&lt;em&gt;Title&lt;/em&gt;&lt;/strong&gt; field: &lt;code&gt;{{$json["Title"]}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will also add a description and a link (if they exist) for the activities. Add the &lt;strong&gt;&lt;em&gt;Description&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Link&lt;/em&gt;&lt;/strong&gt; fields from the &lt;strong&gt;&lt;em&gt;Add Field&lt;/em&gt;&lt;/strong&gt; dropdown list. Enter the following expression in the Expression Editor of the respective fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt; : &lt;code&gt;{{$json["Description"}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link&lt;/strong&gt; : &lt;code&gt;{{$json["Activity Link"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rename the node to &lt;strong&gt;Add Activities&lt;/strong&gt; and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node.&lt;/p&gt;

&lt;p&gt;The following image shows the output from the Add Activities node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nmhyiYZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AUEmR8kTRarWgvbcR" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nmhyiYZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AUEmR8kTRarWgvbcR" alt="Adding activities using the Orbit node"&gt;&lt;/a&gt;Adding activities using the Orbit node&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What’s next?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The current workflow shows how we can migrate our data from Google Sheet to Orbit. But we might be using Airtable or a CRM tool to manage these records. We can migrate these records to Orbit using n8n in less than 10 mins.&lt;/p&gt;

&lt;p&gt;We can build another workflow using the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.cron/#cron"&gt;Cron&lt;/a&gt; node and the Orbit node to get the information about members with the highest activity in a month. Appreciate their contributions in the community using the Mattermost node or the Slack node (or whatever your community uses), and tweet about their work using the Twitter node.&lt;/p&gt;

&lt;p&gt;I previously wrote an &lt;a href="https://medium.com/n8n-io/giving-kudos-to-contributors-with-github-slack-and-n8n-b3f5f4a653a6"&gt;article&lt;/a&gt; on how you can use the Slash command in Slack and integrate it with n8n to get community members’ information and give a shout-out to them. We can combine these workflows. Use the Orbit node to get the data (email, address, t-shirt size) of the members, the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.shopify/#shopify"&gt;Shopify&lt;/a&gt; node to place an order for swags. If you use &lt;a href="https://www.printfection.com/"&gt;Printfection&lt;/a&gt;, you can use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.httpRequest/#http-request"&gt;HTTP Request&lt;/a&gt; node to place the order on Printfection. Let us recognize the contributions of the community!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Community metrics are yet not well defined and is a challenge for a lot of us. But the Orbit model streamlines these metrics and gives us a more efficient output. With this workflow, we now have our community metrics in our Orbit workspace. Orbit displays the data more sensibly and helps us understand the metrics. We can now make sense of these metrics and plan future activities for our community more efficiently.&lt;/p&gt;

&lt;p&gt;I’d love to hear about how you extend the workflow using n8n and manage your communities! If you run into any issues while following the tutorial, feel free to reach out to me on &lt;a href="https://twitter.com/harshil1712"&gt;Twitter&lt;/a&gt; or ask for help on our &lt;a href="https://community.n8n.io"&gt;forum&lt;/a&gt; 🧡&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://n8n.io/blog/migrating-community-metrics-to-orbit-using-n8n"&gt;post&lt;/a&gt; originally appeared on the n8n.io &lt;a href="https://n8n.io/blog/"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>automation</category>
      <category>spreadsheets</category>
      <category>metrics</category>
      <category>community</category>
    </item>
    <item>
      <title>Building an expense tracking app in 10 minutes 📱</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 11 Dec 2020 07:42:06 +0000</pubDate>
      <link>https://forem.com/n8n/building-an-expense-tracking-app-in-10-minutes-jp7</link>
      <guid>https://forem.com/n8n/building-an-expense-tracking-app-in-10-minutes-jp7</guid>
      <description>&lt;p&gt;I tried various ways in the past to keep a record of my expenses. It started with maintaining a record in a book. But this wasn’t an ideal solution and involved manual work. I tried using everyone’s favorite — spreadsheets, but it failed me. I still had to manually enter the information of my expenses. I also tried various apps, but none of them catered to my needs. They all lacked the option to customize the way I wanted to upload the information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JUOJhPvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALU6439lmuKawTvBMf3Uyzw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JUOJhPvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALU6439lmuKawTvBMf3Uyzw.jpeg" alt="Building an expense tracking app in 10 minutes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;I built an app!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I came across the article &lt;a href="https://medium.com/n8n-io/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n-c47eb2f8d7a5"&gt;Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n 🧾&lt;/a&gt; that showed how to build a Telegram bot to track expenses. This article inspired me to create an app for managing my expenditures. But creating a mobile app would mean designing the user interface of the app and transforming the design into a functional app. This was going to be a long process, and I was looking for a less complicated and faster solution, and that is when I learnt about &lt;a href="https://www.bravostudio.app/"&gt;Bravo Studio&lt;/a&gt;. With Bravo Studio, you can convert your &lt;a href="https://www.figma.com"&gt;Figma&lt;/a&gt; designs into a mobile app. I had never used a no-code platform to build a mobile app, and Bravo Studio piqued my interest.&lt;/p&gt;

&lt;p&gt;I ended up creating an app that captures the image of a receipt and stores the information parsed from it in &lt;a href="http://airtable.com/"&gt;Airtable&lt;/a&gt;. I am now storing my data in my Airtable account, and I can use it the way I want. I would also have the flexibility to add more features that I might need in the future.&lt;/p&gt;

&lt;p&gt;If you’re struggling with managing expenses like me, and if you want to build your custom app, follow along with this article.&lt;/p&gt;

&lt;p&gt;In this article, we will learn to build an expense tracker app using no-code tools and platforms. We will start by designing our application in &lt;a href="https://www.figma.com"&gt;Figma&lt;/a&gt; and converting it into an app using &lt;a href="https://www.bravostudio.app/"&gt;Bravo Studio&lt;/a&gt;. We will use &lt;a href="https://www.typeform.com/"&gt;Typeform&lt;/a&gt; to collect the images of the receipts, &lt;a href="https://mindee.com/"&gt;Mindee&lt;/a&gt; to extract the information from the receipts, and &lt;a href="http://airtable.com/"&gt;Airtable&lt;/a&gt; to store all the information. We will use &lt;a href="https://n8n.io"&gt;n8n&lt;/a&gt; to connect these different services and make the app functional.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Figma&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Figma is a prototyping tool. We will use Figma to design the user interface of our application. If you don’t have an account on Figma, go ahead and &lt;a href="https://figma.com"&gt;create one&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Bravo Studio&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Bravo Studio is a no-code tool to build native applications. We will use Bravo Studio to transform our Figma design into a mobile app. &lt;a href="https://projects.bravostudio.app/signup"&gt;Create an account&lt;/a&gt; on Bravo Studio if you don’t have one. To test our application on a real device we will use &lt;a href="https://www.bravostudio.app/download-bravo-vision"&gt;Bravo Vision&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Typeform&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Our application needs an input field that will allow the users to upload images, as well as trigger our n8n workflow. We will use Typeform to handle that. &lt;a href="https://admin.typeform.com/signup"&gt;Create an account&lt;/a&gt; on Typeform and make a form with the question type ‘File Upload’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You need to have a premium account on Typefrom to access the ‘File Upload’ question type. If you don’t have a premium account, use the code n8nxTypeform_2021 to get free access for a month.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Mindee&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Once we have the image of the receipt, we need a service to extract the information from it. We will use Mindee to extract information like merchant name, amount, date of purchase, etc. from the image. You will need an &lt;a href="https://platform.mindee.net/signup"&gt;account&lt;/a&gt; on Mindee to access the Expense Receipts API.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Airtable&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Our app will use Airtable as the database to store and retrieve information from. We will need an &lt;a href="https://airtable.com/invite/r/J8pSjpKY"&gt;Airtable account&lt;/a&gt; to create a base and connect it with Bravo Studio. Sign in to your Airtable account and open &lt;a href="https://airtable.com/shrKmqHWcl3APJFlp"&gt;this base&lt;/a&gt;. Click on the &lt;strong&gt;&lt;em&gt;Copy base&lt;/em&gt;&lt;/strong&gt; button on the top right corner to copy the base in your account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you change the name of the columns, or the name of the Table, make sure to make the changes in the n8n workflow accordingly.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;n8n&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Our application is using different services like Typeform, Mindee and Airtable. n8n will connect these services together and make our app functional. Follow the instructions mentioned in the &lt;a href="https://docs.n8n.io/getting-started/quickstart.html#quickstart"&gt;documentation&lt;/a&gt; to install and spin-up an n8n instance on your machine. You can also sign-up for &lt;a href="https://n8n.cloud/"&gt;n8n.cloud&lt;/a&gt; to get early access to our hosted service.&lt;/p&gt;

&lt;p&gt;This workflow was built in n8n version 0.101.0.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Quickstart&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We often tend to jump to the results before committing to the steps of the experiment if we are aware of the subject. If you already know how to work with Bravo Studio and n8n, you can follow the quick-start instructions below to get to the endgame. If something is unclear or you want to learn more about how it works, feel free to dig deeper into the sections that follow.&lt;/p&gt;

&lt;h4&gt;
  
  
  Typeform
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create a form in Typeform with the question type ‘File Upload’.&lt;/li&gt;
&lt;li&gt;Enter Upload Receipt in the text box where it indicates ‘Type question here…’.&lt;/li&gt;
&lt;li&gt;Publish the Typeform and copy the link under the ‘SHARE’ tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Figma
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;To duplicate &lt;a href="https://www.figma.com/file/w74DevtsNH1TenkwVRqQEH/Expense-Tracker"&gt;this Figma Design&lt;/a&gt; open it in a new tab.&lt;/li&gt;
&lt;li&gt;Click on the down chevron next to &lt;strong&gt;&lt;em&gt;Expense Tracker&lt;/em&gt;&lt;/strong&gt; and select ‘Duplicate to your Drafts’ from your dropdown list.&lt;/li&gt;
&lt;li&gt;Replace ‘TYPEFORM-LINK’ in Add Receipts Data &amp;gt; Typeform Container &amp;gt; Rectangle[component:web-view:TYPEFORM-LINK] with your form’s link.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---TYri4oz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/954/0%2A5RJD-qne2N509q3t" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---TYri4oz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/954/0%2A5RJD-qne2N509q3t" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  n8n
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://docs.n8n.io/getting-started/quickstart.html#quickstart"&gt;Install&lt;/a&gt; n8n, and copy and paste the workflow from the &lt;a href="https://n8n.io/workflows/741"&gt;workflow&lt;/a&gt; page. Configure the credentials for the following nodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typeform Trigger node (&lt;em&gt;Get Receipt&lt;/em&gt;): &lt;a href="https://docs.n8n.io/credentials/typeform/#using-access-token"&gt;&lt;em&gt;configure Access Token credentials&lt;/em&gt;&lt;/a&gt; and make sure to select your form from the &lt;strong&gt;&lt;em&gt;Form&lt;/em&gt;&lt;/strong&gt; dropdown list.&lt;/li&gt;
&lt;li&gt;Mindee node (&lt;em&gt;Extract Information&lt;/em&gt;): &lt;a href="https://docs.n8n.io/credentials/mindee"&gt;&lt;em&gt;configure credentials&lt;/em&gt;&lt;/a&gt; for the &lt;strong&gt;&lt;em&gt;Expense Receipts API.&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Airtable node (&lt;em&gt;Store Information&lt;/em&gt;): &lt;a href="https://docs.n8n.io/credentials/airtable"&gt;&lt;em&gt;configure credentials&lt;/em&gt;&lt;/a&gt; and enter the &lt;a href="https://airtable.com/api"&gt;application id&lt;/a&gt; and the table name in the &lt;strong&gt;&lt;em&gt;Base ID&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Table&lt;/em&gt;&lt;/strong&gt; field respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save the workflow and set it to active.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bravo Studio
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create an app in Bravo Studio by importing the Figma design from step 2.&lt;/li&gt;
&lt;li&gt;Add Airtable as a data library in Bravo Studio. You can follow the instructions mentioned in the official &lt;a href="https://www.notion.so/Using-the-Airtable-API-Wizard-f2e75dde9f13419f93661a9e116c1ac3"&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Bind the data from your Airtable base to your Bravo Studio app. You can learn how to do that from the &lt;a href="https://www.notion.so/Bind-data-to-UI-for-a-list-page-2cf8c91380124ddf8b84d303e1c3ca8a"&gt;documentation&lt;/a&gt; of Bravo Studio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE&lt;/em&gt;&lt;/strong&gt; : If you were successfully able to follow the steps mentioned above, you can jump directly to the &lt;strong&gt;&lt;em&gt;Testing the Application&lt;/em&gt;&lt;/strong&gt; section before going through the conceptual sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Creating the User Interface&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To add the expense in our app, a user will upload an image of the receipt. We will use a Typeform form to get the image of the receipt from the user. Create a form in Typeform with the question type ‘File Upload’. Publish the Typeform and copy the link under the ‘SHARE’ tab. We will use this link in Figma to embed the form.&lt;/p&gt;

&lt;p&gt;We want to create an app with our custom design and functionality. We will use Figma to design the prototype of the app. Below is the screenshot of the app’s design created in Figma.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SvchL8X9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACzdGvWSTuPVboOTr" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SvchL8X9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACzdGvWSTuPVboOTr" alt="Creating the app’s design in Figma"&gt;&lt;/a&gt;Creating the app’s design in Figma&lt;/p&gt;

&lt;p&gt;Our app will have three screens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A welcome screen which gives the user an option to either add a new receipt or view the stored receipts.&lt;/li&gt;
&lt;li&gt;An ‘Add Receipt Data’ screen that will allow the user to upload new receipts using the form we created in Typeform.&lt;/li&gt;
&lt;li&gt;A ‘Review Added Receipts’ screen to view all the receipts added by the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The design that we create in Figma should be compatible with Bravo Studio. To design a Bravo Studio app in Figma there are a few things to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.notion.so/The-Container-how-to-set-up-any-Figma-file-for-Bravo-1af6df44b75f489ab47c0486e9984d91"&gt;Containerize your design&lt;/a&gt;: To make our Figma app design adaptable in Bravo Studio, wrap the layers in containers. These containers are frames that divide an app screen into separate blocks based on the intended behavior of the design. In our app, we will need to create the following containers:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Main Container&lt;/strong&gt; : The &lt;strong&gt;&lt;em&gt;Welcome Screen&lt;/em&gt;&lt;/strong&gt; contains a container that consists of all the layers and the ‘App Buttons’ container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---oKQ8cne--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A9wEdGtjyvwr0xU3P" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---oKQ8cne--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A9wEdGtjyvwr0xU3P" alt="Creating the Main Container"&gt;&lt;/a&gt;&lt;em&gt;Creating the Main Container&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App Buttons&lt;/strong&gt; : This container consists of the ‘Add new receipt’ and ‘My receipts’ button on the &lt;strong&gt;&lt;em&gt;Welcome Screen&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iNrtd_Oq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AO8L5HeLQAFnivtdD" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iNrtd_Oq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AO8L5HeLQAFnivtdD" alt="Creating the App Buttons container"&gt;&lt;/a&gt;&lt;em&gt;Creating the App Buttons container&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Top navigation&lt;/strong&gt; : We need a container that helps us navigate back to the welcome screen. The Top navigation container will contain an image for the back button and the title of the screen. We will add this container to the &lt;strong&gt;&lt;em&gt;Add Receipt Data&lt;/em&gt;&lt;/strong&gt; screen and the &lt;strong&gt;&lt;em&gt;Review Added Receipts&lt;/em&gt;&lt;/strong&gt;  screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cr7VyLY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ar9CHDNvLghr5CxRm" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cr7VyLY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ar9CHDNvLghr5CxRm" alt="Creating the Top navigation container"&gt;&lt;/a&gt;&lt;em&gt;Creating the Top navigation container&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Typeform Container&lt;/strong&gt; : The Typeform Container contains a rectangle layer that will render the Typeform. We will add this container to the ‘Add new receipt’ screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9DTytEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARdFIl2pEPTqSMRJE" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9DTytEh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ARdFIl2pEPTqSMRJE" alt="Creating the Typeform container"&gt;&lt;/a&gt;&lt;em&gt;Creating the Typeform container&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;*List: This container consists of the layers that will render the receipts information such as the merchant name, amount, date, time, category, and image of the receipt. We will add this container to the ‘My receipts’ screen.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c9mwknJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A5HJfkL2t99trUueW" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c9mwknJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A5HJfkL2t99trUueW" alt="Creating the *List container"&gt;&lt;/a&gt;&lt;em&gt;Creating the *List container&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;a href="https://www.notion.so/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8"&gt;Bravo Tags&lt;/a&gt;: A Bravo Tag is a text string that converts the layer into a mobile component. For each container and layer, you want to convert to a mobile component, use the appropriate Bravo Tags. In our design, we will use the &lt;a href="https://www.notion.so/Component-Web-view-909829539eea4a92892a1fa41bd8934e"&gt;[component:web-view:URL]&lt;/a&gt; tag to embed the Typeform in the &lt;em&gt;Typeform Container&lt;/em&gt;. Replace ‘URL’ with the URL of the Typeform you created earlier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The name of the List container and the layers inside the container starts with an asterisk (*). Bravo Studio recognizes such containers and layers as a list.&lt;/p&gt;

&lt;p&gt;After designing the application in Figma, the next step is to use this design in Bravo Studio to create a native application. In Bravo Studio, click on the &lt;strong&gt;&lt;em&gt;Import Figma File&lt;/em&gt;&lt;/strong&gt; button and copy and paste the link of your Figma design in the input field to create a new project.&lt;/p&gt;

&lt;p&gt;Congratulations! The user-interface of your application is ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Connecting with Airtable&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Bravo Studio we can use a custom API or Airtable to connect our application with a database. The application we built uses Airtable as the database. Hence, we will connect Airtable with our application.&lt;/p&gt;

&lt;p&gt;In Bravo Studio, add a new data collection by clicking the ‘+ New Collection’ button on the Data Library page. Select Airtable, and follow the instructions as shown in the video, in the Airtable API Wizard, enter the base URL and your Airtable API Key. You can learn more about &lt;em&gt;Using the Airtable API Wizard&lt;/em&gt; from the documentation &lt;a href="https://www.notion.so/Using-the-Airtable-API-Wizard-f2e75dde9f13419f93661a9e116c1ac3"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;&lt;em&gt;Advanced view&lt;/em&gt;&lt;/strong&gt; and make a GET request for ‘Expenses — List’. Select ‘All’ from the data.records[] dropdown list in the &lt;strong&gt;&lt;em&gt;Response Data&lt;/em&gt;&lt;/strong&gt;  section.&lt;/p&gt;

&lt;p&gt;Navigate to the ‘Projects’ page and select the app that we created. We will bind the data from the Airtable base with the respective components of the ‘Review Added Receipts’ screen. Select the ‘Review Added Receipts’ screen and select the ‘Expenses Tracker’ Airtable base. Select ‘GET Expenses — List’ in the &lt;strong&gt;&lt;em&gt;Select Request&lt;/em&gt;&lt;/strong&gt; section of &lt;strong&gt;&lt;em&gt;Data Binding&lt;/em&gt;&lt;/strong&gt;. Select the *List component and select Records from the dropdown list below &lt;strong&gt;&lt;em&gt;Get Expenses — List&lt;/em&gt;&lt;/strong&gt;. Expand the *List component and map each element to their corresponding field. You can learn more about this from the &lt;a href="https://www.notion.so/Bind-data-to-UI-for-a-list-page-2cf8c91380124ddf8b84d303e1c3ca8a"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The video below shows the steps to bind the data to components.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;Building the workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Creating a backend for applications can get complicated when it comes to connecting different services together. You have to write functions to make API calls to each service, and pass information from one service to another in the proper format. But n8n makes it easy to create the backend and stitch different services together. You also get a visual representation that helps you in designing the application logic.&lt;/p&gt;

&lt;p&gt;In n8n, you will use the following nodes to build the backend logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.typeformTrigger/#typeform-trigger"&gt;Typeform Trigger&lt;/a&gt; node (Get Receipt)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.httpRequest/#http-request"&gt;HTTP Request&lt;/a&gt; node (Get Image)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.mindee/#mindee"&gt;Mindee&lt;/a&gt; node (Extract Information)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.set/#set"&gt;Set&lt;/a&gt; node (Set Information)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.airtable/#airtable"&gt;Airtable&lt;/a&gt; node (Store Information)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our workflow will look like the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZV5C62DN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACkc3jg0WaYHkHfHZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZV5C62DN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ACkc3jg0WaYHkHfHZ" alt=""&gt;&lt;/a&gt;Completed workflow in n8n&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Typeform Trigger node (Get Receipt)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Typeform Trigger node will trigger the workflow whenever the user submits a new receipt. Add the Typeform Trigger node and configure the credentials by following the instructions in the documentation &lt;a href="https://docs.n8n.io/credentials/typeform/#prerequisites"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Select the form that you created for the application from the &lt;strong&gt;&lt;em&gt;Form&lt;/em&gt;&lt;/strong&gt; dropdown list.&lt;/p&gt;

&lt;p&gt;Rename the node as Get Receipt, and save the workflow.&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; button to execute the node. Upload an image of a receipt using the Typeform. You will notice that the Typeform Trigger node triggers the workflow when the form is submitted.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  &lt;strong&gt;2. HTTP Request node (Get Image)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The HTTP Request node is used to make an HTTP request to APIs and websites. It can return data in JSON, String as well as Binary format. Add an HTTP Request node in n8n that will make a GET request to fetch the image we uploaded using the Typeform. In the URL parameter of the node, add the following expression: &lt;code&gt;{{$node["Get Receipt"].json["Upload receipt"]}}&lt;/code&gt;. This expression will get the URL of the image that we uploaded using Typeform.&lt;/p&gt;

&lt;p&gt;Select ‘File’ from the &lt;strong&gt;&lt;em&gt;Response Format&lt;/em&gt;&lt;/strong&gt; dropdown list and rename the node to Get Image. Click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node. In the output, you will notice that the node returns the image of the receipt.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Mindee node (Extract Information)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Mindee API enables to extract information from an image and transform it into usable data. We will use the Mindee node in n8n to extract data from an image of a receipt. The node will extract the merchant name, the amount, the date and time the expense was incurred, and its category.&lt;/p&gt;

&lt;p&gt;Add the Mindee node in the n8n workflow, and configure the credentials as mentioned in the &lt;a href="https://docs.n8n.io/credentials/mindee/#prerequisites"&gt;documentation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rename the node to Extract Information, and click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node. You will notice that the node extracts the information from the image and transforms it into usable data that can be added to Airtable.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Set node (Set Information)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Set node allows us to set the workflow data. We will reference the data from the Mindee node and the Typeform Trigger node in the Set node and set the parameters.&lt;/p&gt;

&lt;p&gt;Add the Set node in your n8n workflow and add the parameters with the following properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amount&lt;/strong&gt; : The type of this field should be &lt;em&gt;Number&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Extract Information"].json["total"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merchant&lt;/strong&gt; : The type of this field should be &lt;em&gt;String&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Extract Information"].json["merchant"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date&lt;/strong&gt; : The type of this field should be &lt;em&gt;String&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Extract Information"].json["date"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt; : The type of this field should be &lt;em&gt;String&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Extract Information"].json["time"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Receipt&lt;/strong&gt;  &lt;strong&gt;URL&lt;/strong&gt; : The type of this field should be &lt;em&gt;String&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Get Receipt"].json["Upload receipt"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category&lt;/strong&gt; : The type of this field should be &lt;em&gt;String&lt;/em&gt; and it’s value should be &lt;code&gt;{{$node["Extract Information"].json["category"]}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The value in the &lt;strong&gt;&lt;em&gt;Name&lt;/em&gt;&lt;/strong&gt; field should be the same as the column name of your Airtable base.&lt;/p&gt;

&lt;p&gt;Toggle the &lt;strong&gt;&lt;em&gt;Keep Only Set&lt;/em&gt;&lt;/strong&gt; to true. This ensures that only the data that we set in this node gets passed on to the next nodes in the workflow. Click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; button to run the node.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  &lt;strong&gt;5. Airtable node (Store Information)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Airtable is a spreadsheet-database hybrid, with the features of a database but applied to a spreadsheet. The Bravo Studio app will get the data from the Airtable base to display it to the user. But before connecting the app with Airtable, in the front-end, we need to connect Airtable with your backend.&lt;/p&gt;

&lt;p&gt;The n8n workflow will store the data extracted by the Mindee node and the URL of the image in Airtable. Create a base in Airtable similar to this &lt;a href="https://airtable.com/shrKmqHWcl3APJFlp"&gt;template base&lt;/a&gt; if you haven’t already created one.&lt;/p&gt;

&lt;p&gt;In n8n, add the Airtable node and configure the credentials following the instructions mentioned &lt;a href="https://docs.n8n.io/credentials/airtable/#prerequisites"&gt;here&lt;/a&gt;. Select ‘Append’ from the &lt;strong&gt;&lt;em&gt;Operation&lt;/em&gt;&lt;/strong&gt; dropdown list. To get the Application ID, go to &lt;a href="https://airtable.com/api"&gt;https://airtable.com/api&lt;/a&gt; and select the base. Copy and paste the ID in the &lt;strong&gt;&lt;em&gt;Base ID&lt;/em&gt;&lt;/strong&gt; field in n8n. Enter the name of your base in the &lt;strong&gt;&lt;em&gt;Table&lt;/em&gt;&lt;/strong&gt;  field.&lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; to run the node. On successful execution, you will notice that a new row gets added to your Airtable base.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;Testing the application&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Congratulations! You have successfully built the application. Now let us test our application and see how it would work in the real world.&lt;/p&gt;

&lt;p&gt;In n8n, on the top right corner, toggle &lt;strong&gt;&lt;em&gt;Active&lt;/em&gt;&lt;/strong&gt; to true. This will set our workflow to active and execute the workflow every time a new receipt is submitted to Typeform.&lt;/p&gt;

&lt;p&gt;Open the Bravo Vision app on your device and select the Expense Tracker app. Click on the &lt;strong&gt;&lt;em&gt;Add new receipt&lt;/em&gt;&lt;/strong&gt; button and submit an image of the receipt.&lt;/p&gt;

&lt;p&gt;If you don’t have a receipt at hand now, feel free to use the following image of the receipt for testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OhqIOUcY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/960/0%2Aqqco5Y1mCAtm1vga" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OhqIOUcY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/960/0%2Aqqco5Y1mCAtm1vga" alt="Image of a receipt"&gt;&lt;/a&gt;A receipt for testing your workflow&lt;/p&gt;

&lt;p&gt;You can see the new receipt and the information on the ‘My Receipts’ screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XxG1m0oL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/0%2AUSKl2aoTNeDR2lmD" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XxG1m0oL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/0%2AUSKl2aoTNeDR2lmD" alt="Viewing the receipt in Bravo Vision"&gt;&lt;/a&gt;My Receipts page after adding the receipt&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What’s next?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can extend the workflow and send an email every time you add a new expense, using either the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.emailSend/"&gt;Send Email&lt;/a&gt; node or the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.gmail/#gmail"&gt;Gmail&lt;/a&gt; node. You can also use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.twilio/#twilio"&gt;Twilio&lt;/a&gt; node or the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.vonage/#vonage"&gt;Vonage&lt;/a&gt; node to send an SMS when a new expense gets added.&lt;/p&gt;

&lt;p&gt;You can also create a new workflow that will send you a weekly or monthly notification about the expenses you made during that period. This workflow can be built using the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.cron/#cron"&gt;Cron&lt;/a&gt; node to trigger the workflow weekly or monthly, the Airtable node to read the data, and the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.function/#function"&gt;Function&lt;/a&gt; node to calculate the sum of the expenses. To send a push notification, you can use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.pushover/#pushover"&gt;Pushover&lt;/a&gt; node.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this article, you learned how to build an application. You learned to design an app in Figma that is compatible with Bravo Studio. You also created the front-end of the app using Bravo Studio. You stitched different services together using n8n to get the desired output. Lastly, you learned how to bind data to your app in Bravo Studio.&lt;/p&gt;

&lt;p&gt;I plan to add more features to the app that will help me build a healthy habit of keeping track of my expenses and help me manage them.&lt;/p&gt;

&lt;p&gt;I’d love to hear about how you extend the app using n8n! If you run into any issues while following the tutorial, feel free to me on &lt;a href="https://twitter.com/harshil1712"&gt;Twitter&lt;/a&gt; or ask for help on our &lt;a href="https://community.n8n.io"&gt;forum&lt;/a&gt; 🧡&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Further Reading&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you would like to dig deeper and learn more about the topics discussed in the article, consult the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.notion.so/Setting-up-your-Figma-file-4a4fa15121284c34a9618e5246a0d7eb"&gt;Setting up your Figma File&lt;/a&gt;: You can read more about making a Bravo Studio compatible Figma design on Bravo Studios’ official documentation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.notion.so/Bravo-Tags-Master-List-145bec845f0b4afaa9e3bb8321b218a8"&gt;Bravo Tags Master List&lt;/a&gt;: Bravo Studio also has various other Bravo Tags that you can use to add more components to your app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io"&gt;n8n documentation&lt;/a&gt;: Check out the official documentation of n8n for more tutorials and reference information&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://n8n.io/integrations"&gt;n8n integrations&lt;/a&gt;: You can extend the functionality of your app by different nodes. Check out the list of all the integrations that n8n provides.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://n8n.io/workflows"&gt;n8n workflows&lt;/a&gt;: n8n has an extensive library of workflows ready for you to use.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/n8n-io/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n-c47eb2f8d7a5"&gt;Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n&lt;/a&gt;: If you are interested in building a Telegram bot instead of the application, check out this article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This &lt;a href="https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/"&gt;post&lt;/a&gt; originally appeared on the n8n.io &lt;a href="https://n8n.io/blog/"&gt;blog&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>n8n</category>
      <category>typeform</category>
      <category>airtable</category>
      <category>apps</category>
    </item>
    <item>
      <title>How to automatically give kudos to contributors with GitHub, Slack, and n8n 👏</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 14 Aug 2020 08:01:15 +0000</pubDate>
      <link>https://forem.com/n8n/giving-kudos-to-contributors-with-github-slack-and-n8n-kob</link>
      <guid>https://forem.com/n8n/giving-kudos-to-contributors-with-github-slack-and-n8n-kob</guid>
      <description>&lt;p&gt;People are the heart of a community. Celebrating their contributions is a way to show them that we value them and appreciate all their hard work. We can give them a shoutout in our community’s &lt;a href="https://slack.com"&gt;Slack&lt;/a&gt; workspace and also in our newsletters. And what could be a better way to appreciate their work by sending them some cool swag! Motivated by this idea, I created a workflow with &lt;a href="http://n8n.io"&gt;n8n&lt;/a&gt;, which gives us the contributors’ &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; information in the Slack workspace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MMEdlo9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Avspl20vxlYWE0PWLqepi_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MMEdlo9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Avspl20vxlYWE0PWLqepi_w.png" alt=""&gt;&lt;/a&gt;Giving kudos to contributors with GitHub, Slack, and n8n&lt;/p&gt;

&lt;p&gt;We will accomplish this through these four nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.webhook"&gt;&lt;strong&gt;&lt;em&gt;Webhook&lt;/em&gt;&lt;/strong&gt; node&lt;/a&gt; — Triggers the workflow when the slash command is issued&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.graphql"&gt;&lt;strong&gt;&lt;em&gt;GraphQL&lt;/em&gt;&lt;/strong&gt; node&lt;/a&gt; — Gets information using GitHub’s GraphQL API&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.function"&gt;&lt;strong&gt;&lt;em&gt;Function&lt;/em&gt;&lt;/strong&gt; node&lt;/a&gt; — Filters and extracts the contributor’s email address&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.slack/"&gt;&lt;strong&gt;&lt;em&gt;Slack&lt;/em&gt;&lt;/strong&gt; node&lt;/a&gt; — Posts the information back in Slack&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we issue a slash command in the Slack channel, the &lt;em&gt;Webhook&lt;/em&gt; node gets triggered, and our workflow starts. The &lt;em&gt;GraphQL&lt;/em&gt; node then executes a query to get the contributor’s information. The &lt;em&gt;Function&lt;/em&gt; node extracts the email address of the contributor and the &lt;em&gt;Slack&lt;/em&gt; node posts this information in the Slack channel from where the information was requested.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To get started with the workflow in n8n, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; or &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; installed on your machine to run n8n. You can also sign-up for &lt;a href="https://n8n.io/cloud"&gt;n8n.cloud&lt;/a&gt; to get access to our hosted service (in beta)&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://api.slack.com/apps"&gt;Slack app&lt;/a&gt; for your workspace&lt;/li&gt;
&lt;li&gt;GitHub &lt;a href="https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token"&gt;Personal Access Token&lt;/a&gt; for the GraphQL API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install n8n&lt;/strong&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you’re using n8n.cloud, you can skip this section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In case, you don’t already have n8n installed, you can do so with &lt;a href="https://www.npmjs.com/get-npm"&gt;npm&lt;/a&gt; by issuing 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;npm install n8n -g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run n8n using &lt;a href="https://github.com/n8n-io/n8n/blob/master/docker/images/n8n/README.md?ref=hackernoon.com#start-n8n-in-docker"&gt;Docker&lt;/a&gt;. Once you have installed n8n, you can start it using 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;n8n start — tunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Make sure that you don’t forget to add the — tunnel parameter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;n8n has to be reachable from the web as the triggers of external services rely on that to be able to send data to the webhooks. To make that easy, n8n has a special tunnel service that redirects requests from n8n’s servers to your local n8n instance (uses &lt;a href="https://github.com/localtunnel/localtunnel"&gt;localtunnel&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Typing “o” in the terminal will open the Editor UI for us.&lt;/p&gt;

&lt;p&gt;Let’s get started with the workflow. I have also submitted this &lt;a href="https://n8n.io/workflows/563"&gt;workflow&lt;/a&gt; on n8n.io, in case you’d like to skim through it. Please note that you will still need to configure credentials for Slack and GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Webhook node&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;n8n has a &lt;em&gt;Webhook&lt;/em&gt; trigger node which will get triggered when we issue the &lt;code&gt;/github&lt;/code&gt; slash command in a Slack channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Adding the Webhook node&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To add the &lt;em&gt;Webhook&lt;/em&gt; node in the workflow, click on the '&lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt;' button. Under the &lt;strong&gt;&lt;em&gt;Trigger&lt;/em&gt;&lt;/strong&gt; section, select the &lt;em&gt;Webhook&lt;/em&gt; node. This creates the &lt;em&gt;Webhook&lt;/em&gt; node with the default parameters.&lt;/p&gt;

&lt;p&gt;Leave the default parameters as they are, we will only change the HTTP Method. Select the ‘POST’ option from the &lt;strong&gt;&lt;em&gt;HTTP Method&lt;/em&gt;&lt;/strong&gt; dropdown list.&lt;/p&gt;

&lt;p&gt;Here’s a video of me following the steps mentioned above.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;2. Adding slash command to the Slack app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you haven’t created a Slack app, go to the &lt;a href="https://api.slack.com/apps"&gt;Applications&lt;/a&gt; page, click on ‘Create New App’ and give your app a name.&lt;/p&gt;

&lt;p&gt;Under the &lt;em&gt;Add Features and Functionality&lt;/em&gt; section, select &lt;em&gt;Slash Commands&lt;/em&gt; and click on &lt;em&gt;Create New Command&lt;/em&gt;. Enter ‘github’ as the command for the Command field. Get the test webhook URL from the Webhook node and paste it in the &lt;strong&gt;&lt;em&gt;Request URL&lt;/em&gt;&lt;/strong&gt; field. Since we are building the workflow, make sure to use the test webhook URL.&lt;/p&gt;

&lt;p&gt;The data that is sent to the test webhook URL is displayed in the Editor UI. The test webhook stays active for 120 seconds and then gets deactivated. The Production URL is only registered when the workflow has been activated, but the data that is sent is not displayed in the Editor UI.&lt;/p&gt;

&lt;p&gt;To give our app permission to post messages, select &lt;em&gt;OAuth &amp;amp; Permissions&lt;/em&gt; under the &lt;em&gt;Features&lt;/em&gt; section. In &lt;em&gt;Scopes&lt;/em&gt;, under the &lt;em&gt;Bot Token Scopes&lt;/em&gt;, click on &lt;em&gt;Add an OAuth Scope&lt;/em&gt; and select the ‘chat:write’ scope from the menu. Similarly, add the ‘chat:write.public’ scope.&lt;/p&gt;

&lt;p&gt;Install the app in your workspace. Click on &lt;strong&gt;&lt;em&gt;Execute Workflow&lt;/em&gt;&lt;/strong&gt; button at the bottom of the n8n workflow editor, and issue the &lt;code&gt;/github harshil1712&lt;/code&gt; (here ‘harshil1712’ is my GitHub username) command to trigger the &lt;em&gt;Webhook&lt;/em&gt; node.&lt;/p&gt;

&lt;p&gt;Here’s a video of me following the steps mentioned above.&lt;/p&gt;

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

&lt;p&gt;Go back to the n8n workflow editor and check the &lt;em&gt;Webhook&lt;/em&gt; node. You’ll see the response from our newly created slash command. Congratulations, your first n8n node is up and running!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. GraphQL Node&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;n8n has a &lt;em&gt;GraphQL&lt;/em&gt; node which can be used to execute GraphQL queries. We will use GitHub’s &lt;a href="https://docs.github.com/en/graphql"&gt;GraphQL API&lt;/a&gt; in this node to get the contributor’s information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Creating a GraphQL node to get contributors information&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the n8n workflow editor, click on &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; and select the &lt;em&gt;GraphQL&lt;/em&gt; node. We will have to specify the endpoint for the GraphQL API. We will also have to change the Request and Response Formats and add headers.&lt;/p&gt;

&lt;p&gt;Enter the following link in the &lt;strong&gt;&lt;em&gt;Endpoint&lt;/em&gt;&lt;/strong&gt; field: &lt;a href="https://api.github.com/graphql"&gt;https://api.github.com/graphql&lt;/a&gt;. This is the link to GitHub’s GraphQL API. Select JSON from the dropdown menu, for the &lt;strong&gt;&lt;em&gt;Request Format&lt;/em&gt;&lt;/strong&gt; field.&lt;/p&gt;

&lt;p&gt;The GitHub GraphQL API requires two headers for running any queries. The first header we will add is the User-Agent header. Click on &lt;strong&gt;&lt;em&gt;Add Header&lt;/em&gt;&lt;/strong&gt; in the &lt;strong&gt;&lt;em&gt;Header&lt;/em&gt;&lt;/strong&gt; section. Enter User-Agent in the &lt;strong&gt;&lt;em&gt;Name&lt;/em&gt;&lt;/strong&gt; field, and n8n in the &lt;strong&gt;&lt;em&gt;Value&lt;/em&gt;&lt;/strong&gt; field. Add another header for Authorization. Enter Authorization in the &lt;strong&gt;&lt;em&gt;Name&lt;/em&gt;&lt;/strong&gt; field. The value for this header will be in the following format: &lt;code&gt;bearer &amp;lt;GitHub-Personal-Access-Token&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;&amp;lt;GitHub-Personal-Access-Token&amp;gt;&lt;/code&gt; with your GitHub Personal Access Token. The Headers should look like in the following image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7ttRbmqC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/0%2ACtNk1c7jRBhhMGOY" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7ttRbmqC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/720/0%2ACtNk1c7jRBhhMGOY" alt="Headers for the GraphQL node"&gt;&lt;/a&gt;Headers for the GraphQL node&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; While generating the GitHub Personal Access token, make sure to select repo and user under the Select scopes section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qF1aqLb0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQZ0Nh9dQ-XgqiMtM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qF1aqLb0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQZ0Nh9dQ-XgqiMtM" alt="Selecting repo and user scope for GitHub Access Token"&gt;&lt;/a&gt;Selecting repo and user scope for GitHub Access Token&lt;/p&gt;

&lt;p&gt;Copy and paste the following query in the Edit Query editor and click on the &lt;strong&gt;&lt;em&gt;Execute Node&lt;/em&gt;&lt;/strong&gt; button to execute the node. On successful execution, it returns the name of the contributor whose username you have passed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
    user(login:"harshil1712") {
        name
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a video of me following the steps mentioned above.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;2. Getting more contributor’s information like company, email, and location&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the query above, we are passing the username statically, which will give us the information about only that contributor, for every slash command we issue. To make the query dynamic, we will fetch the username returned by the &lt;em&gt;Webhook&lt;/em&gt; node.&lt;/p&gt;

&lt;p&gt;Connect the &lt;em&gt;Webhook&lt;/em&gt; node with the &lt;em&gt;GraphQL&lt;/em&gt; node. Open the Edit Expression editor for the &lt;strong&gt;&lt;em&gt;Query&lt;/em&gt;&lt;/strong&gt; field, and replace the username with &lt;code&gt;{{$node[“Webhook”].json[“body”][“text”]}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also do this by selecting:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Current Node&amp;gt; Input Data &amp;gt; JSON &amp;gt; body &amp;gt; text&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s a video of me following the steps mentioned above.&lt;/p&gt;

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

&lt;p&gt;We are now getting the name of the contributor we want. Let’s get more information about them. We will update our query to get additional information like their email address, location, the company they work for, and their profile picture.&lt;/p&gt;

&lt;p&gt;Copy and paste the below query in the Edit Query editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
    user(login:"{{$node["Webhook"].json["body"]["text"]}}") {
        name
        company
        location
        avatarUrl
        email
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On executing the workflow, you will get output similar to the following image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vnTe6Ezx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AAP3H-du_wwvKnG7q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vnTe6Ezx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AAP3H-du_wwvKnG7q" alt="Output from the GraphQL node"&gt;&lt;/a&gt;Output from the GraphQL node&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Function Node&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Some of the contributors on GitHub might have their email addresses private, and so we don’t get this information. But what if we want to get in touch with them, and thank them personally?&lt;/p&gt;

&lt;p&gt;To get their email address, we will query their commits. The commit object contains information about the author like their name and email address. Let’s go ahead and update our GraphQL query so that we get at least 25 of their commits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Update the GraphQL query&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;GraphQL&lt;/em&gt; node, open the Edit Expression editor for the &lt;strong&gt;&lt;em&gt;Query&lt;/em&gt;&lt;/strong&gt; field. Copy and paste the query below in the editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
    user(login:"{{$node["Webhook"].json["body"]["text"]}}"){
        name
        company
        location
        avatarUrl
        email
        pullRequests(last: 25) {
            edges {
                node {
                    commits(last:25) {
                        nodes {
                            commit {
                                author {
                                    email
                                    name
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Execute the node to see the changes in effect. The output now contains the email addresses and names of the authors who made the commits as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9mOglCmY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ADzum3DAdRIQjDNkz" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9mOglCmY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ADzum3DAdRIQjDNkz" alt=""&gt;&lt;/a&gt;Output from the updated GraphQL node&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Using Function node to filter the information&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One can observe from the output that we are getting a lot of repeated values for the email addresses. Also, some email addresses belong to different users. We will write a function to solve this and get the email address of our contributor.&lt;/p&gt;

&lt;p&gt;n8n has a &lt;em&gt;Function&lt;/em&gt; node where we can add custom snippets to JavaScript code to transform data from the other nodes or if you want to implement some custom functionality. Click on the '&lt;strong&gt;+&lt;/strong&gt;' button and select the &lt;em&gt;Function&lt;/em&gt; node. Replace the code in the &lt;em&gt;Function&lt;/em&gt; node, with the following 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;let&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="o"&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;tempEmails&lt;/span&gt; &lt;span class="o"&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GraphQL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&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="s2"&gt;data&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="s2"&gt;user&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="s2"&gt;name&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;publicEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GraphQL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&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="s2"&gt;data&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="s2"&gt;user&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="s2"&gt;email&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&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="s2"&gt;text&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;nameRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;g&lt;/span&gt;&lt;span class="dl"&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;publicEmail&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// if public email address exists, push it to the tempEmails array&lt;/span&gt;
    &lt;span class="nx"&gt;tempEmails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// looping through the pull requests&lt;/span&gt;
&lt;span class="k"&gt;for&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;edge&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;json&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;data&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="nx"&gt;pullRequests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// looping through the commits&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// Checks the name associated with the email address&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;nameRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// if name equals to contributors name or username, push the email address in tempEmails&lt;/span&gt;
           &lt;span class="nx"&gt;tempEmails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Remove duplicates&lt;/span&gt;
&lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempEmails&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="c1"&gt;// RegEx Pattern for email address generated by GitHub&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;)\*&lt;/span&gt;&lt;span class="sr"&gt;@users.noreply.github.com/&lt;/span&gt;

&lt;span class="c1"&gt;// Remove the email addresses Generated by GitHub&lt;/span&gt;
&lt;span class="nx"&gt;emails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;test&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,}}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code takes the name and the public email address of the contributor from the &lt;em&gt;GraphQL&lt;/em&gt; node. It also gets the username from the &lt;em&gt;Webhook&lt;/em&gt; node. The code then verifies if the email address belongs to the contributor, and if it does, it pushes it to a temporary array. It then removes any duplicate values for the email addresses and stores them in the emails array. And lastly, it removes email addresses generated by GitHub and returns the emails array.&lt;/p&gt;

&lt;p&gt;An important thing to keep in mind while using the &lt;em&gt;Function&lt;/em&gt; node is that it returns an array. So make sure you’re returning an array, rather than an object.&lt;/p&gt;

&lt;p&gt;Here’s a video of me following the steps mentioned above.&lt;/p&gt;

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

&lt;p&gt;We are now getting the email address of the contributor along with all the other information. Let’s post this in Slack.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Slack Node&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In n8n, you can perform a lot of operations with the &lt;em&gt;Slack&lt;/em&gt; node. You can create or archive channels, upload or get files from the workspace, add or delete stars from an item, and post or update messages in the Slack channels.&lt;/p&gt;

&lt;p&gt;To add the &lt;em&gt;Slack&lt;/em&gt; node in the workflow, click on the '&lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt;' button, and select Slack. Select “OAuth2” from the &lt;strong&gt;&lt;em&gt;Authentication&lt;/em&gt;&lt;/strong&gt; dropdown menu. Add your Slack app credentials to the node by selecting “Create New” from the dropdown menu in the &lt;strong&gt;&lt;em&gt;Credentials&lt;/em&gt;&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;Head back to the Slack App dashboard, and copy the Client ID and Client Secret from the App Credentials section. Paste them in the &lt;strong&gt;&lt;em&gt;Create Credentials: “Slack OAuth2 API”&lt;/em&gt;&lt;/strong&gt; editor in the n8n workflow editor. Copy the OAuth Callback URL from the editor. In the Slack App dashboard, select “OAuth and Permissions” and click on “Add New Redirect URL” under the “Redirect URLs” section. Paste the URL and click on “Add”. The last step is to connect the OAuth Credentials. Click on the &lt;strong&gt;&lt;em&gt;OAuth&lt;/em&gt;&lt;/strong&gt; button to connect the credentials and select “Allow”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CXiXoldX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AzJjp7JqnUPC7feMB" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CXiXoldX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AzJjp7JqnUPC7feMB" alt="Adding Redirect URL to Slack App"&gt;&lt;/a&gt;Adding Redirect URL to Slack App&lt;/p&gt;

&lt;p&gt;By default, the &lt;em&gt;Slack&lt;/em&gt; node has Message as the Resource and Post as the Operation. If the setting is different for you, make sure to change them. To post a message on the Slack channel where the slash command was issued, we will add the channel id to the Channel field, which is returned by the Webhook node.&lt;/p&gt;

&lt;p&gt;Copy and paste &lt;code&gt;{{$node[“Webhook”].json[“body”][“channel_id”]}}&lt;/code&gt; in the &lt;strong&gt;&lt;em&gt;Channel&lt;/em&gt;&lt;/strong&gt; field. Alternatively you can use the Variable Selector to get this information. Open the Editor Expression editor, and under &lt;strong&gt;&lt;em&gt;Variable Selector&lt;/em&gt;&lt;/strong&gt; select: &lt;code&gt;Nodes &amp;gt; Webhook &amp;gt; Output Data &amp;gt; JSON &amp;gt; body &amp;gt; channel_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let us now add some styling and formatting to our message. Our message will contain a title, some text, and a thumbnail.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;Attachment&lt;/em&gt;&lt;/strong&gt; section, click on &lt;strong&gt;&lt;em&gt;Add Attachment&lt;/em&gt;&lt;/strong&gt; , and select &lt;strong&gt;&lt;em&gt;Title&lt;/em&gt;&lt;/strong&gt; from the Add Attachment Item dropdown menu. Open the Expression editor, and type “GitHub Details for:” in the editor and from the &lt;strong&gt;&lt;em&gt;Variable Selector&lt;/em&gt;&lt;/strong&gt; select Nodes &amp;gt; Webhook &amp;gt; Output Data &amp;gt; JSON &amp;gt; body &amp;gt; text.&lt;/p&gt;

&lt;p&gt;From the &lt;strong&gt;&lt;em&gt;Add Attachment Item&lt;/em&gt;&lt;/strong&gt; , select &lt;strong&gt;&lt;em&gt;Text&lt;/em&gt;&lt;/strong&gt; , to add the Text attachment. Open the Expression editor, and copy and paste the following text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*Name:* {{$node[“GraphQL”].json[“data”][“data”][“user”][“name”]}}

*Email:* {{$node[“Function”].json[“emails”].join(‘,‘)}}

*Company:* {{$node[“GraphQL”].json[“data”][“data”][“user”][“company”]}}

*Location:* {{$node[“GraphQL”].json[“data”][“data”][“user”][“location”]}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To display the profile picture of the contributor, create Thumbnail attachment, by selecting the &lt;strong&gt;&lt;em&gt;Thumbnail&lt;/em&gt;&lt;/strong&gt; option from the &lt;strong&gt;&lt;em&gt;Add Attachment Item&lt;/em&gt;&lt;/strong&gt; menu. Open the Edit Expression editor and from the Variable Selector select &lt;code&gt;Nodes &amp;gt; GraphQL &amp;gt; Output Data &amp;gt; JSON &amp;gt; data &amp;gt; data &amp;gt; user &amp;gt; avatarURL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a video showing how to create the &lt;em&gt;Slack&lt;/em&gt; node, and get information from the Webhook node, the GraphQL node, and the Function node.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Since the &lt;em&gt;Function&lt;/em&gt; node gives an array of email addresses, we will select &lt;strong&gt;&lt;em&gt;Values&lt;/em&gt;&lt;/strong&gt; from the menu, while adding the email from the node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Execute the node, and your app will post a message to the Slack channel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ApNsRL2V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ApEqmP2LcXICP_ssv" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ApNsRL2V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ApEqmP2LcXICP_ssv" alt=""&gt;&lt;/a&gt;Output from the Slack node&lt;/p&gt;

&lt;p&gt;The following video shows our workflow in action.&lt;/p&gt;

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

&lt;p&gt;To use the workflow in production, follow the instructions provided in the &lt;a href="https://docs.n8n.io/reference/server-setup.html"&gt;documentation&lt;/a&gt;. Make sure to use the production webhook URL for the slash command.&lt;/p&gt;

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

&lt;p&gt;Congratulations! You built a workflow that gives you the information of a contributor. You learned how to get started with n8n and how to add nodes to your workflow. You learned how to use the &lt;em&gt;Webhook&lt;/em&gt; node for capturing event triggers, the &lt;em&gt;GraphQL&lt;/em&gt; node to query information, the &lt;em&gt;Function&lt;/em&gt; node to write custom functions, and the &lt;em&gt;Slack&lt;/em&gt; node to post a message on Slack.&lt;/p&gt;

&lt;p&gt;You can use this workflow to gather the information about your contributors, celebrate their successes, and appreciate them for their contributions! Using the GitHub API, you can also get their Twitter username. You can use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.if/"&gt;&lt;em&gt;IF&lt;/em&gt;&lt;/a&gt; node to check for that, and use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.twitter/"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt; node to tweet about them. You can even use the &lt;a href="https://docs.n8n.io/nodes/n8n-nodes-base.mailgun/"&gt;&lt;em&gt;Mailgun&lt;/em&gt;&lt;/a&gt; node to send them a personalized thank you message.&lt;/p&gt;

&lt;p&gt;I’d be excited to check out what you’ve built using n8n! In case you’ve run into an issue while following the tutorial, feel free to reach out to me on &lt;a href="https://twitter.com/harshil1712"&gt;Twitter&lt;/a&gt; or ask for help on our &lt;a href="https://community.n8n.io/"&gt;forum&lt;/a&gt; 💙&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://n8n.io/blog/how-to-automatically-give-kudos-to-contributors-with-github-slack-and-n8n/"&gt;post&lt;/a&gt; originally appeared on the &lt;a href="https://n8n.io"&gt;n8n.io&lt;/a&gt; &lt;a href="https://n8n.io/blog"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>community</category>
      <category>slack</category>
      <category>github</category>
      <category>automation</category>
    </item>
    <item>
      <title>Women of React 2020 - Throwback</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 01 May 2020 19:25:43 +0000</pubDate>
      <link>https://forem.com/harshil1712/women-of-react-2020-throwback-1n9</link>
      <guid>https://forem.com/harshil1712/women-of-react-2020-throwback-1n9</guid>
      <description>&lt;p&gt;Amazing speaker line-up? Check ✅&lt;br&gt;
Awesome Emcee? Check ✅&lt;br&gt;
Accessible? Check ✅&lt;br&gt;
A/V? Check ✅&lt;br&gt;
Being on schedule? Check ✅&lt;br&gt;
React is a potato? Umm Okay!&lt;br&gt;
And the list goes on. &lt;/p&gt;

&lt;p&gt;Women of React 2020 was a conference like no other. The conference had talks for everyone, be it a beginner or someone experienced. &lt;/p&gt;

&lt;p&gt;Let me give you the highlights of all the fun and learning I had, attending this virtual conference.&lt;/p&gt;

&lt;p&gt;The conference started with &lt;a href="https://twitter.com/rachelnabors" rel="noopener noreferrer"&gt;Rachel Nabors&lt;/a&gt; giving the welcoming keynote, and sharing the story of how Women of React 2020 was organized. She also shared her inspiring developer journey.&lt;/p&gt;

&lt;p&gt;I'm an advocate for accessibility and have been encouraging people to build accessible websites. I also gave a &lt;a href="https://www.youtube.com/watch?v=7NLiq3oUADs" rel="noopener noreferrer"&gt;talk&lt;/a&gt; at DevFest Ranchi on accessibility, and listing to the talk "TL;DR Accessible Components : tips for building out accessible components" by &lt;a href="https://twitter.com/yurm04" rel="noopener noreferrer"&gt;Yuraima Estevez&lt;/a&gt; helped me learn more about accessibility. Yuraima explained what accessibility is and why it is important. She also shared some insights on how to make accessible components. She talked about the three easy parts and explains each one of them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Semantic HTML&lt;/li&gt;
&lt;li&gt;ARIA Attributes&lt;/li&gt;
&lt;li&gt;Keyboard Navigation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find her slides &lt;a href="https://tldr-a11y.yuraima.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and learn more about accessibility.&lt;br&gt;
&lt;a href="https://twitter.com/mintiiB" rel="noopener noreferrer"&gt;Brittney Braxton&lt;/a&gt; also made a sketch note for the talk. &lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;Next up was &lt;a href="https://twitter.com/hellonehha" rel="noopener noreferrer"&gt;Neha Sharma&lt;/a&gt;. She shared her experience on building a Design System in her organization and the lessons she learned on this journey. Neha talked about &lt;a href="https://atomicdesign.bradfrost.com/" rel="noopener noreferrer"&gt;Atomic Design&lt;/a&gt; and explained how they adopted it. &lt;br&gt;
Some challenges they faced and learnings from them, that Neha shared are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Think of scalability in terms of 'reusability', this will help you build a scalable design system.&lt;/li&gt;
&lt;li&gt;Convincing teams to use and follow can be hard.&lt;/li&gt;
&lt;li&gt;Get early previews and feedback which will help you understand what the teams need, and help you learn if you're missing out something.&lt;/li&gt;
&lt;li&gt;Documenting the whole process is important.&lt;/li&gt;
&lt;li&gt;Use tools and automation for the code part that are important.
Checkout this Twitter thread to know more about her talk.
&lt;iframe class="tweet-embed" id="tweet-1254103619181346816-595" src="https://platform.twitter.com/embed/Tweet.html?id=1254103619181346816"&gt;
&lt;/iframe&gt;

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



&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://twitter.com/TaleyaMirza" rel="noopener noreferrer"&gt;Taley'a Mirza&lt;/a&gt; gave a talk titled "Level up your Design System with styled-system" in which she discussed about the most common challenges in design system, how we can use style-system to solve them and principles of styled-system.&lt;/p&gt;

&lt;p&gt;The conference also had yoga. Yes, your read it right. In the break there was a small yoga session conducted by &lt;a href="https://twitter.com/lunaleaps" rel="noopener noreferrer"&gt;Luna Wei&lt;/a&gt; which was refreshing.&lt;/p&gt;

&lt;p&gt;Fireside chats are the best! Thank you Women of React for organizing it and Rachel Nabors, &lt;a href="https://twitter.com/NikkitaFTW" rel="noopener noreferrer"&gt;Sara Vieira&lt;/a&gt;, &lt;a href="https://twitter.com/gurlcode" rel="noopener noreferrer"&gt;Jenn Creighton&lt;/a&gt;, &lt;a href="https://twitter.com/cassidoo" rel="noopener noreferrer"&gt;Cassidy Williams&lt;/a&gt;, &lt;a href="https://twitter.com/ParissAthena" rel="noopener noreferrer"&gt;Pariss Athena&lt;/a&gt;, and &lt;a href="https://twitter.com/shrutikapoor08" rel="noopener noreferrer"&gt;Shruti Kapoor&lt;/a&gt; for sharing your experiences and knowledge with the community. They talked about their journey of getting into public speaking and answered questions from the audience. A few questions were around how to get started with speaking at conferences while others were around how to select a topic for a talk. They answered these questions sharing what worked for them and the steps they took to get there.&lt;/p&gt;

&lt;p&gt;The next talk was one of the best talks I've seen. Conclusion of the talk, React is a Potato. &lt;a href="https://twitter.com/Mappletons" rel="noopener noreferrer"&gt;Maggie Appleton&lt;/a&gt; explained React using visual metaphors. She explained how React works, talked about props and state, all by comparing React to a potato. Maggie where well explained how visual metaphors can help in teaching concepts and encouraged us all to adopt this effective technique. She also share a lot of techniques and tools that we can take advantage of for building visual metaphor content.&lt;br&gt;
Some of the tools Maggie shared are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://figma.com/" rel="noopener noreferrer"&gt;Figma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://miro.com/" rel="noopener noreferrer"&gt;Miro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://whimsical.com" rel="noopener noreferrer"&gt;Whimsical&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://excalidraw.com/" rel="noopener noreferrer"&gt;Exaclidraw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://procreate.art/" rel="noopener noreferrer"&gt;Procreate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Keynote&lt;/li&gt;
&lt;li&gt;Powerpoint&lt;/li&gt;
&lt;li&gt;CSS, SVG or &lt;a href="https://greensock.com/" rel="noopener noreferrer"&gt;Greensock&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also find some really good resources Maggie shared &lt;a href="https://illustrated.dev/resources/" rel="noopener noreferrer"&gt;https://illustrated.dev/resources/&lt;/a&gt;&lt;br&gt;
Maggie goes on explaining how we can build metaphors. She shared 4 important points to consider when we exercise it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find your nouns and verbs.&lt;/li&gt;
&lt;li&gt;State one main concept in simple terms.&lt;/li&gt;
&lt;li&gt;Pick functions and key qualities to highlight.&lt;/li&gt;
&lt;li&gt;Think laterally to find alternatives.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let us try to use visual metaphors in our next tutorial/video and build a better learning experience!&lt;/p&gt;

&lt;p&gt;Developer Tools are a developers best friend. They increase productivity and help save a lot of time. &lt;a href="https://twitter.com/imAnushree" rel="noopener noreferrer"&gt;Anushree Subramani&lt;/a&gt; gave a talk on React Dev Tools. She took us through the journey of how Anika, a junior developer, learned about the dev tools, and how it increased her productivity. She also shared the tale of how Anika was mentored by a senior developer, Radhika.&lt;br&gt;
In her talk Anushree illustrated the fast refresh, props/state editor, component tree navigation and a lot more.&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1254148295305412608-579" src="https://platform.twitter.com/embed/Tweet.html?id=1254148295305412608"&gt;
&lt;/iframe&gt;

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



 &lt;br&gt;
At the end of her talk, Anushree motivated us all and encouraged to help and mentor people who need it. &lt;br&gt;
Mentorship is a beautiful thing. By mentoring someone you can help them reach their potential and become better versions of themselves. And in this period of time, people need someone to talk to, share their story, their success and their failure. Mentorship has personally helped me. I had a chance to have some amazing mentors, people who I can reach out to talk to whenever I am stuck, need help or just to have a normal conversation. And we want to bring this to more people. For the same reason I, and &lt;a href="https://twitter.com/pransh15" rel="noopener noreferrer"&gt;Pranshu Khanna&lt;/a&gt; decided to start taking mentorship calls, for free, and help people. &lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1241812203268784128-109" src="https://platform.twitter.com/embed/Tweet.html?id=1241812203268784128"&gt;
&lt;/iframe&gt;

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



&lt;/p&gt;

&lt;p&gt;After the short break it was time for some lighting talks.&lt;br&gt;
The first lighting talk "The Most Important UI: You" by &lt;a href="https://twitter.com/carolstran" rel="noopener noreferrer"&gt;Carolyn Stransky&lt;/a&gt; was amazing. It talked about self-care. Carolyn explained its importance and shared tons of resources to take care of ourselves and have a healthy mental health. It is true that we in the tech industry don't focus a lot on self-care and are often the victim of burnout. One of the many tips Carolyn shared, my favorite one is asking ourselves daily - "What have I done today that feels nourishing, supportive and inspiring for my well-being?"&lt;br&gt;
Check out other &lt;a href="//bit.ly/self-care-talk-resources"&gt;resources&lt;/a&gt; Carolyn shared for self-care and a better mental health.&lt;br&gt;
The next lighting talk was by &lt;a href="https://twitter.com/frontendgirl" rel="noopener noreferrer"&gt;Olena Sovyn&lt;/a&gt; - "Testing, tEstIng, teStIng or how to test React apps with generated input data". She takes us through an example and explains a better way of writing tests when we have multiple combinations for the input data.&lt;br&gt;
&lt;a href="https://twitter.com/knitcodemonkey" rel="noopener noreferrer"&gt;Jen Luker&lt;/a&gt; live coded and explained the accessibility concepts around button and div. She showed how we can style a button, and make it look like a div, and how painful it is to use divs to built an accessible button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/eveporcello" rel="noopener noreferrer"&gt;Eve Porcello&lt;/a&gt; knows how to give a talk! The way Eve started her talk "React Finding the Fun: Using TDD with React" was so good, she made it look like she was giving the talk at an offline conference. In her talk Eve, explained Test Driven Development (TDD). She live coded and showed how TDD can be used to write better code. Eve time-traveled and came back from the future to complete her application and continued her talk. &lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;The last session was by &lt;a href="https://twitter.com/adriannavaldivi" rel="noopener noreferrer"&gt;Adrianna Valdivi&lt;/a&gt; on preparing for React Tech Interviews. Adrianna shared the most common questions asked in the interview, how one should answer these questions and the concepts that one should know very well. &lt;/p&gt;

&lt;p&gt;But this wasn't the end. We had a Q &amp;amp; A with people from the React Core team, and folks from Google Chrome team. We had &lt;a href="https://twitter.com/sophiebits" rel="noopener noreferrer"&gt;Sophie APlert&lt;/a&gt;, &lt;a href="https://twitter.com/ProvablyFlarnie" rel="noopener noreferrer"&gt;Flarnie Marchan&lt;/a&gt;, &lt;a href="https://twitter.com/lunaruan" rel="noopener noreferrer"&gt;Luna Ruan&lt;/a&gt;, &lt;a href="https://twitter.com/shubhie" rel="noopener noreferrer"&gt;Shubhie Panicker&lt;/a&gt;, &lt;a href="https://twitter.com/stubbornella" rel="noopener noreferrer"&gt;Nicole Sullivan&lt;/a&gt; and Rachel Nabors. They answered our questions on React, open source and shared their journey. They also shared some interesting tips on how to get started with contributing to Open Source.&lt;/p&gt;

&lt;p&gt;The blog post would be incomplete without mentioning the awesome and funny &lt;a href="https://twitter.com/cassidoo" rel="noopener noreferrer"&gt;Cassidy Williams&lt;/a&gt;. Cassidy was the emcee for the conference and she did a wonderful job! Thank you Cassidy for being such an great emcee.&lt;/p&gt;

&lt;p&gt;I would also like to thank the organizers Jenn Creighton, Sara Vieira, Rachel Nabors and &lt;a href="https://twitter.com/_phzn" rel="noopener noreferrer"&gt;Kevin Lewis&lt;/a&gt; for bringing this amazing conference to the community and making it accessible for all!&lt;/p&gt;

</description>
      <category>react</category>
      <category>womenintech</category>
      <category>conference</category>
      <category>virtual</category>
    </item>
    <item>
      <title>React Summit Remote Edition: My Experience</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Mon, 20 Apr 2020 19:35:48 +0000</pubDate>
      <link>https://forem.com/harshil1712/react-summit-remote-edition-my-experience-277i</link>
      <guid>https://forem.com/harshil1712/react-summit-remote-edition-my-experience-277i</guid>
      <description>&lt;p&gt;On April 17, 2020, the &lt;a href="https://reactsummit.com/"&gt;React Summit&lt;/a&gt; conference hosted a Remote Edition of the React Summit with two tracks, a React track and an Alt track, with 10+ sessions, 5 discussion rooms, and a lot of fun!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/rauchg"&gt;Guillermo Rauch&lt;/a&gt;, from Zeit, was the first speaker who talked about Next.js and the future of Serverless. He gave a lot of good insights. His talk convinced me more of using Next.js and explore the world of Serverless.&lt;/p&gt;

&lt;p&gt;The world is changing. With technologies like Augmented Reality, Virtual Reality and Artificial Intelligence, have you ever wondered how the future of user interaction looks like? Well, &lt;a href="https://twitter.com/VladimirNovick"&gt;Vladimir Novick&lt;/a&gt;, in his talk "Controlling apps with your mind and AI" amazingly showed what the future holds for user interaction. His talk displayed all the possibilities of the user interaction, and focused on understanding the reality and building reality-based interaction. He showed a cool demo with a Consumer EEG. He connected the headset with his browser through the Bluetooth WebAPI, and interacted with the web-page through brainwaves. He used the KNN classifier to differentiate the incoming waves which helped him define actions for a particular brainwave. The most coolest part of this session was when Vladimir flew a drone without a remote, but through his brainwaves. Checkout this Twitter thread from &lt;a href="https://twitter.com/archimydes"&gt;Archimydes&lt;/a&gt; where they've live tweeted his session and shared what they learnt.&lt;br&gt;
Liquid error: internal&lt;/p&gt;

&lt;p&gt;After the talk there was a Panel Discussion on JAMStack and Serveless hosted by &lt;a href="https://twitter.com/jlengstorf"&gt;Jason Lengstorf&lt;/a&gt;, with &lt;a href="https://twitter.com/mxstbr"&gt;Max Stoiber&lt;/a&gt; and Guillermo Rauch. It was very insightful. They discussed about the future of JAMStack and how GatsbyJS and Next.js are helping developers with JAMStack.&lt;/p&gt;

&lt;p&gt;The last session that I attended was of none other than &lt;a href="https://twitter.com/kentcdodds"&gt;Kent C. Dodds&lt;/a&gt;, titled "AHA Programming". In this talk Kent talks about the Avoid Hasty Abstractions abbreviated AHA, with an example. He explains that modifying the abstraction with the incoming changes is not always a good practice and it is okay to not follow DRY principles sometimes. &lt;br&gt;
The key takeaways from his talks are&lt;br&gt;
Liquid error: internal &lt;br&gt;
You can find his slides here.&lt;br&gt;
Also here's the list of resources that Kent shared&lt;br&gt;
Liquid error: internal&lt;/p&gt;

&lt;p&gt;The conference was very well organized and had a lot of amazing sessions. I couldn't attend all the sessions, but thankfully the organizers will soon upload the talks on YouTube. If you missed out, keep an eye on their YouTube channel.&lt;/p&gt;

&lt;p&gt;This conference also proved that remote conferences could be a thing. There are endless possibilities for a remote conference. The only thing I would miss is to network with people, offline, in real world. Sure we can network virtually, but for me, connecting with people in real world is far more interesting and fun! &lt;/p&gt;

&lt;p&gt;Looking forward to more such conferences! &lt;/p&gt;

&lt;p&gt;Stay safe everyone :)&lt;/p&gt;

</description>
      <category>react</category>
      <category>conference</category>
      <category>remote</category>
      <category>virtual</category>
    </item>
    <item>
      <title>Using Auth0 Hooks to store user information</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Sat, 29 Feb 2020 14:58:41 +0000</pubDate>
      <link>https://forem.com/harshil1712/using-auth0-hooks-to-store-user-information-4f0n</link>
      <guid>https://forem.com/harshil1712/using-auth0-hooks-to-store-user-information-4f0n</guid>
      <description>&lt;p&gt;Hooks have become really popular after its official release. They've truly made the lives of React Developers easy. You can know more about &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;React Hooks here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://auth0.com/"&gt;Auth0&lt;/a&gt;, who provides a seamless service to integrate authentication and authorization in you apps, have recently released Hooks, which are in beta. There are four different extensibility points where you can use these hooks.&lt;br&gt;
These extensibility points are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client Credentials Exchange&lt;/li&gt;
&lt;li&gt;Post Change Password&lt;/li&gt;
&lt;li&gt;Post User Registration&lt;/li&gt;
&lt;li&gt;Pre User Registration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This blog post focuses more on &lt;strong&gt;Post User Registration Hook&lt;/strong&gt;, but let's try and understand the other hooks as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client Credentials Exchange
&lt;/h2&gt;

&lt;p&gt;This particular hook can be used when you want to modify the scope for the user. Consider an example where you want to provide the user with the additional ability to read the resources. You can use this hook to modify the scope. To know more read the official &lt;a href="https://auth0.com/docs/hooks/extensibility-points/client-credentials-exchange"&gt;documentation&lt;/a&gt; from Auth0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post Change Password
&lt;/h2&gt;

&lt;p&gt;When your user changes their password you want to send them a notification email.This is the extensibility point where you want to execute the code to send them the notification. This is just one use-case for this hook, according to your requirements you can use this hook and notify the user. The official &lt;a href="https://auth0.com/docs/hooks/extensibility-points/post-change-password"&gt;Auth0 documentation&lt;/a&gt; covers this pretty well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Pre User Registration
&lt;/h2&gt;

&lt;p&gt;Let's say you want to store some additional information about the user. The Pre User Registration extensibility point is the perfect place for that. With this you can store &lt;code&gt;user_metadata&lt;/code&gt; or &lt;code&gt;app_metadata&lt;/code&gt;. To know more how to use this hook checkout the official &lt;a href="https://auth0.com/docs/hooks/extensibility-points/pre-user-registration"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post User Registration
&lt;/h2&gt;

&lt;p&gt;The Post User Registration helps you perform any activity you want once a user registers an account. It can be from sending an email notification, to notifying on the slack. It can also be used to add it your database, which is what we are going to learn to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the application
&lt;/h3&gt;

&lt;p&gt;For this demo  we will be using firebase as our database.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Setting up Firebase
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://console.firebase.google.com/"&gt;Firebase Console&lt;/a&gt; and login.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Create Project&lt;/strong&gt; and give your project a name. You can choose to disable Google Analytics for the project if you wish to.&lt;/li&gt;
&lt;li&gt;Once your project is created, select &lt;strong&gt;Develop&lt;/strong&gt; from the sidebar and then select &lt;strong&gt;Database&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;For this tutorial I'll be creating the Realtime database with the test mode selected&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you hit the enable button your database is created. &lt;/p&gt;

&lt;h4&gt;
  
  
  2. Setting up Auth0
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Auth0 gives us a default app to play with. We will this for the tutorial.&lt;/li&gt;
&lt;li&gt;On the left side there is an option of &lt;strong&gt;Hooks&lt;/strong&gt;. Once you select that you will see the above mentioned options.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Eo_8OOwN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7bwp8sks5e9rfnpljh7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eo_8OOwN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7bwp8sks5e9rfnpljh7r.png" alt="Default Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will create a new hook under Post User Registration. Click on &lt;code&gt;Create New Hook&lt;/code&gt; and give your hook a name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kzROTK5q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1p4bysy4a32nv13bbanj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kzROTK5q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1p4bysy4a32nv13bbanj.png" alt="Post User Registration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the text editor by clicking on the edit button to write some custom code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
@param {object} user - The user being created
@param {string} user.id - user id
@param {string} user.tenant - Auth0 tenant name
@param {string} user.username - user name
@param {string} user.email - email
@param {boolean} user.emailVerified - is e-mail verified?
@param {string} user.phoneNumber - phone number
@param {boolean} user.phoneNumberVerified - is phone number verified?
@param {object} user.user_metadata - user metadata
@param {object} user.app_metadata - application metadata
@param {object} context - Auth0 connection and other context info
@param {string} context.requestLanguage - language of the client agent
@param {object} context.connection - information about the Auth0 connection
@param {object} context.connection.id - connection id
@param {object} context.connection.name - connection name
@param {object} context.connection.tenant - connection tenant
@param {object} context.webtask - webtask context
@param {function} cb - function (error, response)
*/&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&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;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;request&lt;/span&gt;&lt;span class="dl"&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;post&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="s2"&gt;https://&amp;lt;USER-PROJECT-NAME&amp;gt;.firebaseio.com/user.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;json&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="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;email&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;cb&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;ul&gt;
&lt;li&gt;Hit on save to save your script. You can test it out using Runner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SRKCCFVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2947879cee56vkoe2av3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRKCCFVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2947879cee56vkoe2av3.png" alt="Text Editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now go back to the Firebase and you'll see new data has been added.&lt;/p&gt;

&lt;p&gt;Similarly you can add user information to your database, once the user has registered. &lt;/p&gt;

&lt;p&gt;Follow along &lt;a href="https://auth0.com/docs/quickstart/spa/react/01-login"&gt;this article&lt;/a&gt; from the Auth0 team to setup Auth0 with your React Application. &lt;/p&gt;

</description>
      <category>auth0</category>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>My GitHub Campus Expert Journey and how you can become one</title>
      <dc:creator>Harshil Agrawal</dc:creator>
      <pubDate>Fri, 01 Nov 2019 13:35:31 +0000</pubDate>
      <link>https://forem.com/harshil1712/my-github-campus-expert-journey-and-how-you-can-become-one-4den</link>
      <guid>https://forem.com/harshil1712/my-github-campus-expert-journey-and-how-you-can-become-one-4den</guid>
      <description>&lt;p&gt;I've been asked a lot about my GitHub Campus Expert journey and how can one become a GitHub Campus Expert. This is an attempt to answer those questions and express my gratitude to this amazing program.&lt;/p&gt;

&lt;p&gt;While browsing through the &lt;a href="https://education.github.com/" rel="noopener noreferrer"&gt;GitHub Education&lt;/a&gt; website, one day I landed on the &lt;a href="https://githubcampus.expert/" rel="noopener noreferrer"&gt;GitHub Campus Expert&lt;/a&gt; webpage. I skimmed through the webpage and understood that this program will help me start a community on my campus, and so I hit the &lt;em&gt;Become a Campus Expert&lt;/em&gt; button.&lt;/p&gt;

&lt;p&gt;Before applying to the program you need to verify that you're a student and for that you need to either upload your institute ID or sign-up with your institute email id. Once you've been verified you can proceed to the next step which is filling up the initial application.  I followed the same procedure and I got selected for the next phase.&lt;br&gt;
Did I mention that once you're verified as a Student you get $100000 worth of amazing developer tools and services to learn and improve your skills! Check it out &lt;a href="https://education.github.com/pack" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second phase of the program is the training, where you work with amazingly designed modules which helps you to be a better community leader. To be honest, it were these modules that helped me gain a clear vision of what a community is, how to plan and host events and what skills I need to work on to be an effective leader. If you complete the modules with the same enthusiasm you started it with, you're going to be a great leader.&lt;/p&gt;

&lt;p&gt;Once you've completed the modules, the next step is to wait and be patient. Your submissions undergoes a detailed review. Unlike any other program, the review team very thoroughly reads and reviews each and every submission and provide you feedback to improve it. My application was also reviewed and a very helpful feedback was provided. I worked on my feedback, it again went for a review, the submissions were accepted and vola! I was just one step away to become a GitHub Campus Expert.&lt;/p&gt;

&lt;p&gt;It was October 2, 2018, the day I officially became a GitHub Campus Expert. It was that day when a call with the amazing Joe Nash (he was Program Manager at that time) was scheduled. The call was great, after the chat, he showed me the on-boarding process. I created my GitHub Campus Expert profile, got added to Slack, and I was a GitHub Campus Expert! 🥳&lt;/p&gt;

&lt;p&gt;I already had an event planned which I proudly hosted as a GitHub Campus Expert. I also got to organize a Hacktoberfest event with Daniel Phiri (GitHub Campus Expert Alumni). Daniel helped me a lot during the process and was a constant support. &lt;/p&gt;

&lt;p&gt;As a GitHub Campus Expert, I got a lot of opportunities to help and inspire people, talk about open source and meet some great folks. I did my first booth crawl &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@harshil1712/booth-crawl-at-makerfest-vadodara-2019-61bbcf1e20c1" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AA55WTuqeHJl1nazm4fPheA.png" alt="Harshil Agrawal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@harshil1712/booth-crawl-at-makerfest-vadodara-2019-61bbcf1e20c1" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Booth Crawl at MakerFest Vadodara — 2019 | by Harshil Agrawal | Medium&lt;/h2&gt;
      &lt;h3&gt;Harshil Agrawal ・ &lt;time&gt;Apr 21, 2019&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 organized the first Flutter Bootcamp &lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@harshil1712/the-flutter-bootcamp-story-2089ccc261f6" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AA55WTuqeHJl1nazm4fPheA.png" alt="Harshil Agrawal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@harshil1712/the-flutter-bootcamp-story-2089ccc261f6" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Flutter Bootcamp Story. This is the story of how two Student… | by Harshil Agrawal | Medium&lt;/h2&gt;
      &lt;h3&gt;Harshil Agrawal ・ &lt;time&gt;Aug 16, 2019&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 gave my first DevFest talk &lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@harshil1712/web-accessibility-at-devfest-ranchi-3e254155ebfa" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AA55WTuqeHJl1nazm4fPheA.png" alt="Harshil Agrawal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@harshil1712/web-accessibility-at-devfest-ranchi-3e254155ebfa" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Web Accessibility at DevFest Ranchi | by Harshil Agrawal | Medium&lt;/h2&gt;
      &lt;h3&gt;Harshil Agrawal ・ &lt;time&gt;Nov 9, 2019&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 and also my first international talk! &lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@harshil1712/fossasia-summit-2019-my-first-international-talk-a2106aa450c4" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A88%3A88%2F1%2AA55WTuqeHJl1nazm4fPheA.png" alt="Harshil Agrawal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@harshil1712/fossasia-summit-2019-my-first-international-talk-a2106aa450c4" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;FOSSASIA Summit 2019 — My First International Talk | by Harshil Agrawal | Medium&lt;/h2&gt;
      &lt;h3&gt;Harshil Agrawal ・ &lt;time&gt;Jun 25, 2021&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 I organized more than 40+ events/meetups/workshops in just 6 months impacting more than 200 people!

&lt;p&gt;The program has been really helpful and inspiring. Whenever and wherever I faced an issue, I knew there were 100+ other GitHub Campus Experts there to help me out. The program makes you feel like a huge family you have, that is spread out to different parts of the world.&lt;/p&gt;

&lt;p&gt;I would like to thank Joe, Lieke and all the GitHub Campus Experts to be a constant inspiration and support! You folks are amazing! 💖   &lt;/p&gt;

&lt;p&gt;&lt;em&gt;About the program&lt;/em&gt;&lt;br&gt;
The GitHub Campus Expert program is an amazing opportunity to help your local community. The program focuses on your local community and helps you to build and grow your local community. This is not an ambassador program unlike others, the program actually focuses on supporting you to help you grow your community.&lt;br&gt;
By becoming a GitHub Campus Expert you don't represent GitHub nor you can be called as a GitHub Employee.&lt;/p&gt;

&lt;p&gt;I hope I was able to answer a few questions students have about the program. Below are the answers to the few that I always come across about the program.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What should I write in my application?&lt;br&gt;
Honestly I don't have an answer to this. The best advice I could give is be honest with your application, you know your community better.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I am not sure what I should write in my application, may you please give me some points?&lt;br&gt;
I am afraid if you don't know why you want to be a GitHub Campus Expert, you're not ready to be one. Take some more time and work on it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What prerequisites/qualities to become a GitHub Campus Expert?&lt;br&gt;
There are no such prerequisites/qualities. Personally, I believe you should be motivated enough to help people and grow your community.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My application got rejected. Can I reapply?&lt;br&gt;
Yes you definitely can!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My application got rejected. When can I reapply?&lt;br&gt;
If your application got rejected you can reapply in the next semester i.e after 6 months. But please don't let this stop you to contribute towards the community. Use this time to build and grow your community, you'll get a great experience before joining the program and will know the roles and responsibilities of a community lead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My application got rejected, what should I do to improve myself, so that I get selected the next time?&lt;br&gt;
If your application got rejected don't worry, you're not the reason. Sometimes there are so many applications that it becomes really difficult to shortlist many of you. There might also be a huge probability that someone from your institute is already in the training.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I am in the training phase and working on the modules. Could you please share your submissions?&lt;br&gt;
I am sorry but I won't. The modules are designed to help you become a better community leader and improve your skills. I don't want to take away this learning opportunity from you.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you still have any more questions, please feel free to ask them.&lt;/p&gt;

</description>
      <category>githubcampusexpert</category>
      <category>community</category>
      <category>github</category>
    </item>
  </channel>
</rss>
