<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pato</title>
    <description>The latest articles on DEV Community by Pato (@devpato).</description>
    <link>https://dev.to/devpato</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%2F224070%2Fcafd30d7-a2d3-49bd-88fe-9339dae9d973.png</url>
      <title>DEV Community: Pato</title>
      <link>https://dev.to/devpato</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devpato"/>
    <language>en</language>
    <item>
      <title>Build a Docs‑Aware Chatbot with React, Vite, Node, and OpenAI (plus fun DALL·E avatars)</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Wed, 17 Sep 2025 17:57:11 +0000</pubDate>
      <link>https://dev.to/cloudinary/build-a-docs-aware-chatbot-with-react-vite-node-and-openai-plus-fun-dalle-avatars-1chi</link>
      <guid>https://dev.to/cloudinary/build-a-docs-aware-chatbot-with-react-vite-node-and-openai-plus-fun-dalle-avatars-1chi</guid>
      <description>&lt;h2&gt;
  
  
  What you’ll build
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A chat UI that streams answers from your own examples/context&lt;/li&gt;
&lt;li&gt;A Node/Express API that calls OpenAI for text and image generation&lt;/li&gt;
&lt;li&gt;Two cute, auto‑generated avatars (user &amp;amp; assistant)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Demo question shown here: “How do I use the Cloudinary React SDK?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repo (reference): &lt;strong&gt;Cloudinary-Chatbot-OpenAI-Demo&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prereqs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node 18+&lt;/li&gt;
&lt;li&gt;An OpenAI API key stored server‑side (never in the browser). How to create/manage keys: see the official docs. (&lt;a href="https://platform.openai.com/docs/quickstart/step-2-setup-your-api-key?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1) Create the React app (Vite)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# New project&lt;/span&gt;
npm create vite@latest cloudinary-chatbot &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;span class="nb"&gt;cd &lt;/span&gt;cloudinary-chatbot
npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Vite proxy (avoid CORS while developing)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;vite.config.js&lt;/code&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&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;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&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;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;proxy&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;/api&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="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:6000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;changeOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Chatbot UI
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;src/App.jsx&lt;/code&gt; file. You can file the full code of this file in the &lt;a href="https://github.com/cloudinary-devs/Cloudinary-Chatbot-OpenAI-Demo/blob/main/src/App.jsx" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Chat functionality
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendMessage&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;inputMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
    &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newMessages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setInputMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/chat&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;application/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;body&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="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newMessages&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;data&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;newMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&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;content&lt;/span&gt; &lt;span class="p"&gt;}]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="nf"&gt;setMessages&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;newMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server error. Try again.&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;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function sends the user’s message to the backend and updates the chat UI. It first adds the user’s message to the conversation, clears the input, and sets a loading state. Then it POSTs the full message history to &lt;code&gt;/api/chat&lt;/code&gt; and appends the assistant’s reply when the server responds. If the request fails, it adds an error message instead. Finally, it resets the status to idle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating avatars
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nf"&gt;useEffect&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;makeAvatars&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="k"&gt;try&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/avatar&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&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;data&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// [{url}, {url}]&lt;/span&gt;
        &lt;span class="nf"&gt;setUserImage&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setAssistantImage&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// silently ignore; UI still works without avatars&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;makeAvatars&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make a more realistic chatBot, we are going to generate 2 avatars. In our backend, we have the endpoint &lt;code&gt;/api/avatar&lt;/code&gt;. We call that endpoint, and we assign the avatars one for the user and one for the bot/assistant.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add your own CSS or use our existing &lt;a href="https://github.com/cloudinary-devs/Cloudinary-Chatbot-OpenAI-Demo/blob/main/src/App.css" rel="noopener noreferrer"&gt;App.css&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2) Add the backend (Express + OpenAI)
&lt;/h2&gt;

&lt;p&gt;Inside the project root, create a folder named &lt;code&gt;backend&lt;/code&gt; and a file &lt;code&gt;server.js&lt;/code&gt;. We’ll reuse the root &lt;code&gt;package.json&lt;/code&gt; for simplicity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install deps
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i express dotenv openai
&lt;span class="c"&gt;# optional: nodemon for dev&lt;/span&gt;
npm i &lt;span class="nt"&gt;-D&lt;/span&gt; nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environment variables
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; in the &lt;strong&gt;project root&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_KEY=sk-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Server code (Responses API + Images API)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why Responses API?&lt;/strong&gt; It’s the recommended, modern way to generate text and stream outputs going forward; if you’re coming from Chat Completions, see the official migration guide. (&lt;a href="https://platform.openai.com/docs/guides/migrate-to-responses?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why SDK over raw fetch?&lt;/strong&gt; Cleaner code, types, and built‑ins for images. (&lt;a href="https://platform.openai.com/docs/libraries/javascript?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;). You can find the full code to the backend in the &lt;a href="https://github.com/cloudinary-devs/Cloudinary-Chatbot-OpenAI-Demo/tree/main/backend" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;backend/server.js&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Training the chatBot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&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;demoModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Where is the Cloudinary React SDK documentation?&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;See: https://cloudinary.com/documentation/react_integration&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="na"&gt;role&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Where can I read about Cloudinary image transformations in React?&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;See: https://cloudinary.com/documentation/react_image_transformations&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="na"&gt;role&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How do I display an image using the Cloudinary React SDK?&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="s2"&gt;`Use @cloudinary/react and @cloudinary/url-gen. Example:

import { AdvancedImage } from '@cloudinary/react';
import { Cloudinary } from '@cloudinary/url-gen';
import { sepia } from '@cloudinary/url-gen/actions/effect';

const cld = new Cloudinary({ cloud: { cloudName: 'demo' } });
const img = cld.image('front_face').effect(sepia());

&amp;lt;AdvancedImage cldImg={img} /&amp;gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code initializes the OpenAI client on the server using an API key from environment variables, ensuring all AI calls are authenticated. It also defines a &lt;code&gt;demoModel&lt;/code&gt; array containing a series of example question-and-answer pairs. These serve as “conversation seeds” that help guide the AI toward Cloudinary-specific knowledge by showing it how the assistant should respond. Each entry mimics a real chat message, with a &lt;code&gt;role&lt;/code&gt; (&lt;code&gt;user&lt;/code&gt; or &lt;code&gt;assistant&lt;/code&gt;) and &lt;code&gt;content&lt;/code&gt;. Together, these samples act as contextual training data, steering the model to provide accurate Cloudinary documentation links and example React code when similar questions are asked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the chatBot with OpenAI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/chat&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;messages&lt;/span&gt; &lt;span class="o"&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;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// System prompt keeps the bot scoped to your docs&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;system&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a helpful developer docs assistant. Prefer official Cloudinary docs. Include links when helpful.&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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;demoModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;]&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;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;r&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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;input&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Convenience: return plain text&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_text&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server Error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint takes the user’s chat messages, prepends a system prompt, and mixes in example Q&amp;amp;A pairs to guide the model toward Cloudinary-focused answers. It sends this combined conversation to OpenAI using the gpt-4o-mini model, then returns the assistant’s plain-text reply to the client. If an error occurs, it logs the issue and responds with a 500 error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Avatars with DALL-E
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/avatar&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;r&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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-image-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minimal, cute round animal avatar on flat background, high contrast, centered, no text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;256x256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Return {url} objects for the UI&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server Error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint generates simple AI-created avatars. When called, it sends a prompt to OpenAI’s image generation model (&lt;code&gt;gpt-image-1&lt;/code&gt;) requesting two minimal, cute, round animal avatars at 256×256 resolution. The OpenAI API returns image objects containing URLs, which the server maps into a clean &lt;code&gt;{ url }&lt;/code&gt; format for the frontend. If generation fails, the server logs the error and responds with a &lt;code&gt;500&lt;/code&gt; status code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responses API reference (Node): see &lt;strong&gt;Responses&lt;/strong&gt; docs. (&lt;a href="https://platform.openai.com/docs/api-reference/responses?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Images API reference: see &lt;strong&gt;Images&lt;/strong&gt; docs. (&lt;a href="https://platform.openai.com/docs/api-reference/images?lang=node.js&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3) Dev scripts
&lt;/h2&gt;

&lt;p&gt;Add these to your root &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node backend/server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"server:dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon backend/server.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4) Run it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# terminal 1&lt;/span&gt;
npm run server:dev

&lt;span class="c"&gt;# terminal 2&lt;/span&gt;
npm run dev
&lt;span class="c"&gt;# open http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type:&lt;br&gt;
“&lt;strong&gt;How do I use the Cloudinary React SDK?&lt;/strong&gt;”&lt;br&gt;
You should get a helpful, linked answer pulled in the spirit of your seed examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production notes (important)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never expose your API key&lt;/strong&gt; in client code or public repos. Use env vars and a server. (&lt;a href="https://platform.openai.com/docs/guides/production-best-practices/api-keys?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Prefer &lt;strong&gt;Responses API&lt;/strong&gt; for new builds and streaming; see migration notes if you used Chat Completions before. (&lt;a href="https://platform.openai.com/docs/guides/migrate-to-responses?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;If you want retrieval over your actual docs (beyond hardcoded examples), look at the &lt;strong&gt;Assistants API&lt;/strong&gt; with tools or Retrieval. (&lt;a href="https://platform.openai.com/docs/assistants/overview?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrap‑up
&lt;/h2&gt;

&lt;p&gt;You now have a lightweight, dev‑friendly chatbot that answers from your docs and greets users with generated avatars. From here you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Swap the seed examples for real retrieval.&lt;/li&gt;
&lt;li&gt;Add streaming UI for token‑by‑token responses. (&lt;a href="https://platform.openai.com/docs/guides/streaming-responses?api-mode=responses&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Validate outputs with structured JSON. (&lt;a href="https://platform.openai.com/docs/guides/structured-outputs?lang=node.js&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Further reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI Quickstart (Node) (&lt;a href="https://platform.openai.com/docs/quickstart?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Responses API (text generation) (&lt;a href="https://platform.openai.com/docs/api-reference/responses?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Images API (generation &amp;amp; sizes) (&lt;a href="https://platform.openai.com/docs/api-reference/images?lang=node.js&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenAI Platform&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/cloudinary-devs/Cloudinary-Chatbot-OpenAI-Demo/tree/main" rel="noopener noreferrer"&gt;Cloudinary-Chatbot-OpenAI-Demo&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://cloudinary.com/users/register_free?utm_campaign=4870-&amp;amp;utm_medium=employee_referral&amp;amp;utm_source=dev-dot-to&amp;amp;utm_content=docs-aware-chatbot" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>react</category>
      <category>cloudinary</category>
      <category>firebase</category>
      <category>aws</category>
    </item>
    <item>
      <title>Turn Any Image into a Blog Post with AI (React, Cloudinary &amp; OpenAI)</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Mon, 08 Sep 2025 13:11:47 +0000</pubDate>
      <link>https://dev.to/cloudinary/turn-any-image-into-a-blog-post-with-ai-react-cloudinary-openai-3cb6</link>
      <guid>https://dev.to/cloudinary/turn-any-image-into-a-blog-post-with-ai-react-cloudinary-openai-3cb6</guid>
      <description>&lt;h2&gt;
  
  
  Why this is cool
&lt;/h2&gt;

&lt;p&gt;Give your content team a superpower: drop in any image → get a well‑formed, vertical‑specific blog post &lt;strong&gt;plus audio playback&lt;/strong&gt;. We’ll combine &lt;strong&gt;Cloudinary AI&lt;/strong&gt; (image captioning) with &lt;strong&gt;OpenAI&lt;/strong&gt; (blog generation + TTS) inside a &lt;strong&gt;Vite + React&lt;/strong&gt; app with an Express backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you’ll build&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload an image → Cloudinary generates a caption describing it&lt;/li&gt;
&lt;li&gt;Send that caption to OpenAI → get a 300‑word marketing blog post tailored to the image’s vertical (auto, travel, fashion, etc.)&lt;/li&gt;
&lt;li&gt;Generate an MP3 narration of the post with OpenAI TTS&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Demo idea: a red Ferrari image becomes a short, punchy automotive blog post with a play button for audio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Full repo: &lt;a href="https://github.com/cloudinary-devs/Cloudinary-React-Image-to-Blog-AI" rel="noopener noreferrer"&gt;Cloudinary-React-Image-to-Blog-AI&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prereqs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node 18+&lt;/li&gt;
&lt;li&gt;Free accounts: &lt;strong&gt;Cloudinary&lt;/strong&gt; and &lt;strong&gt;OpenAI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Basic React/JS/Node skills&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ OpenAI billing: add a small credit (\$5–\$10) and a spending cap to avoid surprises.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1) Cloudinary setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create/login → &lt;strong&gt;Settings → Product Environments&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Note your &lt;strong&gt;Cloud name&lt;/strong&gt; (e.g. &lt;code&gt;demo&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Keys&lt;/strong&gt;: &lt;strong&gt;Settings → Product Environments → API Keys → Generate New API Key&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep these handy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CLOUDINARY_CLOUD_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLOUDINARY_API_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLOUDINARY_API_SECRET&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;We’ll also use the public cloud name on the client (via Vite env).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2) OpenAI setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create/login at platform.openai.com&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing&lt;/strong&gt; → add payment details + monthly limit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Keys&lt;/strong&gt; → &lt;em&gt;Create new secret key&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Save your &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; in &lt;strong&gt;.env&lt;/strong&gt; (server only).&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Scaffold the project (Vite + React)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest image-to-blog-ai &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react-swc
&lt;span class="nb"&gt;cd &lt;/span&gt;image-to-blog-ai
npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install deps for client &amp;amp; server:&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="c"&gt;# client deps&lt;/span&gt;
npm i axios react-markdown @cloudinary/react @cloudinary/url-gen

&lt;span class="c"&gt;# server deps&lt;/span&gt;
npm i express cors cloudinary multer streamifier openai dotenv

&lt;span class="c"&gt;# (optional in dev)&lt;/span&gt;
npm i &lt;span class="nt"&gt;-D&lt;/span&gt; nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project layout (single repo, both client + server):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image-to-blog-ai/
├─ index.html
├─ src/
├─ server.js            # Express API
├─ public/              # serves speech.mp3
├─ .env                 # server secrets
├─ vite.config.js
├─ package.json
└─ ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4) Vite dev proxy (no CORS headaches)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;vite.config.js&lt;/strong&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&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;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&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;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;proxy&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;/api&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="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:6000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Express port&lt;/span&gt;
        &lt;span class="na"&gt;changeOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5) React UI
&lt;/h2&gt;

&lt;p&gt;Create &lt;strong&gt;src/App.jsx&lt;/strong&gt;. You can find the explanation of the main parts of the code below and the full code example &lt;a href="https://github.com/cloudinary-devs/Cloudinary-React-Image-to-Blog-AI/blob/main/src/App.tsx" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the story
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/caption&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multipart/form-data&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="nf"&gt;setCaption&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;caption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setStory&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;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;cldImg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&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;public_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;cldImg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nf"&gt;setImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cldImg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setShouldSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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;We are going to break the code snippet above to have a better idea of what's going on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/caption&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multipart/form-data&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We make a POST call to &lt;code&gt;/api/caption&lt;/code&gt; with &lt;code&gt;multipart/form-data&lt;/code&gt;. The backend is responsible for uploading the image to Cloudinary, generating a caption of that image using Cloudinary AI technologies, and generating a story via OpenAI.&lt;/p&gt;

&lt;p&gt;We set the caption and the story in the state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setCaption&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;caption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;setStory&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;story&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's work with the image uploaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cldImg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&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;public_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;cldImg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;setImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cldImg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above shows &lt;code&gt;cld.image(publicId)&lt;/code&gt; which creates a CloudinaryImage instance. &lt;code&gt;.resize(fill().width(500).height(500))&lt;/code&gt; applies a fill resize, cropping to maintain aspect ratio while fitting the &lt;code&gt;500×500&lt;/code&gt; frame. Then we overwrite the image state with the CloudinaryImage instance. This is key: image now stops being a File and becomes a Cloudinary object.&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AudioPlayer&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactMarkdown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;story&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;/ReactMarkdown&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the image is shown with the code snippet above. This block renders only when a story exists. The &lt;code&gt;AudioPlayer&lt;/code&gt; component receives the full story, generates audio (text-to-speech API from OpenAI), and uses &lt;code&gt;setLoading&lt;/code&gt; to pause UI updates while processing. Meanwhile, ReactMarkdown converts the story’s Markdown into formatted HTML, displaying it only when the app isn’t busy (!loading). Together, these pieces let the user upload an image and immediately get a caption, hear the story read aloud, and view it as a polished blog-style post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AudioPlayer component
&lt;/h2&gt;

&lt;p&gt;Time to create the AudioPlayer component &lt;strong&gt;src/AudioPlayer.jsx&lt;/strong&gt;. Here's the complete code of the &lt;a href="https://github.com/cloudinary-devs/Cloudinary-React-Image-to-Blog-AI/blob/main/src/AudioPlayer.tsx" rel="noopener noreferrer"&gt;AudioPlayer.jsx&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;The most importat functio of this file is the generate function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generate&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/generate-audio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nf"&gt;setUrl&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;audioUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function sends the story text to the backend to generate audio. When &lt;code&gt;generate&lt;/code&gt; runs, it first sets &lt;code&gt;loading&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; to indicate processing. It then makes a POST request to &lt;code&gt;/api/generate-audio&lt;/code&gt;, passing the text payload. The server responds with an &lt;code&gt;audioUrl&lt;/code&gt;, which the component stores in state so the audio player can use it. Finally, in a &lt;code&gt;finally&lt;/code&gt; block—ensuring it runs whether the request succeeds or fails—it resets &lt;code&gt;loading&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, keeping the UI state consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/App.css&lt;/strong&gt; (grab your own styles, e.g. a centered column, spinner, and a &lt;code&gt;.custom-file-upload&lt;/code&gt; button). Here's the complete code of the &lt;a href="https://github.com/cloudinary-devs/Cloudinary-Chatbot-OpenAI-Demo/blob/main/src/App.css" rel="noopener noreferrer"&gt;App.css&lt;/a&gt; file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Store only the &lt;strong&gt;Cloud Name&lt;/strong&gt; on the client via &lt;code&gt;VITE_CLOUD_NAME&lt;/code&gt;. Keep all secrets on the server.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6) Express backend (Cloudinary + OpenAI)
&lt;/h2&gt;

&lt;p&gt;Create &lt;strong&gt;.env&lt;/strong&gt; in project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_CLOUD_NAME=YOUR_CLOUD_NAME
CLOUDINARY_CLOUD_NAME=YOUR_CLOUD_NAME
CLOUDINARY_API_KEY=YOUR_CLOUDINARY_API_KEY
CLOUDINARY_API_SECRET=YOUR_CLOUDINARY_API_SECRET
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;strong&gt;server.js&lt;/strong&gt; in project root:&lt;/p&gt;

&lt;p&gt;Here you can find the full code of the &lt;a href="https://github.com/cloudinary-devs/Cloudinary-React-Image-to-Blog-AI/blob/main/server.js" rel="noopener noreferrer"&gt;server.js&lt;/a&gt; file. Now, let's deep dive into the different parts of the &lt;code&gt;server.js.&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenAI Initialization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates a reusable OpenAI client for generating text (blog posts) and audio (text-to-speech).&lt;/p&gt;

&lt;h3&gt;
  
  
  Multer Upload Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memoryStorage&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;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;multer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;fileFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&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="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;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/image&lt;/span&gt;&lt;span class="se"&gt;\/(&lt;/span&gt;&lt;span class="sr"&gt;jpeg|png|webp|gif|bmp|tiff&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mimetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unsupported file 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;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup configures Multer to store uploaded images directly in memory rather than on disk, while enforcing a maximum file size of 8MB to prevent oversized uploads. It also filters incoming files to allow only valid image &lt;code&gt;MIME&lt;/code&gt; types, ensuring users can't upload unsupported formats. With this configuration, the &lt;code&gt;/api/caption&lt;/code&gt; endpoint receives the image as req.file.buffer, ready to be processed or uploaded to Cloudinary without ever touching the filesystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Helper Function: Upload Image Buffer to Cloudinary
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadBufferToCloudinary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;detection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;captioning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;streamifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helper function wraps Cloudinary’s &lt;code&gt;upload_stream&lt;/code&gt; in a Promise so it can be used with &lt;code&gt;await&lt;/code&gt;, making the upload flow cleaner and fully async. It streams the in-memory file buffer into Cloudinary using &lt;code&gt;streamifier&lt;/code&gt;, enabling AI caption detection through the &lt;code&gt;detection: 'captioning'&lt;/code&gt; option. Once the upload completes, it returns the full Cloudinary response with the &lt;code&gt;public_id&lt;/code&gt;, and the automatically generated caption found in &lt;code&gt;info.detection.captioning.data.caption&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the caption
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/caption&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image file is required&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;uploadStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;detection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;captioning&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cloudinary error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;story&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;generateBlog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captioning&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;caption&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;resObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;public_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captioning&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;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;story&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resObj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;streamifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uploadStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This endpoint is reponsabile for uploading the image to Cloudinary via the &lt;code&gt;multer&lt;/code&gt; stream and using the &lt;code&gt;captioning&lt;/code&gt; AI mechanism to analyze the image and generate a caption. Then this caption gets sent to the &lt;code&gt;generateBlog&lt;/code&gt; function to create a blog post using OpenAI APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the blog content
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateBlog&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;caption&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`create an 300 world blog post to be used as part of a marketing campaign from a business-- the blog must focused on the vertical industry of that image based on the following caption of the image: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. This blog is not for the business but for the person interested in the vetical industry of the image`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&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="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&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="c1"&gt;// pass the new message and the previous messages&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open ai response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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;message&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`error: Internal Server Error`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This functions generates the blog based on the instructions passed in the &lt;code&gt;content&lt;/code&gt; property of the message object. Then we use the NodeJS OpenAI SDk completion to generate the blog based on the instructions we set and the caption we got from the image we uploaded to Cloudinary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating audio
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/generate-audio&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;mp3&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;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speech&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tts-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alloy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;input&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;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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;mp3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&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;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&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;speech.mp3&lt;/span&gt;&lt;span class="dl"&gt;"&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audioUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/speech.mp3`&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error generating audio:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error generating audio&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this endpoint, we are using the OpenAI SDK text-to-speech to generate the audio based on the request text. This text is blog text generated in the &lt;code&gt;generateBlog()&lt;/code&gt; function. Once the audio has been generated, we store the audio in the &lt;code&gt;speech.mp3&lt;/code&gt; file, to be used in the front end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;package.json&lt;/strong&gt; (scripts for both dev servers):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image-to-blog-ai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon server.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7) Run it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Terminal A (API)&lt;/span&gt;
npm run dev:api
&lt;span class="c"&gt;# API → http://localhost:6000&lt;/span&gt;

&lt;span class="c"&gt;# Terminal B (Vite)&lt;/span&gt;
npm run dev
&lt;span class="c"&gt;# Web → http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload an image → watch the caption + blog appear → click &lt;strong&gt;Generate Audio&lt;/strong&gt; to get an MP3.&lt;/p&gt;




&lt;h2&gt;
  
  
  8) Production &amp;amp; security notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep secrets server‑side only; never expose API keys in the client&lt;/li&gt;
&lt;li&gt;Add rate limiting (e.g. &lt;code&gt;express-rate-limit&lt;/code&gt;) and basic auth or tokens on &lt;code&gt;/api&lt;/code&gt; routes&lt;/li&gt;
&lt;li&gt;Validate file types and size (shown above); consider virus scanning for public apps&lt;/li&gt;
&lt;li&gt;Cache TTS results per post hash to avoid re‑billing&lt;/li&gt;
&lt;li&gt;Consider the &lt;strong&gt;Responses API&lt;/strong&gt; for future‑proof OpenAI calls; swap &lt;code&gt;chat.completions&lt;/code&gt; when you’re ready&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CORS in dev&lt;/strong&gt;: use the Vite proxy as shown (don’t call &lt;code&gt;http://localhost:6000&lt;/code&gt; directly from the client)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudinary caption is undefined&lt;/strong&gt;: ensure the &lt;code&gt;detection: 'captioning'&lt;/code&gt; add‑on is enabled for your account/plan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MP3 not found&lt;/strong&gt;: verify &lt;code&gt;public/&lt;/code&gt; exists and the server has write permissions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrap‑up
&lt;/h2&gt;

&lt;p&gt;You now have an image‑to‑blog pipeline with Cloudinary + OpenAI: caption → post → audio. Drop it into your content workflow to turn static visuals into dynamic marketing assets.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://cloudinary.com/users/register_free?utm_campaign=4870-&amp;amp;utm_medium=employee_referral&amp;amp;utm_source=dev-dot-to&amp;amp;utm_content=ai-image-ai-blog" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>react</category>
      <category>cloudinary</category>
      <category>openai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I went to the Firebase Summit 2022 -NYC</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Mon, 30 Jan 2023 19:11:13 +0000</pubDate>
      <link>https://dev.to/paypaldeveloper/i-went-to-the-firebase-summit-2022-nyc-3p5b</link>
      <guid>https://dev.to/paypaldeveloper/i-went-to-the-firebase-summit-2022-nyc-3p5b</guid>
      <description>&lt;p&gt;Hi friends! I recently had the fantastic opportunity to attend the Firebase Summit 2022 in New York City! I’m here to tell you how it went and share some fantastic moments of this great event.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F6k0d6le7rm44nmjba7th.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6k0d6le7rm44nmjba7th.png" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, if you don’t know what Firebase is, that’s okay!&lt;/p&gt;

&lt;p&gt;What is Firebase?&lt;br&gt;
A lot of you have heard of Firebase, which is way more than just a database.&lt;/p&gt;

&lt;p&gt;Firebase is a web and mobile development platform. It has 19 products and is used by millions of apps. Also, it is backed by our friends at Google.&lt;/p&gt;

&lt;p&gt;I have been a longtime fan of Firebase and have been using the platform for nearly 5 years. I’m still in shock with all the different use cases of the product that helps build amazing applications in a one-stop dashboard.&lt;/p&gt;

&lt;p&gt;A few months ago, I saw a Tweet about registering for the Firebase Summit in NYC, which turned out to be just a few blocks away from my house so I had to go! I immediately messaged my friend David East (Developer Advocate at Firebase).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5xzl00cz4xaqrxnb0pdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5xzl00cz4xaqrxnb0pdw.png" alt=" " width="593" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was super excited not only to learn more about Firebase, but to have the opportunity to meet amazing people from the tech community.&lt;/p&gt;

&lt;p&gt;Finally, October 18 came! I didn’t sleep much the night before because I was super excited about this event, but the excitement helped me feel energized. The Firebase Summit took place in the Google offices in NYC where I met members of the community and listened to talks presented by the Firebase team on the latest features.&lt;/p&gt;

&lt;p&gt;What’s new with Firebase?&lt;/p&gt;

&lt;p&gt;Firebase Hosting&lt;br&gt;
Firebase provides hosting that you can use to deploy fast and secure static web applications. Now you can deploy web apps with your favorite web dynamic frameworks with the help of one single command from the Firebase CLI. With just one command the CLI will detect your framework, build it, and deploy it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffhp2lptleuos5pnh1yvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffhp2lptleuos5pnh1yvh.png" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn more from this awesome demo David East (Developer Advocate at Firebase) created for the Firebase Summit.&lt;/p&gt;

&lt;p&gt;Cloud Firestore New Features&lt;br&gt;
A few changes with Cloud Firestore:&lt;/p&gt;

&lt;p&gt;Scalable Baas: The Firebase team has removed hard limits for write throughput &amp;amp; concurrent active connections.&lt;br&gt;
Auto-delete: You can now auto-delete content with Firestore’s time-to-live (TTL) policies. Basically, you set an expiration date for the content that lives in your Firestore database.&lt;br&gt;
The new COUNT() function operation: This operation can help you execute the count in collection group queries without having to retrieve all documents. Take a look at David’s tweet on firebase with a code example showing how to use the COUNT() function. with a code, an example showing how to use the COUNT() function.&lt;br&gt;
Learn more about these Cloud Firestore updates in this YouTube video.&lt;/p&gt;

&lt;p&gt;Firestore Cloud Storage security rules&lt;br&gt;
Working with security rules got easier by using firestore.get(). You can use the service side security rules that you have written, and make sure only authorized users have access to a specific file. This will help you only have one set of rules instead of having the same ones in two places (Firestore and Cloud Storage).&lt;/p&gt;

&lt;p&gt;Learn more about Firestore Cloud Storage security rules in this YouTube video.&lt;/p&gt;

&lt;p&gt;Firebase Extensions&lt;br&gt;
This is one of the things I’m most excited about! You can now create your own extensions and publish them to the Firebase extension marketplace. You can now sign up for the extensions provider alpha program so you can start building your own Firebase extensions.&lt;/p&gt;

&lt;p&gt;Learn more about the Firebase Extensions in this YouTube video.&lt;/p&gt;

&lt;p&gt;Deliver Personalized Behavior with Remote Config&lt;br&gt;
Have you ever wondered how to create a better and more personalized experience for your app users? Well with this remote config, you can help optimize and personalize the experience of your users automatically.&lt;/p&gt;

&lt;p&gt;If you want to learn more about Remote Config personalization look at this YouTube video.&lt;br&gt;
Resources:&lt;/p&gt;

&lt;p&gt;Firebase Blog&lt;br&gt;
Firebase YouTube&lt;br&gt;
Firebase Twitter&lt;br&gt;
Watch the entire Firebase Summit Keynote.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbnrb79dufib9flj12fiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbnrb79dufib9flj12fiq.png" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fg0m68dvnnso4k4z47k9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fg0m68dvnnso4k4z47k9o.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PayPal Developer Community
&lt;/h2&gt;

&lt;p&gt;The PayPal Developer community helps you build your career, while also improving PayPal products and the developer experience. You’ll be able to contribute code and documentation, meet new people and learn from the open-source community.&lt;/p&gt;

&lt;p&gt;Website: developer.paypal.com&lt;br&gt;
Twitter: @paypaldev&lt;br&gt;
GitHub: @paypal developer&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>web3</category>
      <category>offers</category>
    </item>
    <item>
      <title>How to add PayPal checkout payments to your React app</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Wed, 02 Nov 2022 17:25:59 +0000</pubDate>
      <link>https://dev.to/paypaldeveloper/how-to-add-paypal-checkout-payments-to-your-react-app-53aa</link>
      <guid>https://dev.to/paypaldeveloper/how-to-add-paypal-checkout-payments-to-your-react-app-53aa</guid>
      <description>&lt;p&gt;Have you always wondered how to monetize your web applications 🤑? Time to start making those benjamins 💸💸. In this how-to guide, you will learn how to integrate &lt;a href="https://www.paypal.com/us/home" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt; as your checkout payment solution for your ReactJS app using the &lt;a href="https://www.npmjs.com/package/@paypal/react-paypal-js" rel="noopener noreferrer"&gt;react-paypal-js&lt;/a&gt; npm package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What is PayPal?&lt;/em&gt;&lt;/strong&gt; Paypal is a payment processing product that helps you process payments for your mobile and web applications. We provide a fast and easy way to handle online payments, whether it's for a digital media property or an online merchant of any kind in over 100 countries. &lt;/p&gt;

&lt;h2&gt;
  
  
  Guide Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 1: PayPal Developer sandbox App&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Creating an app using the PayPal sandbox&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Part 2: Adding PayPal to your React App&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt; Add the PayPal NPM package&lt;/li&gt;
&lt;li&gt; Working with the &lt;code&gt;PayPalScriptProvider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Loading state with the &lt;code&gt;usePayPalScriptReducer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Adding the PayPal buttons&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Part 3: Testing the PayPal Checkout&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Testing the PayPal Checkout&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This tutorial requires the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A PayPal Developer Account&lt;/li&gt;
&lt;li&gt;A ReactJS application (I'm using &lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;create react app&lt;/a&gt; for this example).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code to this guide in our &lt;a href="https://github.com/paypaldev/PayPal-React-Checkout-Sample" rel="noopener noreferrer"&gt;PayPal React Sample App&lt;/a&gt; in our Github Org.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: PayPal Developer sandbox app
&lt;/h2&gt;




&lt;p&gt;First, we need to create a PayPal app. To do this, navigate to the &lt;a href="https://developer.paypal.com/home" rel="noopener noreferrer"&gt;PayPal Developer Dashboard&lt;/a&gt; and login into your PayPal developer account. Once you are inside the PayPal Developer dashboard, make sure you are in the &lt;strong&gt;My Apps &amp;amp; Credentials&lt;/strong&gt; page. Inside this page, click on the blue button &lt;strong&gt;Create App.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyohdrnoqb0q5zn63gxg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyohdrnoqb0q5zn63gxg4.png" alt="Create a PayPal app inside the PayPal developer Dashboard" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the name of the PayPal app you are creating. In my case, I named my app &lt;strong&gt;React-checkout&lt;/strong&gt;. Now, select the &lt;em&gt;App Type&lt;/em&gt; to be a &lt;strong&gt;Merchant&lt;/strong&gt;, and click on the blue button &lt;strong&gt;Create App.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fmqmj54vyxjgmvntpzsgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fmqmj54vyxjgmvntpzsgq.png" alt="Name your new PaPal Developer App" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating your PayPal app, you will see a screen similar to mine. In this screen, you will see your &lt;strong&gt;Client ID&lt;/strong&gt;. Copy this ID and save it somewhere (We will use it later on in this tutorial).&lt;/p&gt;

&lt;p&gt;You can always get this &lt;strong&gt;Client ID&lt;/strong&gt; by navigating to the app you just created inside of the &lt;a href="https://www.paypal.com/signin?returnUri=https%3A%2F%2Fdeveloper.paypal.com%2Fdeveloper%2Fapplications&amp;amp;_ga=1.9387580.841672670.1664266268" rel="noopener noreferrer"&gt;PayPal Developer Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fx7k65xm92t6kalkap4xj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fx7k65xm92t6kalkap4xj.png" alt="Copy the Client ID generated for your PayPal app" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: Client ID is Class 4 data. Client ID is non-sensitive data, but still be prudent about sharing or posting it. We recommend putting the Client ID in an environment variable in an &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Adding PayPal to your React App
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Add the PayPal NPM package
&lt;/h3&gt;

&lt;p&gt;To install the &lt;a href="https://www.npmjs.com/package/@paypal/react-paypal-js" rel="noopener noreferrer"&gt;react-paypal-js npm&lt;/a&gt; package run the following command inside of your project's terminal.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install @paypal/react-paypal-js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The PayPal npm package consists of 2 main parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Context Provider, this &lt;code&gt;&amp;lt;PayPalScriptProvider/&amp;gt;&lt;/code&gt; is responsible for the PayPal JS SDK script. This provider uses the native &lt;a href="https://reactjs.org/docs/context.html" rel="noopener noreferrer"&gt;React Context API&lt;/a&gt; for managing the state and communicating with child components. It also supports reloading the script when parameters change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The PayPal SDK Components, components like &lt;code&gt;&amp;lt;PayPalButtons/&amp;gt;&lt;/code&gt; are used to render the UI for PayPal products served by the JS SDK.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any issues with this npm package, please report them in its &lt;a href="https://github.com/paypal/react-paypal-js/issues" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you have installed the react-paypal-js npm package, open your root file, in my case my root file is the &lt;code&gt;App.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In this app, the &lt;code&gt;App.js&lt;/code&gt; component is responsible for loading the PayPal script and rendering the &lt;code&gt;&amp;lt;Checkout/&amp;gt;&lt;/code&gt; component. The &lt;code&gt;&amp;lt;Checkout/&amp;gt;&lt;/code&gt; component will be created later in this tutorial. &lt;/p&gt;

&lt;p&gt;In this file, you will import the &lt;code&gt;PayPalScriptProvider&lt;/code&gt; from the PayPal npm package.&lt;/p&gt;

&lt;p&gt;At the top of the file, add the following line of 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PayPalScriptProvider&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="s2"&gt;@paypal/react-paypal-js&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;In this file we are adding the &lt;code&gt;initialOptions&lt;/code&gt; object, these options can be changed with other configuration parameters. To learn more about the other configuration options look at the &lt;a href="https://developer.paypal.com/docs/business/javascript-sdk/javascript-sdk-configuration/" rel="noopener noreferrer"&gt;PayPal SDK docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialOptions&lt;/span&gt; &lt;span class="o"&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;client-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;YOUR-CLIENT-ID-HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;capture&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, make sure you replace the text from the client-id property with the Client ID from your PayPal app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with the &lt;code&gt;PayPalScriptProvider&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, inside the &lt;code&gt;App.js&lt;/code&gt;, we add the &lt;code&gt;&amp;lt;PayPalScriptProvider/&amp;gt;&lt;/code&gt;. Notice we have inside the provider the &lt;code&gt;&amp;lt;Checkout/&amp;gt;&lt;/code&gt; component where we have the PayPal components. We now add the options prop to the &lt;code&gt;PayPalScriptProvider&lt;/code&gt; to configure the JS SDK. It accepts an object for passing query parameters and data attributes to the JS SDK script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PayPalScriptProvider&lt;/span&gt; &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;initialOptions&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PayPalScriptProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your &lt;code&gt;App.js&lt;/code&gt; component should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Checkout&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;./Checkout&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;PayPalScriptProvider&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="s2"&gt;@paypal/react-paypal-js&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;initialOptions&lt;/span&gt; &lt;span class="o"&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;client-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;YOUR-CLIENT-ID-HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;capture&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;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PayPalScriptProvider&lt;/span&gt; &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;initialOptions&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PayPalScriptProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our React app, we are giving the user the option to select between 2 currencies (USD and Euro) to make a payment. When the user changes the currency, the value will be passed to the PayPal script thanks to the &lt;code&gt;usePayPalScriptReducer()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Time to create a new &lt;code&gt;Checkout.js&lt;/code&gt; component inside of your React application. This file is responsible for loading the PayPal components such as the PayPal buttons. &lt;/p&gt;

&lt;p&gt;At the top of the &lt;code&gt;Checkout.js&lt;/code&gt; file, add the following line to include the &lt;code&gt;PayPalButtons&lt;/code&gt; and the &lt;code&gt;usePayPalScriptReducer&lt;/code&gt;.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PayPalButtons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usePayPalScriptReducer&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="s2"&gt;@paypal/react-paypal-js&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;h3&gt;
  
  
  Loading state with the &lt;code&gt;usePayPalScriptReducer&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;usePayPalScriptReducer&lt;/code&gt; will show a spinner when the PayPal script is loading and can be used to change the values of the options of the PayPal script and at the same time reload the script with the updated parameters.&lt;/p&gt;

&lt;p&gt;The PayPal script has several loading states and with the &lt;code&gt;usePayPalScriptReducer&lt;/code&gt; we can track it in an easier way. This state can be used to show a loading spinner while the script loads or an error message if it fails to load.&lt;/p&gt;

&lt;h4&gt;
  
  
  Loading states:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;isInitial - not started (only used when passing deferLoading={true})&lt;/li&gt;
&lt;li&gt;isPending - loading (default)&lt;/li&gt;
&lt;li&gt;isResolved - successfully loaded&lt;/li&gt;
&lt;li&gt;isRejected - failed to load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this sample app, we used the &lt;code&gt;isPending&lt;/code&gt; state to render the rest of the UI including the &lt;code&gt;PayPalButtons&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside your &lt;code&gt;Checkout&lt;/code&gt; component add the code below. This code will extract the &lt;code&gt;options&lt;/code&gt;, the loading state (isPending), and the &lt;code&gt;dispatch&lt;/code&gt; to dispatch an action to our &lt;code&gt;usePayPalScriptReducer()&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePayPalScriptReducer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding The Currency Selectors
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;Checkout&lt;/code&gt; component, you will add the code to update the state with the new currency the user selects and this will dispatch an action to the &lt;code&gt;usePayPalScriptReducer&lt;/code&gt; to update the PayPal script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCurrency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&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;onCurrencyChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setCurrency&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="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resetOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;currency&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="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, your UI will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;LOADING...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;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;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onCurrencyChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;💵 USD&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;💶 Euro&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the PayPal buttons
&lt;/h3&gt;

&lt;p&gt;To start using the PayPal buttons, all you have to do is add the &lt;code&gt;&amp;lt;PayPalButtons/&amp;gt;&lt;/code&gt; component to your &lt;code&gt;JSX&lt;/code&gt;. The magic comes when you extend the functionality of the PayPal buttons by passing the following props available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.paypal.com/sdk/js/reference/#style" rel="noopener noreferrer"&gt;style&lt;/a&gt;: This attribute allows you to style the PayPal button E.g color, shape, layout, and more.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.paypal.com/docs/api/orders/v2/#orders-create-request-body" rel="noopener noreferrer"&gt;createOrder&lt;/a&gt;: This attribute allows you to create the request of your order with the following properties: item_total, purchase_units, and more.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.paypal.com/docs/api/orders/v2/#orders_get" rel="noopener noreferrer"&gt;onApprove&lt;/a&gt;: This attribute allows doing something with the order details after the order has been created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside of your &lt;code&gt;&amp;lt;Checkout/&amp;gt;&lt;/code&gt; component, after the &lt;code&gt;onCurrencyChange&lt;/code&gt; function add the following functions to be called with the &lt;code&gt;onCreateOrder&lt;/code&gt; and &lt;code&gt;onApprove&lt;/code&gt; props of the PayPal button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onCreateOrder&lt;/span&gt; &lt;span class="o"&gt;=&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;actions&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;purchase_units&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="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8.99&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onApproveOrder&lt;/span&gt; &lt;span class="o"&gt;=&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;actions&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;details&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payer&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="nx"&gt;given_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction completed by &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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will add the &lt;code&gt;&amp;lt;PayPalButtons/&amp;gt;&lt;/code&gt; component to your &lt;code&gt;&amp;lt;Checkout/&amp;gt;&lt;/code&gt; component. Your &lt;code&gt;JSX&lt;/code&gt; code should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkout"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;LOADING...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;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;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onCurrencyChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          option value="USD"&amp;gt;💵 USD&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;💶 Euro&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PayPalButtons&lt;/span&gt; 
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vertical&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;createOrder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onCreateOrder&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onApprove&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onApproveOrder&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Final code of the &lt;code&gt;Checkout.js&lt;/code&gt; file will look like this:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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;react&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Checkout.css&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;PayPalButtons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usePayPalScriptReducer&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="s2"&gt;@paypal/react-paypal-js&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;Checkout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePayPalScriptReducer&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;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCurrency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&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;onCurrencyChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setCurrency&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="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resetOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;currency&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="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;onCreateOrder&lt;/span&gt; &lt;span class="o"&gt;=&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;actions&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;purchase_units&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="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8.99&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="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onApproveOrder&lt;/span&gt; &lt;span class="o"&gt;=&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;actions&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="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;details&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payer&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="nx"&gt;given_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction completed by &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="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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;LOADING&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;/p&amp;gt; : &lt;/span&gt;&lt;span class="err"&gt;(
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;select&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onCurrencyChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;💵&lt;/span&gt; &lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/option&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;💶&lt;/span&gt; &lt;span class="nx"&gt;Euro&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/option&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/select&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PayPalButtons&lt;/span&gt; 
                        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vertical&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
                        &lt;span class="nx"&gt;createOrder&lt;/span&gt;&lt;span class="o"&gt;=&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onCreateOrder&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;actions&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
                        &lt;span class="nx"&gt;onApprove&lt;/span&gt;&lt;span class="o"&gt;=&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;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onApproveOrder&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;actions&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
                    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Testing the PayPal Checkout
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Testing the PayPal Checkout
&lt;/h3&gt;

&lt;p&gt;Inside your project run in the terminal the &lt;code&gt;npm start&lt;/code&gt; command to run your ReactJS application.&lt;/p&gt;

&lt;p&gt;Open &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; to view the app in your browser.&lt;/p&gt;

&lt;p&gt;You should see the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxxuabyfb8ubwnh3la98m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxxuabyfb8ubwnh3la98m.png" alt="React app with PayPal checkout buttons" width="447" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, click on the Debit or Credit Card button to make a payment! You can use the sample card below to test the guest checkout experience with the credit cards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Card
&lt;/h3&gt;

&lt;p&gt;You can create sample credit card numbers using the &lt;a href="https://developer.paypal.com/dashboard/creditCardGenerator" rel="noopener noreferrer"&gt;PayPal Credit Card Generator&lt;/a&gt; inside of your &lt;a href="https://www.paypal.com/signin?returnUri=https%3A%2F%2Fdeveloper.paypal.com%2Fdeveloper%2Fapplications&amp;amp;_ga=1.9387580.841672670.1664266268." rel="noopener noreferrer"&gt;PayPal Developer Dashboard&lt;/a&gt;.&lt;br&gt;
Card Type: &lt;code&gt;Visa&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Card Number: &lt;code&gt;4032039534213337&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Expiration Date: &lt;code&gt;03/2026&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;CVV: &lt;code&gt;952&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Online payments have grown exponentially in the past years, especially during the COVID-19 pandemic. The number of online payment transactions will continue to grow as the years go by. We know that online payments are not going anywhere, but now it’s up to you to get on this trend so your business continues to make money and PayPal is here to help you with this.&lt;/p&gt;

&lt;p&gt;You can find the source code to guide in our &lt;a href="https://github.com/paypaldev/PayPal-React-Checkout-Sample" rel="noopener noreferrer"&gt;PayPal React Sample App&lt;/a&gt; in our Github Org.&lt;/p&gt;

&lt;p&gt;S/O to Greg Jopa for his content that help me write this how-to guide :)&lt;/p&gt;

&lt;h2&gt;
  
  
  PayPal Developer Community
&lt;/h2&gt;

&lt;p&gt;The PayPal Developer community helps you build your career, while also improving PayPal products and the developer experience. You’ll be able to contribute code and documentation, meet new people and learn from the open source community.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://developer.paypal.com" rel="noopener noreferrer"&gt;developer.paypal.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/paypaldev" rel="noopener noreferrer"&gt;@paypaldev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Github:  &lt;a href="https://github.com/paypaldev" rel="noopener noreferrer"&gt;@paypal developer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Add In-App Messages to a Flutter App</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Fri, 03 Jun 2022 20:21:15 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-add-in-app-messages-to-a-flutter-app-2fg0</link>
      <guid>https://dev.to/onesignal/how-to-add-in-app-messages-to-a-flutter-app-2fg0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F62hmgte0gceaw90n7c11.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F62hmgte0gceaw90n7c11.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In-app messages (IAM) can help increase user engagement among active users, nudging them towards desired actions with targeted messages and dynamic content. These messages can be automated and personalized based on custom &lt;a href="https://onesignal.com/blog/boost-push-notification-engagement-with-onesignals-segmentation-tool/" rel="noopener noreferrer"&gt;segmentation and trigger criteria&lt;/a&gt;. This tutorial will cover how to integrate OneSignal IAM into a Flutter app for both Android and iOS. It will also show you how to use message triggers to automate and customize your messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Flutter Project
&lt;/h2&gt;

&lt;p&gt;Open your terminal and run the following command to create a new Flutter project&lt;br&gt;&lt;br&gt;
&lt;code&gt;flutter create flutter_onesignal_iamcd flutter_onesignal_iam&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Now run the following command to add Onesignal SDK to the flutter project&lt;br&gt;&lt;br&gt;
&lt;code&gt;flutter pub add onesignal_flutter&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up your OneSignal Account
&lt;/h2&gt;

&lt;p&gt;This tutorial requires a OneSignal account. You can either &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;log in&lt;/a&gt; to your existing OneSignal account or &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a new account for free&lt;/a&gt;. Then, click &lt;strong&gt;&lt;em&gt;+New App/Website&lt;/em&gt;&lt;/strong&gt; to begin setting up your OneSignal account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F37P1h9kX0fQTxgKg50RfFmNRpJV5ym6cAmEqGKNOec36Ni9pMugoMkoD7WjJk8TYWyAeVa5KnMH3rh58uPLhMtuwJJ1J0aAwqYl3tUHMKq56kfiBK1gkxu-joRURQkXkF2B6DEMS" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F37P1h9kX0fQTxgKg50RfFmNRpJV5ym6cAmEqGKNOec36Ni9pMugoMkoD7WjJk8TYWyAeVa5KnMH3rh58uPLhMtuwJJ1J0aAwqYl3tUHMKq56kfiBK1gkxu-joRURQkXkF2B6DEMS" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Android Setup
&lt;/h3&gt;

&lt;p&gt;As Flutter apps can target both Android and iOS, both of these platforms need to be set up individually. Let’s proceed with setting up Android for now — iOS can be added later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2F1079YxjGproJRdRzcgmoEn1a0wStoczHtPLh2T7cX2jhnbdmI6TJugzAeyspHUVKwW22dq43QdmyoRylInn3uOI-OSy-76F6nf8RCVzBezvyaTrd7mF5_FrO6T1XISPYnHqMkE4m" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2F1079YxjGproJRdRzcgmoEn1a0wStoczHtPLh2T7cX2jhnbdmI6TJugzAeyspHUVKwW22dq43QdmyoRylInn3uOI-OSy-76F6nf8RCVzBezvyaTrd7mF5_FrO6T1XISPYnHqMkE4m" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name your app and select &lt;em&gt;&lt;strong&gt;Google Android (FCM)&lt;/strong&gt;&lt;/em&gt; and use the following guide to &lt;a href="https://documentation.onesignal.com/docs/generate-a-google-server-api-key" rel="noopener noreferrer"&gt;&lt;u&gt;generate a Firebase Server Key&lt;/u&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F--c0A23Xt7HOrOzAnrVWuG70tsTimR4Q8wt68y6Al84-S77WWDe3gWGn27PpJUpsxVcC9Ukz5ORIqpxVZPBIcygszg0fkV6XsPiow22R8vw6_9xOHQqfxE9dYjV8jK6DepAarjHW" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F--c0A23Xt7HOrOzAnrVWuG70tsTimR4Q8wt68y6Al84-S77WWDe3gWGn27PpJUpsxVcC9Ukz5ORIqpxVZPBIcygszg0fkV6XsPiow22R8vw6_9xOHQqfxE9dYjV8jK6DepAarjHW" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you've input your Firebase Server Key and Firebase Sender ID, click &lt;strong&gt;&lt;em&gt;Save &amp;amp; Continue&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the next screen, select _ &lt;strong&gt;Flutter&lt;/strong&gt; _ as your target SDK.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F49fTc1QegAjP3hoAUqXmbIanKQvNYHRJ7qNQiFm5YRySJttfIhfy4L-wfH1fP0PEix2f5fQAAhvacK10aPFQrs577RhpBXTDsxXAJN7YBcrqQmLMqmwrWEZi1wsLWaVE4rL1o-2x" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F49fTc1QegAjP3hoAUqXmbIanKQvNYHRJ7qNQiFm5YRySJttfIhfy4L-wfH1fP0PEix2f5fQAAhvacK10aPFQrs577RhpBXTDsxXAJN7YBcrqQmLMqmwrWEZi1wsLWaVE4rL1o-2x" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next page, you'll see your App ID — copy it for future reference. &lt;strong&gt;Don't click &lt;em&gt;Done&lt;/em&gt;&lt;/strong&gt; just yet. The Flutter app needs to be run on your device first before you complete this step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2F521q84nDI0wzckpwbEZKBNcHIesKtfHjnVX1uOYbXxYPivQfgKlluiSKLUGEHccnZj-XKaFLpzw8gyXe_e_AVkR3twnt6eRAZBbDrYekQ3LqkG_AH12-1T4Ud-at_jIb53S96eMd" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2F521q84nDI0wzckpwbEZKBNcHIesKtfHjnVX1uOYbXxYPivQfgKlluiSKLUGEHccnZj-XKaFLpzw8gyXe_e_AVkR3twnt6eRAZBbDrYekQ3LqkG_AH12-1T4Ud-at_jIb53S96eMd" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The App ID is used to initialize the OneSignal SDK. Add the following code to &lt;code&gt;main.dart&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter/material.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State&amp;lt;MyHomePage&amp;gt; createState() =&amp;gt; _MyHomePageState();
}

class _MyHomePageState extends State&amp;lt;MyHomePage&amp;gt; {
  @override
  void initState() {
    super.initState();
    OneSignal.shared.setAppId("YOUR ONESIGNAL APP ID HERE");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('OneSignal IAM'),
      ),
      body: const Center(child: Text('OneSignal IAM Example')),
    );
  }
}

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

&lt;/div&gt;



&lt;p&gt;Now, run the app on your device. Then, return to your OneSignal account and click on &lt;strong&gt;&lt;em&gt;Check Subscribed Users&lt;/em&gt;&lt;/strong&gt;. A message showing your device model will be shown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FBw_Wmiv3Ri2Fnf19tWaV6vI53KsVBYEKlWOaymWDONk0vOUXnjA9k-a_q5REejk16C5Db5_b9LIjjVyW5I00msFfA_pSgGzjgWApeuGwCz3p5nR5yM8DJv3l56V7LJG63ZUHJ_Al" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FBw_Wmiv3Ri2Fnf19tWaV6vI53KsVBYEKlWOaymWDONk0vOUXnjA9k-a_q5REejk16C5Db5_b9LIjjVyW5I00msFfA_pSgGzjgWApeuGwCz3p5nR5yM8DJv3l56V7LJG63ZUHJ_Al" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  iOS Setup
&lt;/h3&gt;

&lt;p&gt;In your OneSignal account, navigate _ &lt;strong&gt;Settings&lt;/strong&gt; _ and click on &lt;em&gt;&lt;strong&gt;Apple iOS (APNs)&lt;/strong&gt;&lt;/em&gt;. In this step, you will be asked for an iOS push certificate and its password.&lt;/p&gt;

&lt;p&gt;Check out the linked documentation to learn &lt;a href="https://documentation.onesignal.com/docs/generate-an-ios-push-certificate" rel="noopener noreferrer"&gt;how to generate an iOS push certificate&lt;/a&gt;. The easiest method is to use&lt;a href="https://onesignal.com/provisionator" rel="noopener noreferrer"&gt;OneSignal provisionator&lt;/a&gt;, which directly generates the p12 file and password without much hassle. Once generated, upload the p12 file and password, and continue to the next screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fg-RK42ukOsNazyECQOoa9yLCwENsb3WxMgn33m8_DXCk1wsHgjMdy74OL-S5nAirQinhg46HLWkt7xsxMrWTNnWKpWywHsnSgIqtjwtFnO3RkKxwt9pgTEmgHAWJPDp4AmCojvPlMsOb2fySWQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fg-RK42ukOsNazyECQOoa9yLCwENsb3WxMgn33m8_DXCk1wsHgjMdy74OL-S5nAirQinhg46HLWkt7xsxMrWTNnWKpWywHsnSgIqtjwtFnO3RkKxwt9pgTEmgHAWJPDp4AmCojvPlMsOb2fySWQ" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUadu5kRL8BxcMZQ9IMMenYy670uHseGf3yGR504sDO_L1saV8wPfKs-5ouH4uDWaFUKcM--LcP-sIiyckbeOxd9Zq8MTzZNbxEpXF9L21BPrtPthcwYi8ZkEVju8IWVASgG-clP6xGhg7UpwyA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUadu5kRL8BxcMZQ9IMMenYy670uHseGf3yGR504sDO_L1saV8wPfKs-5ouH4uDWaFUKcM--LcP-sIiyckbeOxd9Zq8MTzZNbxEpXF9L21BPrtPthcwYi8ZkEVju8IWVASgG-clP6xGhg7UpwyA" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload Your APNs Cert
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FVRzrv4qZcGkIrjtez8mRAu40EJexhtWj4T41HFvgkI_XuNzf0HlgVgwgLrR8y7mYqiZWzTB2vbKsGeskkZrtv5zpZViIHPyKFRrOgbIudRlhi1i8QhUw5cSyxGcan53fmIFkiIJq_VEop7cdCw" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FVRzrv4qZcGkIrjtez8mRAu40EJexhtWj4T41HFvgkI_XuNzf0HlgVgwgLrR8y7mYqiZWzTB2vbKsGeskkZrtv5zpZViIHPyKFRrOgbIudRlhi1i8QhUw5cSyxGcan53fmIFkiIJq_VEop7cdCw" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The certificate password is the one used to encrypt the exported certificate. If you left the password empty, do not enter a value for &lt;strong&gt;Certificate Password&lt;/strong&gt;. OneSignal will verify the certificate can be used for push notifications upon clicking the continue button.&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;&lt;em&gt;Flutter&lt;/em&gt;&lt;/strong&gt; SDK on this screen, the next screen is identical to the Android configuration screen. Running the same code for iOS will work without any further modifications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhtto3iouz76coli7wwcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhtto3iouz76coli7wwcy.png" alt="How to Add In-App Messages to a Flutter App" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom of the Apple iOS (APNs) Configuration screen, a warning will appear saying that your user has not subscribed. This is because we have not yet asked for permission to send push notification. We will be &lt;a href="https://onesignal.com/blog/how-to-create-more-compelling-opt-in-messages-for-ios-push/" rel="noopener noreferrer"&gt;asking for opt-in permission using in app messages&lt;/a&gt; later in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending an In-App Message
&lt;/h2&gt;

&lt;p&gt;Click on _ &lt;strong&gt;Message&lt;/strong&gt; _ from the main navigation bar and then select _ &lt;strong&gt;In-App&lt;/strong&gt; _ from the submenu that appears.&lt;/p&gt;

&lt;p&gt;Onesignal provides default in-app messaging templates which can then be customized according to your use case and preference. From the list of templates, click on &lt;strong&gt;&lt;em&gt;[Default Template] Welcome Message&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FZtKIq8Q5hxYuszQM_bH4Yf8LyDzVZsZgB3dMrfBkqx3gkPjkhDumAZwg5TERq4G_ezs-r4k-Eu9vjBwVyOu7cY-x6P3_SvKyQlOE14BT-4gA0ZaqZtPLim_I-aP10hy17lnW_o-r" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FZtKIq8Q5hxYuszQM_bH4Yf8LyDzVZsZgB3dMrfBkqx3gkPjkhDumAZwg5TERq4G_ezs-r4k-Eu9vjBwVyOu7cY-x6P3_SvKyQlOE14BT-4gA0ZaqZtPLim_I-aP10hy17lnW_o-r" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the top right corner of the screen, select &lt;strong&gt;&lt;em&gt;Actions&lt;/em&gt;&lt;/strong&gt; — a drop-down menu will appear. If you'd like to edit and customize the default welcome message, click Edit to alter the template. If you've finished editing or would simply like to test the default message as is, click _ &lt;strong&gt;Resume&lt;/strong&gt; _ from the drop-down menu. Then, run the app on your device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fek4b4x0n7rmwaua07wwj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fek4b4x0n7rmwaua07wwj.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In-App Messaging Triggers
&lt;/h2&gt;

&lt;p&gt;You can use &lt;a href="https://documentation.onesignal.com/docs/iam-triggers" rel="noopener noreferrer"&gt;Triggers&lt;/a&gt; to choose when to show the in-app message to the user. There are some predefined Triggers such as "app open," as well as custom triggers that can be set programmatically using the &lt;code&gt;addTrigger()&lt;/code&gt; function. To begin, let's try using a predefined trigger for showing an app rating message.&lt;/p&gt;

&lt;p&gt;If you're using a free OneSignal plan, you will only be able to have one in-app message live at a time. Before creating the new message, you'll need to pause the welcome in-app message by clicking _ &lt;strong&gt;Actions&lt;/strong&gt; _ and then _ &lt;strong&gt;Pause&lt;/strong&gt; _ from the drop-down menu. Then, navigate back to the main in-app messages screen and select &lt;strong&gt;&lt;em&gt;[Default Template] App Store Rating&lt;/em&gt;&lt;/strong&gt;. Select _ &lt;strong&gt;Actions&lt;/strong&gt; _ &amp;gt; &lt;strong&gt;&lt;em&gt;Edit&lt;/em&gt;&lt;/strong&gt; and then scroll down on the editing screen to the section entitled &lt;strong&gt;&lt;em&gt;3. Triggers&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FF1o5vfGYugkkpPBcJoaGGVfhuSmaPdjEd1TkbUSpk-PmgAz9ivXwtK3jDelGDDxzx-os2pGc--S4ldpcUdJKmwjUplscPUaS_9l9VdrBp-Tea_xeGZZ5zD3FdkJOURk9rXi_GU72" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FF1o5vfGYugkkpPBcJoaGGVfhuSmaPdjEd1TkbUSpk-PmgAz9ivXwtK3jDelGDDxzx-os2pGc--S4ldpcUdJKmwjUplscPUaS_9l9VdrBp-Tea_xeGZZ5zD3FdkJOURk9rXi_GU72" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When should users see this message? select _ &lt;strong&gt;When certain conditions are satisfied during the session&lt;/strong&gt; &lt;em&gt;. You should see two form fields for **_session duration&lt;/em&gt;** and _ &lt;strong&gt;duration since the last in-app&lt;/strong&gt; &lt;em&gt;. Enter a session duration greater than 10 seconds for demonstration purposes, then scroll down to the bottom of the page and click on the blue **_Update Message&lt;/em&gt;** button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FJfiPv71jN9ad6eXNRlmIbd_RWTenYhSOiX6JI8265cwDjJhbeZ7ZHLiRckmlkzTtBPhM_MZOyXxAISjtTodSo3KBOhmZrrY37uVWIb-r2Wa3-IOsruDfKTzX4ckghxg0AwLds0OI" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FJfiPv71jN9ad6eXNRlmIbd_RWTenYhSOiX6JI8265cwDjJhbeZ7ZHLiRckmlkzTtBPhM_MZOyXxAISjtTodSo3KBOhmZrrY37uVWIb-r2Wa3-IOsruDfKTzX4ckghxg0AwLds0OI" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, from the list of In-app messages, click _ &lt;strong&gt;Actions&lt;/strong&gt; _ &amp;gt; _ &lt;strong&gt;Resume&lt;/strong&gt; _ for this message and then open the app. After 10 seconds, you should see a rating request message inside your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fwjacxbdnq2i36w8e4l7e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwjacxbdnq2i36w8e4l7e.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example demonstrates the power of in-app messaging! Using OneSignal's in-app messaging tool, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add and remove in-app messages remotely without requiring any app update.&lt;/li&gt;
&lt;li&gt;Leverage useful, pre-made triggers such as _ &lt;strong&gt;app open&lt;/strong&gt; &lt;em&gt;, **_session duration&lt;/em&gt;** , and _ &lt;strong&gt;duration since the last in-app message&lt;/strong&gt; _, along with the option to club these triggers with an OR operation. This makes implementing a wide range of in-app messaging strategies possible without requiring any code customizations!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Asking for Push Permission (iOS)
&lt;/h3&gt;

&lt;p&gt;In iOS, a user needs to grant permission to an app in order to receive push notifications. As a general rule of thumb, you don’t want to ask a user for push notification permission immediately when they first launch the app because they aren't likely to understand the value of notifications at that early stage of adoption. Onesignal provides a predefined in-app messaging template to help you &lt;a href="https://onesignal.com/blog/how-to-create-more-compelling-opt-in-messages-for-ios-push/" rel="noopener noreferrer"&gt;time your opt-in request and give users more context to inform th&lt;/a&gt;eir opt-in decision.&lt;/p&gt;

&lt;p&gt;To try out this prompt, pause the current message (if you're using a free account), then click &lt;strong&gt;&lt;em&gt;Action&lt;/em&gt;&lt;/strong&gt; &amp;gt; _ &lt;strong&gt;Resume&lt;/strong&gt; _ to enable the &lt;em&gt;&lt;strong&gt;[Default Template] Push Permission Prompt&lt;/strong&gt;&lt;/em&gt;. This prompt has been set to show the user a message asking for permission upon launching the app, but the trigger and message content can be customized to provide a better user experience and increase the likelihood of opt-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fp48byix82w1x7loo3sqs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fp48byix82w1x7loo3sqs.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the clicks to &lt;strong&gt;&lt;em&gt;Allow&lt;/em&gt;&lt;/strong&gt; notifications in the in-app message, it will automatically trigger the native iOS permission prompt. If they click &lt;strong&gt;&lt;em&gt;Maybe Later&lt;/em&gt;&lt;/strong&gt; , they will be opted out of notifications but can be prompted again later with an in-app message encouraging them to revisit this decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2juabnavnfaawnxxrh3u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2juabnavnfaawnxxrh3u.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If a user denies permission to receive notifications the first time around, but later clicks _ &lt;strong&gt;Allow&lt;/strong&gt; _ when they are re-prompted, they will be taken to the notification settings where they will have to manually allow the app to show notifications — this is a restriction imposed by iOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Custom Triggers in In-App Messaging
&lt;/h3&gt;

&lt;p&gt;Custom triggers are key-value pairs of string or integer types to which the SDK responds. Whenever the condition set is satisfied, the trigger is initiated. Custom triggers can be clubbed together with AND and OR to create more complex triggers.&lt;/p&gt;

&lt;p&gt;For demonstration purposes, let’s build a button that, when tapped eight times, will trigger a promotional in-app message.&lt;/p&gt;

&lt;p&gt;To do so, open &lt;code&gt;main.dart&lt;/code&gt; and add a floating action button to the scaffold, along with a variable to save the button tap count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void main() {
 runApp(const MyApp());
}

class MyApp extends StatelessWidget {
 const MyApp({Key? key}) : super(key: key);

 // This widget is the root of your application.
 @override
 Widget build(BuildContext context) {
   return const MaterialApp(
     home: MyHomePage(),
   );
 }
}

class MyHomePage extends StatefulWidget {
 const MyHomePage({Key? key}) : super(key: key);

 @override
 State&amp;lt;MyHomePage&amp;gt; createState() =&amp;gt; _MyHomePageState();
}

class _MyHomePageState extends State&amp;lt;MyHomePage&amp;gt; {
 int taps = 0;

 @override
 void initState() {
   super.initState();
   initMessaging();
 }

 Future&amp;lt;void&amp;gt; initMessaging() async {
   await OneSignal.shared.setAppId("f3afbef4-2fe4-452b-a391-b8175c2b65a1");
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: const Text('OneSignal IAM'),
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: () {
         setState(() {
           taps = taps + 1;
         });
         OneSignal.shared.addTrigger('taps', taps);
       },
       child: const Icon(Icons.add),
     ),
     body: const Center(child: Text('IAM')),
   );
 }

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

&lt;/div&gt;



&lt;p&gt;Open the OneSignal dashboard, select the &lt;em&gt;&lt;strong&gt;[Default Template] 10% Off Promotional&lt;/strong&gt;&lt;/em&gt; template, and click _ &lt;strong&gt;Actions&lt;/strong&gt; _ &amp;gt; _ &lt;strong&gt;Edit&lt;/strong&gt; &lt;em&gt;. On the editing page, scroll down until you see the **_3. Triggers&lt;/em&gt;** section. Under the question, &lt;strong&gt;&lt;em&gt;When should users see this message?&lt;/em&gt;&lt;/strong&gt; select &lt;strong&gt;&lt;em&gt;When certain conditions are satisfied during the session&lt;/em&gt;&lt;/strong&gt;. Click &lt;strong&gt;&lt;em&gt;IN-APP TRIGGER&lt;/em&gt;&lt;/strong&gt; and input &lt;strong&gt;&lt;em&gt;taps is 8&lt;/em&gt;&lt;/strong&gt; to the appropriate form fields, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FFqsNq5n7ROCTM0b-uGsMMXftLnKgyXwvMA1yAQKLVjd2aae2v_o90yx5QHwB8OIT8VV-voQrXSikhU4N368zWtojvWs_kRwvVaX0s-YEivH2G5Qx2mnRvZryxDKMnZ2aEmNx7aPv" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FFqsNq5n7ROCTM0b-uGsMMXftLnKgyXwvMA1yAQKLVjd2aae2v_o90yx5QHwB8OIT8VV-voQrXSikhU4N368zWtojvWs_kRwvVaX0s-YEivH2G5Qx2mnRvZryxDKMnZ2aEmNx7aPv" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, click _ &lt;strong&gt;Add Trigger&lt;/strong&gt; _ and then scroll to the bottom of the page and click &lt;strong&gt;&lt;em&gt;Update Message&lt;/em&gt;&lt;/strong&gt;. If you followed along and implemented the previous example, the push permission prompt will still be live. If you are using a free plan, pause that message, navigate back to your promotional message, and click &lt;strong&gt;&lt;em&gt;Actions&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;Resume&lt;/em&gt;&lt;/strong&gt; to set this one live. Now, run the app with the updated code. Tap the button 8 times and the promotional message should pop up on your screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7nsq2qnqxt81uzrmx9ye.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7nsq2qnqxt81uzrmx9ye.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This custom trigger was an example of &lt;code&gt;key&lt;/code&gt; is &lt;code&gt;value&lt;/code&gt; pair. There are other conditions on which the triggers can be set as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F1RHH9EqDClgKyMnlqql3-bPUYFdTk12FCVdYDn3hmk4AlFBwzZa09vIc-a0M4y4H3XbZ36D8d0b1__5bcCvm7KxKVDyHB36PGMWoNIdzMtVmOIGDS9S-ivbuUorFp9mNNTxqEQ16" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F1RHH9EqDClgKyMnlqql3-bPUYFdTk12FCVdYDn3hmk4AlFBwzZa09vIc-a0M4y4H3XbZ36D8d0b1__5bcCvm7KxKVDyHB36PGMWoNIdzMtVmOIGDS9S-ivbuUorFp9mNNTxqEQ16" alt="How to Add In-App Messages to a Flutter App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the best things about Onesignal's in-app messaging tool is the ability to overhaul the design of the popup without doing an app update. To demonstrate, let's update the current 10% promotional message to something more appropriate. To do so, first click _ &lt;strong&gt;Actions&lt;/strong&gt; _ &amp;gt; &lt;strong&gt;&lt;em&gt;Pause&lt;/em&gt;&lt;/strong&gt; to pause the current message, then click on _ &lt;strong&gt;Edit&lt;/strong&gt; _.&lt;/p&gt;

&lt;p&gt;All the UI elements are highly customizable in the OneSignal message builder, as can be seen in the video below. Almost all aspects of text can be formatted to suit the design language of your app.&lt;/p&gt;

&lt;p&gt;&amp;lt;!--kg-card-begin: html--&amp;gt;&amp;lt;!--kg-card-end: html--&amp;gt;&lt;/p&gt;

&lt;p&gt;Messages also do not have to be fixed to a particular type of layout. All the UI elements can be reordered on the fly without requiring an app update.&lt;/p&gt;

&lt;p&gt;&amp;lt;!--kg-card-begin: html--&amp;gt;&amp;lt;!--kg-card-end: html--&amp;gt;&lt;/p&gt;

&lt;p&gt;In-app messages also support GIFs!&lt;/p&gt;

&lt;p&gt;&amp;lt;!--kg-card-begin: html--&amp;gt;&amp;lt;!--kg-card-end: html--&amp;gt;&lt;/p&gt;

&lt;p&gt;Let’s apply all these changes, scroll to the bottom and click _ &lt;strong&gt;Update Message&lt;/strong&gt; _. No need to update any code, just open the app again!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Futghml99gl5jmjzlftiv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Futghml99gl5jmjzlftiv.jpg" alt="How to Add In-App Messages to a Flutter App" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Click Actions in Messages
&lt;/h2&gt;

&lt;p&gt;Onesignal provides a handful of click actions out of the box that can be customized from the dashboard. There is also a Custom Action ID, in which a custom action ID string is sent, which can handle custom cases such as deep-linking, app updates, or any other functionality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F74pnasojuz2u0rwxjh6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F74pnasojuz2u0rwxjh6q.png" alt="How to Add In-App Messages to a Flutter App" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s implement a URL click action first. Implementing an URL means that when a user clicks on the button, they will be taken to the specified URL. To add a link, click &lt;strong&gt;&lt;em&gt;Actions&lt;/em&gt;&lt;/strong&gt; &amp;gt; _ &lt;strong&gt;Edit&lt;/strong&gt; _ on the promotional message (if you closed out from the last example) and scroll down to the _ &lt;strong&gt;Button 1&lt;/strong&gt; _ box and update the URL. Then, scroll down to the bottom of the page and click _ &lt;strong&gt;Update Message&lt;/strong&gt; &lt;em&gt;. Then, click _ &lt;strong&gt;Action&lt;/strong&gt; _ &amp;gt; **_Resume&lt;/em&gt;** to resume the message. To test it out, open your app and tap the button 8 times again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Focfcb0pr8d4ff2bkmp1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Focfcb0pr8d4ff2bkmp1q.png" alt="How to Add In-App Messages to a Flutter App" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the message pops up, press the first button and you should be taken to the website link you provided.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Click Action ( Custom Action ID)
&lt;/h2&gt;

&lt;p&gt;Creating custom click actions requires developer support. All the use cases that may be necessary for the future should be listed beforehand and handled in the code.&lt;/p&gt;

&lt;p&gt;In this example let’s try deep linking to a second page when pressing the button. To do so, create a new file called success_screen.dart and add this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter/material.dart';
class SuccessScreen extends StatelessWidget {
  const SuccessScreen({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text(
          'Success',
          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 42),
        ),
      ),
    );
  }

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

&lt;/div&gt;



&lt;p&gt;Now, go to the &lt;code&gt;initMessaging()&lt;/code&gt; in &lt;code&gt;main.dart&lt;/code&gt; and add a &lt;code&gt;setInAppMessageClickedHandler&lt;/code&gt; to listen to any click actions that happen on the message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Future&amp;lt;void&amp;gt; initMessaging() async {
    await OneSignal.shared.setAppId("f3afbef4-2fe4-452b-a391-b8175c2b65a1");
    OneSignal.shared.setInAppMessageClickedHandler((action) {
      if (action.clickName == 'successPage') {
        Navigator.of(context)
            .push(MaterialPageRoute(builder: (_) =&amp;gt; const SuccessScreen()));
      }
    });
  }

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

&lt;/div&gt;



&lt;p&gt;This works as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;set &lt;code&gt;InAppMessageClickedHandler&lt;/code&gt; listens to any action event that is emitted by interacting with any UI element.&lt;/li&gt;
&lt;li&gt;When a click action is set in the OneSignal console, it means that an action binds to that UI element.&lt;/li&gt;
&lt;li&gt;Whenever an interaction occurs with that element, the action is triggered.&lt;/li&gt;
&lt;li&gt;If that action is a pre-defined one, such as opening a URL, then while the click handler will listen to the action being emitted, the action to perform is already handled by the SDK and will result in opening the URL in the browser.&lt;/li&gt;
&lt;li&gt;For action IDs that you specify, you can build different use cases as shown in the above example to handle different action IDs.&lt;/li&gt;
&lt;li&gt;In the above snippet, the action &lt;a href="https://documentation.onesignal.com/docs/iam-sdk-methods#in-app-message-click-handler" rel="noopener noreferrer"&gt;has many properties&lt;/a&gt; which can be further leveraged to create better user experiences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, click &lt;strong&gt;&lt;em&gt;Action&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;Pause&lt;/em&gt;&lt;/strong&gt; to pause the current message and then select &lt;strong&gt;&lt;em&gt;Edit&lt;/em&gt;&lt;/strong&gt;. Scroll down to the button to which a click action has to be added. Then, select &lt;strong&gt;&lt;em&gt;Custom Action ID&lt;/em&gt;&lt;/strong&gt; and give the action a name such as &lt;strong&gt;&lt;em&gt;successPage&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8w93st7ylublxc31y09u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8w93st7ylublxc31y09u.png" alt="How to Add In-App Messages to a Flutter App" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, scroll down to the bottom of the screen and click &lt;strong&gt;&lt;em&gt;Update Message&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Resume&lt;/em&gt;&lt;/strong&gt; the message via the &lt;strong&gt;&lt;em&gt;Actions&lt;/em&gt;&lt;/strong&gt; menu. Now, run the updated app.&lt;/p&gt;

&lt;p&gt;When you click on the button, you should have successfully implemented deep linking!&lt;/p&gt;

&lt;p&gt;&amp;lt;!--kg-card-begin: html--&amp;gt;&amp;lt;!--kg-card-end: html--&amp;gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Share Your Feedback
&lt;/h2&gt;

&lt;p&gt;We'd love to know what you think and answer any additional questions you have. To connect with us, &lt;a href="https://github.com/OneSignal/onesignal-vue/issues" rel="noopener noreferrer"&gt;create an issue on GitHub&lt;/a&gt; or ping us on the &lt;a href="https://discord.com/invite/EP7gf6Uz7G" rel="noopener noreferrer"&gt;OneSignalDevs Discord server&lt;/a&gt; to share your experience.  We appreciate any insight you can share to help us better serve Vue.js users!&lt;/p&gt;

&lt;p&gt;To stay in the loop with the latest product updates and innovations, follow the &lt;a href="https://twitter.com/onesignaldevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt;. For additional support and dev inspiration, tap into our global developer community.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&amp;gt;&amp;gt; &lt;a href="https://onesignal.com/onesignal-developers" rel="noopener noreferrer"&gt;Connect with the OneSignal Developer Community&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This guest post was authored by Chinmay Kabi&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobiledev</category>
    </item>
    <item>
      <title>How to Add In-App Messages in React Native (Expo)</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Fri, 20 May 2022 21:07:27 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-add-in-app-messages-in-react-native-expo-o6c</link>
      <guid>https://dev.to/onesignal/how-to-add-in-app-messages-in-react-native-expo-o6c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F4eaj4a0bxussnuzr1llq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4eaj4a0bxussnuzr1llq.jpg" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://onesignal.com/in-app" rel="noopener noreferrer"&gt;In-app messages&lt;/a&gt; (IAM) are highly customizable pop-up interstitials that mobile app user receive inside your application. Unlike push notifications, IAM don’t require opt-in permission and they only show when the users are actively using your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;OneSignal &amp;amp; Your Browser's Push API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It’s no secret that in-app messages can help you engage and &lt;a href="https://onesignal.com/blog/easy-strategies-to-increase-app-retention/" rel="noopener noreferrer"&gt;retain app users&lt;/a&gt;. This tutorial will show you how to integrate with the &lt;a href="https://github.com/OneSignal/onesignal-expo-plugin" rel="noopener noreferrer"&gt;React Native OneSignal NPM package&lt;/a&gt; to leverage IAM in your React app.&lt;/p&gt;

&lt;p&gt;Some valuable use cases for IAM include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Onboarding:&lt;/strong&gt; Guide your users through getting started with your application. Use an &lt;a href="https://onesignal.com/blog/new-feature-in-app-carousel/" rel="noopener noreferrer"&gt;in-app slide carousel&lt;/a&gt; to &lt;a href="https://onesignal.com/blog/how-to-build-an-effective-mobile-app-onboarding-process/" rel="noopener noreferrer"&gt;build an effective onboarding process&lt;/a&gt;, introduce them to key application features, and emphasize the value your app will provide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Announcing New Products &amp;amp; Features:&lt;/strong&gt; Inform your users when you have added new products and features to the application to improve adoption and enhance the UX.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requesting Push Permission &amp;amp; Location Access:&lt;/strong&gt; Provide users with more context to &lt;a href="https://onesignal.com/blog/how-to-create-more-compelling-opt-in-messages-for-ios-push/" rel="noopener noreferrer"&gt;inform their opt-in decision&lt;/a&gt; or request location or other access permissions that are vital to your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encouraging Referrals:&lt;/strong&gt; Allow your users to invite their friends to your application with a single click to grow your active users and build community.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial will cover how to integrate the &lt;a href="https://github.com/OneSignal/onesignal-expo-plugin" rel="noopener noreferrer"&gt;React Native Expo OneSignal Plugin&lt;/a&gt; (managed workflow) into your app in order to gain in-app messaging functionality. Part one of this guide covers the OneSignal setup process. Part two of this guide covers how to integrate OneSignal with React using our NPM package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Part 1: Set up Your OneSignal Account (for free!)&lt;/li&gt;
&lt;li&gt;Part 2: Push Notification Setup in React&lt;/li&gt;
&lt;li&gt;Send an In-App Message to Your Android Device&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires some basic knowledge of React Native (Expo). I'm using the &lt;a href="https://docs.expo.dev/get-started/installation/#installing-expo-cli" rel="noopener noreferrer"&gt;Expo CLI&lt;/a&gt; to generate my project and &lt;strong&gt;NodeJS version 14.16&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional React Setup Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/OneSignalDevelopers/OneSignal-React-NPM-Sample" rel="noopener noreferrer"&gt;React Native (Expo) plugin Sample Ap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Set Up Your OneSignal Account
&lt;/h2&gt;

&lt;p&gt;To begin, &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;login&lt;/a&gt; to your OneSignal account or &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt;. Then, click on the blue button entitled _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ to configure your OneSignal account to fit your app or website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FmmDxy2BLsH0r6cTYs6pBt53Wc0pWoEAePBF2XR-dXRubANxdbkfBxXd2ren0MfUGrjvbSxPoIjy6tbNDRL_g4hwxpNa_MyHSxgK817OgDtsPmxXvAS7XCJ8uProuG_yWaudEgfRM1ZffVIXigQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FmmDxy2BLsH0r6cTYs6pBt53Wc0pWoEAePBF2XR-dXRubANxdbkfBxXd2ren0MfUGrjvbSxPoIjy6tbNDRL_g4hwxpNa_MyHSxgK817OgDtsPmxXvAS7XCJ8uProuG_yWaudEgfRM1ZffVIXigQ" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Insert the name of your app or website. Select _ &lt;strong&gt;Google Android&lt;/strong&gt; _ as your platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FUMgdQ0-ewQrO8JWj-NqhGp7yENRAsWZ5gJzo2zQ7nV3tBZZGjlT6qJ1nX2Gs_Cw4l7MfdPEEjMfws_O4jeKUwdtdLdk-vWsvCeCi8v11uBYY6oJcdl4IEZxsN6RBGYDt03z9-gtjJ2d9q6810g" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FUMgdQ0-ewQrO8JWj-NqhGp7yENRAsWZ5gJzo2zQ7nV3tBZZGjlT6qJ1nX2Gs_Cw4l7MfdPEEjMfws_O4jeKUwdtdLdk-vWsvCeCi8v11uBYY6oJcdl4IEZxsN6RBGYDt03z9-gtjJ2d9q6810g" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the blue button entitled, _ &lt;strong&gt;Next: Configure Your Platform&lt;/strong&gt; _.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Google Android FCM Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It’s time to configure your Android app using a Firebase Server key. All Android apps require this key and the server ID if you want to send push notifications. If you don’t have the Firebase Server Keys, take a look at our documentation to learn &lt;a href="https://documentation.onesignal.com/docs/generate-a-google-server-api-key" rel="noopener noreferrer"&gt;how to generate a Firebase server API key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FvL286nxIjKWeEbPDVE591BEgqJDj05Lhqvt7l9lhaZzSY9TmY94ncSsoS-LTMsMORHoqMc2vOAMLNnlP3MmszN0ZVRLfXykiaPDha3iCGbp_sB-292FqvNMo105SqyNkp3b0cOjjGlGm_dZopA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FvL286nxIjKWeEbPDVE591BEgqJDj05Lhqvt7l9lhaZzSY9TmY94ncSsoS-LTMsMORHoqMc2vOAMLNnlP3MmszN0ZVRLfXykiaPDha3iCGbp_sB-292FqvNMo105SqyNkp3b0cOjjGlGm_dZopA" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now select your target SDK. We'll take you through the steps to get your first user and send your first test notification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FUnAuqw-DiXoSCyQHRawunv-u4ys4IjxQWgfuDqc8rsu2cPfrZAfzqRQiPsDrMDufK9QOE9stjCecGD0EIALzuJs0Wl2l9G2cgO3OU3dgZfn7jlyqRaONUO0OOBK9VZD-_OA6Ghm1vuyrlRXamg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FUnAuqw-DiXoSCyQHRawunv-u4ys4IjxQWgfuDqc8rsu2cPfrZAfzqRQiPsDrMDufK9QOE9stjCecGD0EIALzuJs0Wl2l9G2cgO3OU3dgZfn7jlyqRaONUO0OOBK9VZD-_OA6Ghm1vuyrlRXamg" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen that appears, you will see your app ID — copy that app ID because you will use it inside of your Expo Application. &lt;strong&gt;DO NOT&lt;/strong&gt; click to &lt;strong&gt;&lt;em&gt;Check Subscribed Users&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;Done&lt;/em&gt;&lt;/strong&gt; yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fvm5pRv1rygAfjzghVDNa-jTy1OxOkW18g7WUUeVB38zb11PJOxJ9dMqhh-Ayfo1ZCl_ZPQBJLa9u4AuHKHyLJ1-fW6EX78pcZ52xRH2KbhagNqhvm1MBiuVQ1P_5qyXz3BXXm0ML3M7S9GXnOg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fvm5pRv1rygAfjzghVDNa-jTy1OxOkW18g7WUUeVB38zb11PJOxJ9dMqhh-Ayfo1ZCl_ZPQBJLa9u4AuHKHyLJ1-fW6EX78pcZ52xRH2KbhagNqhvm1MBiuVQ1P_5qyXz3BXXm0ML3M7S9GXnOg" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Push Notification Setup In React Native Expo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating Your React App
&lt;/h3&gt;

&lt;p&gt;Inside of your terminal, run the following commands to create a new React project using Create&lt;br&gt;&lt;br&gt;
Expo App:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo init onesignal-rn-expo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When asked, selec any of the options under the &lt;strong&gt;&lt;em&gt;Managed Workflow&lt;/em&gt;&lt;/strong&gt;. In my case, I selected the first option, which is &lt;strong&gt;&lt;em&gt;blank&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FIYDO7EONtfeZAiLYsjnjYiej-oevyB0i4awuljvxjV6PZEZmOWqwzeY1aIe3mxRcmOJMto-3fCLhfp_5MVpZe01NKCeswoHYLb53b2azEI-SPAbLwCiR9dsk0YPXaIa3Mlidhaad7XU0IGq6sA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FIYDO7EONtfeZAiLYsjnjYiej-oevyB0i4awuljvxjV6PZEZmOWqwzeY1aIe3mxRcmOJMto-3fCLhfp_5MVpZe01NKCeswoHYLb53b2azEI-SPAbLwCiR9dsk0YPXaIa3Mlidhaad7XU0IGq6sA" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd onesignal-rn-expo
expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the official Expo, documentation click &lt;a href="https://docs.expo.dev/get-started/create-a-new-app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install OneSignal Expo Plugin
&lt;/h3&gt;

&lt;p&gt;Inside of your project folder, open your terminal and run the following command to install the &lt;a href="https://github.com/OneSignal/onesignal-expo-plugin" rel="noopener noreferrer"&gt;OneSignal Expo Plugin&lt;/a&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo install onesignal-expo-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, install the React Native OneSignal plugin by running 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;yarn add react-native-onesignal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though &lt;code&gt;onesignal-expo-plugin&lt;/code&gt; defines &lt;code&gt;react-native-onesignal&lt;/code&gt; as a dependency and it gets put into the &lt;code&gt;node_module&lt;/code&gt;, it will make sure the native parts get built.&lt;/p&gt;

&lt;p&gt;If you forgot to run the following command after you have built your project, you can fix this by running expo prebuild --clean. This should delete android and ios and do a clean native build, then run the yarn add &lt;code&gt;react-native-onesignal&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration in app.json / app.config.js
&lt;/h2&gt;

&lt;p&gt;Inside the &lt;code&gt;app.json/app.config.js&lt;/code&gt; file, add the plugin to the &lt;a href="https://docs.expo.dev/versions/latest/config/app/" rel="noopener noreferrer"&gt;plugin array&lt;/a&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  App.json
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "plugins": [
    [
      "onesignal-expo-plugin",
      {
        "mode": "development",
        "devTeam": "91SW8A37CR"
      }
    ]
  ]
}

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

&lt;/div&gt;



&lt;p&gt;or&lt;/p&gt;

&lt;h3&gt;
  
  
  App.config.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
...
plugins: [
        [
        "onesignal-expo-plugin",
            {
                mode: process.env.NODE_ENV || "development",
                devTeam: "91SW8A37CR"
            }
        ]
    ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plugin Options
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mode&lt;/code&gt;: used to configure &lt;a href="https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment" rel="noopener noreferrer"&gt;APNs environment&lt;/a&gt; entitlement.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"development"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"production"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;devTeam&lt;/code&gt;: *optional* used to configure Apple Team ID. You can find your Apple Team ID by running &lt;code&gt;expo credentials:manager&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "extra": {
        "oneSignalAppId": "&amp;lt;YOUR APP ID HERE&amp;gt;"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then access the value to pass to the &lt;code&gt;setAppId&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import OneSignal from 'react-native-onesignal';
import Constants from "expo-constants";
OneSignal.setAppId(Constants.manifest.extra.oneSignalAppId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, pass the OneSignal app ID directly to the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import OneSignal from 'react-native-onesignal';
import Constants from "expo-constants";

OneSignal.setAppId("YOUR-ONESIGNAL-APP-ID");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run &amp;amp; Build your Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo prebuild
# Build your native iOS project
$ expo run:ios
# Build your native Android project
expo run:android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send an In-App Message to your Android Device
&lt;/h2&gt;

&lt;p&gt;I recommend you run the application on an actual Android device to test the in-app messages. To do so, you will need to connect your Android device and enable &lt;a href="https://developer.android.com/studio/debug/dev-options" rel="noopener noreferrer"&gt;developer mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have connected to the device and enabled developer mode, run the application on your device by selecting your device as the target device. In my example, I’m running the app on a &lt;strong&gt;Google Pixel 5&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fn4CUphIQxx3Cy3uTNuSeAbr3oVjuS8OolfjMtLnM0iEext6VprhmTqiopVKsexQFvyole6MxwlAs1TjrKaTJp5XYTsjEN3QVhoY5U4wf5QSUT98tIN_A9vkHdA1Ak3VQOLM-Uw5wzQbLnqAGvQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fn4CUphIQxx3Cy3uTNuSeAbr3oVjuS8OolfjMtLnM0iEext6VprhmTqiopVKsexQFvyole6MxwlAs1TjrKaTJp5XYTsjEN3QVhoY5U4wf5QSUT98tIN_A9vkHdA1Ak3VQOLM-Uw5wzQbLnqAGvQ" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have opened the application on your device, the device will be automatically be subscribed to notifications. Now, your device will be able to receive notifications sent by OneSignal.  &lt;/p&gt;

&lt;p&gt;To complete the setup process, return to your OneSignal dashboard to the point at which you previously left off. Click on the _ &lt;strong&gt;Check Subscribed Users&lt;/strong&gt; _ button and a green message will appear like the one in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FhpI4isUt78oBqR30nY39oeAYV3ZcfHq_KLgNyQhKcnDHnfGjJuJm7KR6-er-qUzBWfTjrh_ogAWzVvbKECXrdibUBs6IEpJ7rqB-WUtJYKiwlAjxG8dBhqXBDlYva06fE2VLkepGwOPZEHnUCw" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FhpI4isUt78oBqR30nY39oeAYV3ZcfHq_KLgNyQhKcnDHnfGjJuJm7KR6-er-qUzBWfTjrh_ogAWzVvbKECXrdibUBs6IEpJ7rqB-WUtJYKiwlAjxG8dBhqXBDlYva06fE2VLkepGwOPZEHnUCw" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the _ &lt;strong&gt;Done&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an In-App Message
&lt;/h3&gt;

&lt;p&gt;It’s time to send your first in-app message! To do so, login to your OneSignal account and navigate to the &lt;strong&gt;&lt;em&gt;Dashboard&lt;/em&gt;&lt;/strong&gt; tab. On the dashboard page, click on the tab that says &lt;strong&gt;&lt;em&gt;Messages&lt;/em&gt;&lt;/strong&gt; and you will be redirected to a new page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F4GgK6n4VfIDMlbN2AuXt5kRbjVIg64L-lcUtb7Y2sEjcwVoK-t1HCeUsSkXSGFS9r4EYq01a3PUiPibT-0oyYmJmwZ6vbYotaRO3wrLNv-V7I6UFmr1LXrGR6LzkgJv_PhD4dtgYFfBfyeMWyQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F4GgK6n4VfIDMlbN2AuXt5kRbjVIg64L-lcUtb7Y2sEjcwVoK-t1HCeUsSkXSGFS9r4EYq01a3PUiPibT-0oyYmJmwZ6vbYotaRO3wrLNv-V7I6UFmr1LXrGR6LzkgJv_PhD4dtgYFfBfyeMWyQ" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the _ &lt;strong&gt;In-App&lt;/strong&gt; _ tab from the submenu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FxpLj2MNhOgXUdfazMqbwpCh7H_ng57drr5e22ZfdKoUDLDvuHgYFCUnxnyIXccE9PMZJW0aNR8HEs1f5lUkTfbXWMCJP6g-Jnam2A_m8tK7G_8nPniC6SXMSyV4e9PDSfURGD09VWZAdE1yGyA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FxpLj2MNhOgXUdfazMqbwpCh7H_ng57drr5e22ZfdKoUDLDvuHgYFCUnxnyIXccE9PMZJW0aNR8HEs1f5lUkTfbXWMCJP6g-Jnam2A_m8tK7G_8nPniC6SXMSyV4e9PDSfURGD09VWZAdE1yGyA" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking on &lt;strong&gt;_In-App,  _&lt;/strong&gt; you will see the In-App Messages dashboard (pictured below). Click on the blue button &lt;strong&gt;&lt;em&gt;New In-App&lt;/em&gt;&lt;/strong&gt; button to create your first message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FQqYixzwUhOq2rMNCR_D9AqlNrFoLsQkmIkC6KFr4at8XTlrLFW3zsvqwhJxRXQvODMXwAqLi4KJIxSOlUN9YxoFXaUkiNAGuR1iefIOZFgBhW2dn1LZwsnyKa0E6rJ-mzlDz6OnTHf8l3dme_Q" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FQqYixzwUhOq2rMNCR_D9AqlNrFoLsQkmIkC6KFr4at8XTlrLFW3zsvqwhJxRXQvODMXwAqLi4KJIxSOlUN9YxoFXaUkiNAGuR1iefIOZFgBhW2dn1LZwsnyKa0E6rJ-mzlDz6OnTHf8l3dme_Q" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this page, you customize the In-App Message, from the content to display, the position, the image, your audience, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FTrn46CgKJ14dgMzYRAoZZroQ-DPMW2f_ur07e-CUTXZ-0Z1u3RhLA2l4MSYPgbq6wzl4fNRlTejjhVPiJFr1DaaKE-3lTN85TA4G1elFh3vxDXZerVz3LcWNTpmZEITc2eVBadoWhe4M_9nDjg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FTrn46CgKJ14dgMzYRAoZZroQ-DPMW2f_ur07e-CUTXZ-0Z1u3RhLA2l4MSYPgbq6wzl4fNRlTejjhVPiJFr1DaaKE-3lTN85TA4G1elFh3vxDXZerVz3LcWNTpmZEITc2eVBadoWhe4M_9nDjg" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have finishing configuring sections one and two, scroll down to the triggers section (Section three. For testing purposes, select the _ &lt;strong&gt;On app open&lt;/strong&gt; _ option. This option will automatically trigger the in-app message to appear when the app is opened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2Fe1_dKkgBQMB8mCMYmrQovP-QqFYHqmRzWlzYs54a_pzyi_HQoSHgnZ5SU1oSYkntospJ-3V-UXGHE8VnlNQRtJN3MlCATxHVuP-WZOKM0HLLoOqMb3tT_bBH3kzc0JWKzUWzzAoSR7bvelBOJQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2Fe1_dKkgBQMB8mCMYmrQovP-QqFYHqmRzWlzYs54a_pzyi_HQoSHgnZ5SU1oSYkntospJ-3V-UXGHE8VnlNQRtJN3MlCATxHVuP-WZOKM0HLLoOqMb3tT_bBH3kzc0JWKzUWzzAoSR7bvelBOJQ" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, in the Schedule section, make sure your configuration looks like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FXbawhDcDijbP67qmATndvse_VZxkuhxdJbETcYtb1E2IFYNVWKoooBLZ5wboeFDf-LoYd7FibzAwZpOLrqr43kHrTA9igtDI1bhMlJZF5rEpHQfCY_-0SgBYo1pbjv0xKKRA7BO0GmBGscBQrg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FXbawhDcDijbP67qmATndvse_VZxkuhxdJbETcYtb1E2IFYNVWKoooBLZ5wboeFDf-LoYd7FibzAwZpOLrqr43kHrTA9igtDI1bhMlJZF5rEpHQfCY_-0SgBYo1pbjv0xKKRA7BO0GmBGscBQrg" alt="How to Add In-App Messages in React Native (Expo)" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Under Schedule, select "Immediately," "Show forever," "Show until dismissed," and "Only once."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This configuration will send the message immediately and only once when you open the app.&lt;/p&gt;

&lt;p&gt;Now it's time to set your in-app message live! To do so, click on the blue button that says _ &lt;strong&gt;Make Message Live&lt;/strong&gt; _.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect With Us
&lt;/h2&gt;

&lt;p&gt;Don’t forget to follow the &lt;a href="https://twitter.com/onesignaldevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt; and join our &lt;a href="https://discord.gg/EP7gf6Uz7G" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt; to learn more and connect with the OneSignal community of developers around the world.&lt;/p&gt;

&lt;p&gt;Want to learn more about the OneSignal community? Visit our &lt;a href="https://onesignal.com/onesignal-developers" rel="noopener noreferrer"&gt;official website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mobiledev</category>
      <category>android</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>How to Send Push Notifications with the OneSignal NodeJS Client SDK</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Fri, 13 May 2022 16:25:56 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-send-push-notifications-with-the-onesignal-nodejs-client-sdk-448g</link>
      <guid>https://dev.to/onesignal/how-to-send-push-notifications-with-the-onesignal-nodejs-client-sdk-448g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fa7wg6ls6o287laj80no7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fa7wg6ls6o287laj80no7.jpg" alt="How to Send Push Notifications with the OneSignal NodeJS Client SDK" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s no secret that push notifications can help you engage and retain app users. In this tutorial, we'll show you how to use the &lt;a href="https://github.com/OneSignal/node-onesignal" rel="noopener noreferrer"&gt;OneSignal NodeJS Client SDK&lt;/a&gt; to interact with all the OneSignal functionalities that you have available in our &lt;a href="https://documentation.onesignal.com/reference/create-notification" rel="noopener noreferrer"&gt;REST API&lt;/a&gt; but we made it easier for you with this wrapper.  &lt;/p&gt;

&lt;p&gt;Using the OneSignal NodeJS Client SDK is very useful because it can help you integrate OneSignal into different workflows that your applications may have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful resources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://onesignal.com/blog/how-to-send-push-notifications-with-the-onesignal-rest-api/" rel="noopener noreferrer"&gt;How to send push notification using the OneSignal REST API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OneSignal &lt;a href="https://www.postman.com/onesignaldevs/workspace/efc5736d-2ddf-45fd-8a5b-cd2dffa137f7/overview" rel="noopener noreferrer"&gt;Postman Collection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/OneSignalDevelopers/OneSignal-Node-Sample" rel="noopener noreferrer"&gt;Tutorial Github Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OneSignal &amp;amp; Your Browser's Push API
&lt;/h2&gt;

&lt;p&gt;The Push API gives applications the ability to receive messages from a server whether or not the app is in the foreground or currently loaded on a user agent. This lets you deliver asynchronous notifications and updates to users who opt-in, resulting in better engagement with timely new content.&lt;/p&gt;

&lt;p&gt;This tutorial will cover an overview the usage of our API with the OneSignal NodeJS Client SDK.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Part 1: OneSignal REST API Overview&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Part 2: Push Notification In NodeJS&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires some basic knowledge of NodeJS and usage of REST APIs. I'm using the OneSignal Account along with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App with OneSignal integrated (mobile, web, or game)&lt;/li&gt;
&lt;li&gt;NPM (I’m using NPM version v6.14.11)&lt;/li&gt;
&lt;li&gt;NodeJS (I’m using NodeJS v16.14.2)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1: OneSignal REST API Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sending Notifications
&lt;/h3&gt;

&lt;p&gt;The OneSignal Push API allows you to programmatically send &lt;a href="https://documentation.onesignal.com/reference/create-notification" rel="noopener noreferrer"&gt;push notifications&lt;/a&gt;. The push notifications can be sent to different &lt;a href="https://documentation.onesignal.com/reference/create-notification#send-to-segments" rel="noopener noreferrer"&gt;segments&lt;/a&gt; (by default you send them to all subscribed users) and even specific devices using the User ID. Another cool feature of the OneSignal REST API is the ability to &lt;a href="https://documentation.onesignal.com/reference/cancel-notification" rel="noopener noreferrer"&gt;cancel notifications&lt;/a&gt; that have been scheduled.&lt;/p&gt;

&lt;h3&gt;
  
  
  View Notification
&lt;/h3&gt;

&lt;p&gt;One of my favorite endpoints to use with the OneSignal REST API is the &lt;a href="https://documentation.onesignal.com/reference/view-notification" rel="noopener noreferrer"&gt;view notification&lt;/a&gt; endpoint. This endpoint allows you to gather information about the notifications and outcomes associated with them. For example, the returned data can tell you see the number of notifications that have not been sent out, the number of notifications that got delivered, the number of confirmed deliveries, and much more information. If you want to learn more about all the &lt;a href="https://documentation.onesignal.com/reference/view-notification#returned-fields" rel="noopener noreferrer"&gt;data returned&lt;/a&gt; by this endpoint visit our rest API reference &lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our API can do way more than just send a notification and view data from that notification. If you want to learn more about our whole REST API, visit the &lt;a href="https://documentation.onesignal.com/docs/onesignal-api" rel="noopener noreferrer"&gt;OneSignal REST API overview&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;The cool thing about the NodeJS client library is that you don’t have to worry about the whole REST API setup in your NodeJS project, we handle all the boilerplate so you don’t have to worry about it ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your NodeJS App
&lt;/h3&gt;

&lt;p&gt;Inside of your terminal run the following commands to create a new NodeJS project using NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After entering the previous npm command, answer all the questions that will appear on your terminal. These questions will generate the values of your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your package.json file will look similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "myapp",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    “type”: “module”
    "scripts": {
        "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
    },
    "author": "",
    "license": "ISC"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you add the type property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Push Notifications In NodeJS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup your NodeJS App
&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is to create an index.js file. This file will contain all code necessary to send and view your notifications.&lt;/p&gt;

&lt;p&gt;At the top of this file, add the request npm package. This package will help us make API calls to the OneSignal endpoints in an easier way than doing it with NodeJS natively.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import * as OneSignal from '@onesignal/node-onesignal';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, run &lt;code&gt;npm install @onesignal/node-onesignal --save&lt;/code&gt; to add the &lt;code&gt;OneSignal NodeJS SDK Client&lt;/code&gt; NPM package to your project. After you have installed the OneSignal NPM package, add the following variable to your index.js after the OneSignal import.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const ONE_SIGNAL_APP_ID = 'ONESIGNAL_APP_ID';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;How to get the API KEY and the APP ID from OneSignal? Navigate to the OneSignal Dashboard, and navigate to the app you created inside of OneSignal. Once you have selected the app you want to work with during this how-to guide, the dashboard page will open up.&lt;/p&gt;

&lt;p&gt;Navigate to the settings page, by clicking the &lt;strong&gt;&lt;em&gt;S&lt;/em&gt;&lt;/strong&gt; _ &lt;strong&gt;ettings&lt;/strong&gt; _ tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F4qwqoZc8i-RKk4is2mKr8nrIKRsSV1PnboJhGxXKUlj5Tuok4IUELJ9CpHzeBrFr8oGHYrN8hdn2pHh_dgNwVeBIRzrMvWE0SImD2LThOOOPg3XTDlj62SUP_Jan72H6KzjEiZ2_u0GoQCugNA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F4qwqoZc8i-RKk4is2mKr8nrIKRsSV1PnboJhGxXKUlj5Tuok4IUELJ9CpHzeBrFr8oGHYrN8hdn2pHh_dgNwVeBIRzrMvWE0SImD2LThOOOPg3XTDlj62SUP_Jan72H6KzjEiZ2_u0GoQCugNA" alt="How to Send Push Notifications with the OneSignal NodeJS Client SDK" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside of settings, click on Keys &amp;amp; IDs. On this page, you will see your OneSignal App ID and your API key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FwuXFutPI4abItJPro3MH_QffVFrTHhjI6jAGgw4Y9k4E3Z6vQtZZmFpsfaNAQQfO6G_9gdIcER5VtT4Ws2DOt_VZMrDpV29-gChapuN86-QCwCkl6RVBKFWpVSVyQCFcoF8RtviR7fYVLZJOXg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FwuXFutPI4abItJPro3MH_QffVFrTHhjI6jAGgw4Y9k4E3Z6vQtZZmFpsfaNAQQfO6G_9gdIcER5VtT4Ws2DOt_VZMrDpV29-gChapuN86-QCwCkl6RVBKFWpVSVyQCFcoF8RtviR7fYVLZJOXg" alt="How to Send Push Notifications with the OneSignal NodeJS Client SDK" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you are in the &lt;strong&gt;Settings &amp;gt; Keys &amp;amp; IDs&lt;/strong&gt; tab, you can copy the &lt;strong&gt;OneSignal App ID&lt;/strong&gt; and the &lt;strong&gt;REST API KEY&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FzNzceoQexrEGcuVuy-3T-Gh1453rTekJokLTYb4lcLnx3xJ-uTsoy0cc-tqZdytC992-DZH9R9zaqrY1jVUkqOsXLB_bm9S5LSUiet7RkEmxfNsH9JCi7Agoj4ORGCKNb8Dkz1onMgiMGNpTqg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FzNzceoQexrEGcuVuy-3T-Gh1453rTekJokLTYb4lcLnx3xJ-uTsoy0cc-tqZdytC992-DZH9R9zaqrY1jVUkqOsXLB_bm9S5LSUiet7RkEmxfNsH9JCi7Agoj4ORGCKNb8Dkz1onMgiMGNpTqg" alt="How to Send Push Notifications with the OneSignal NodeJS Client SDK" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Another quick way to access the OneSignal App ID is by copying it from the URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F3PjhdZoDz9d-wt--4IdT8AG5oDY3soknq5LNrzCr5hqUTBAzrnqb3BwgQN5BdpknqDD-7VODior4T9uMoBE4VGO9zDQ26l4JpfKPDB6cgoDIX-28FYfBBrvrx12fRb05LhpO_LclHBcrc1Q-aA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F3PjhdZoDz9d-wt--4IdT8AG5oDY3soknq5LNrzCr5hqUTBAzrnqb3BwgQN5BdpknqDD-7VODior4T9uMoBE4VGO9zDQ26l4JpfKPDB6cgoDIX-28FYfBBrvrx12fRb05LhpO_LclHBcrc1Q-aA" alt="How to Send Push Notifications with the OneSignal NodeJS Client SDK" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep in mind that if you want to create an app using the OneSignal NodeJS Client, you will need the &lt;a href="https://documentation.onesignal.com/docs/accounts-and-keys#user-auth-key" rel="noopener noreferrer"&gt;User Authentication Key&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Builder
&lt;/h3&gt;

&lt;p&gt;To authentificate the app, you will need to use your OneSignal REST API key. Create a key provider object with the function &lt;code&gt;getToken()&lt;/code&gt; that returns your key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Returns:&lt;/strong&gt; Your key. In the background when you use this variable &lt;code&gt;app_key_provider.getToken()&lt;/code&gt; gets executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app_key_provider = {
    getToken() {
        return 'ONESIGNAL_REST_API_KEY';
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Client Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We can configure the client using the &lt;code&gt;createConfiguration()&lt;/code&gt; function. The configuration object can be used to set the &lt;code&gt;app_key_provider&lt;/code&gt; properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const configuration = OneSignal.createConfiguration({
    authMethods: {
        user_key: {
            tokenProvider: user_key_provider
        },
        app_key: {
            tokenProvider: app_key_provider
        }
    }
});
const client = new OneSignal.DefaultApi(configuration);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Create Notification&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a push notification and send it to the users of your app.&lt;/p&gt;

&lt;p&gt;To send a push notification, you will add the following function that will make a call to the OneSignal REST API. This function takes a body parameter that represents the information that the push notification will contain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const notification = new OneSignal.Notification();
notification.app_id = ONESIGNAL_APP_ID;
notification.included_segments = ['Subscribed Users'];
notification.contents = {
    en: "Hello OneSignal!"
};
const {id} = await client.createNotification(notification);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we use object destructuring to store the ID of the notification in a variable called ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  View a Notification
&lt;/h3&gt;

&lt;p&gt;After you have sent a notification, view the notification information and outcomes associated with it using the notification id.&lt;/p&gt;

&lt;p&gt;As you can see, I’m passing as the second parameter the &lt;code&gt;id&lt;/code&gt; variable that contains the notification id after I have created the notification using the &lt;code&gt;createNotification()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await client.getNotification(ONESIGNAL_APP_ID, id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run Your Code
&lt;/h3&gt;

&lt;p&gt;Thanks to our &lt;code&gt;package.json&lt;/code&gt;, you will be able to run your nodejs code by opening your terminal and typing &lt;code&gt;npm run start&lt;/code&gt;. After running this command you should see a notification appearing on your device if and only if you subscribed to notifications from your website, game, or app that you created and registered it in the OneSignal Dashboard.&lt;/p&gt;

&lt;p&gt;Feel free to test other &lt;a href="https://github.com/OneSignal/node-onesignal/blob/main/apis/DefaultApi.ts" rel="noopener noreferrer"&gt;methods of the NodeJS Client SDK&lt;/a&gt; and let us know what you think!&lt;/p&gt;

&lt;p&gt;Want to learn more about the OneSignal products and other technologies? Join our OneSignal Developers Community!&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the OneSignal Developers Community
&lt;/h2&gt;

&lt;p&gt;The OneSignal Developer community is a group of passionate individuals who work with OneSignal products. Community members have the opportunity to expand their network and knowledge across different technologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect on Twitter
&lt;/h3&gt;

&lt;p&gt;Follow our &lt;a href="https://twitter.com/OneSignalDevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt; to learn more about OneSignal, technical tips, and the latest events from OneSignal developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Join Our Discord Server
&lt;/h3&gt;

&lt;p&gt;The OneSignal Developer community gathers on our public chat server, available on Discord. &lt;a href="https://discord.gg/EP7gf6Uz7G" rel="noopener noreferrer"&gt;Our Discord server&lt;/a&gt; is a safe environment to network with other members, ask questions, and learn from each other. It is also a place to engage with the OneSignal product development team.&lt;/p&gt;

</description>
      <category>node</category>
      <category>backend</category>
      <category>webdev</category>
      <category>mobieldev</category>
    </item>
    <item>
      <title>GraphQL and Push Notifications with OneSignal and TakeShape</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Mon, 25 Apr 2022 16:05:38 +0000</pubDate>
      <link>https://dev.to/onesignal/graphql-and-push-notifications-with-onesignal-and-takeshape-5gcm</link>
      <guid>https://dev.to/onesignal/graphql-and-push-notifications-with-onesignal-and-takeshape-5gcm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fddynwxl6cqope6pqq84q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fddynwxl6cqope6pqq84q.jpg" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Jaden Baptista from TakeShape &amp;amp; Patricio Vargas from OneSignal&lt;/p&gt;

&lt;p&gt;We're excited to share a sample project we’ve been working on with TakeShape which leverages our push notification solution with TakeShape’s powerful API mesh. This article explains what we accomplished and the steps we took to get there. If you want to follow along, you can check out the &lt;a href="https://github.com/OneSignalDevelopers/TakeShape-OneSignal-Sample" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build an app that will look up a country based on its abbreviation and send the user a push notification&lt;/li&gt;
&lt;li&gt;Use OneSignal's SDK to do the subscription registration for push notifications&lt;/li&gt;
&lt;li&gt;Send the actual notification with OneSignal using an API call from TakeShape&lt;/li&gt;
&lt;li&gt;Use TakeShape to set up a pipeline for the data that can be triggered with a single GraphQL API call instead of multiple separate callsIt'll be our app → TakeShape API mesh → Countries API → TakeShape API mesh → OneSignal API → return to our app. All in one request.&lt;/li&gt;
&lt;li&gt;Turn this into a starter project to help people get going with TakeShape and OneSignal&lt;/li&gt;
&lt;li&gt;Try to make it look pretty so that people don't ridicule us for making something cool without it looking the part&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Our Process
&lt;/h2&gt;

&lt;p&gt;This tutorial will cover how to integrate OneSignal push notifications into your app using our typical setup process and how to send push notifications using the &lt;a href="https://documentation.onesignal.com/docs/onesignal-api" rel="noopener noreferrer"&gt;OneSignal REST API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Set Up Your OneSignal Account
&lt;/h2&gt;

&lt;p&gt;To begin, &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;login&lt;/a&gt; to your OneSignal account or &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt;. Then, click on the blue button entitled _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ to configure your OneSignal account to create your app or website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FD0FC-b_1EDhMBs9JrLBL1QJO5SJjSvM2UD0r2JfFSLjLWck9X0cktWSWdnJ8IxuxPnnaCf7T-ZamLjeKiZHZRtcypNBW8CwZKumxJWr5w36rkIQgt0SIZi50M_XitW7QXPoLBMNy" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FD0FC-b_1EDhMBs9JrLBL1QJO5SJjSvM2UD0r2JfFSLjLWck9X0cktWSWdnJ8IxuxPnnaCf7T-ZamLjeKiZHZRtcypNBW8CwZKumxJWr5w36rkIQgt0SIZi50M_XitW7QXPoLBMNy" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure the name of your app or website. Select _ &lt;strong&gt;Web Push&lt;/strong&gt; _ as your platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FCDE0825Y2OyB0xjT3lfaYMJu-ghINnNy6oGPFlpJ28XZOpGXkmZW8kC_nQh3LS2mJx-OA73qU-DLIql6lNOUvDQN9uxL5AHtAVrGS6s6hnEpDnK_3wXJSDro53Zk3RozU4gElqOC" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FCDE0825Y2OyB0xjT3lfaYMJu-ghINnNy6oGPFlpJ28XZOpGXkmZW8kC_nQh3LS2mJx-OA73qU-DLIql6lNOUvDQN9uxL5AHtAVrGS6s6hnEpDnK_3wXJSDro53Zk3RozU4gElqOC" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the blue button entitled, _ &lt;strong&gt;Next: Configure Your Platform&lt;/strong&gt; _.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Configuration
&lt;/h3&gt;

&lt;p&gt;Under Choose Integration, select the _ &lt;strong&gt;Typical Site&lt;/strong&gt; _ option.&lt;/p&gt;

&lt;p&gt;In the Site Setup section, enter your chosen web configuration. In my case, the configuration looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FHEJ2__W_cVECf9FYqnDcahUA2uRC-mCtvC6BOmybvjqZ2-uDsiYzTI4a4DAU4QQ8jG_CJ9JsUzNMgKieNOVYexuSCeW_sNV6gCx8x75gjJ7PEdoEFW_YD5QM7Ikllu5x9h6H4XJS" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FHEJ2__W_cVECf9FYqnDcahUA2uRC-mCtvC6BOmybvjqZ2-uDsiYzTI4a4DAU4QQ8jG_CJ9JsUzNMgKieNOVYexuSCeW_sNV6gCx8x75gjJ7PEdoEFW_YD5QM7Ikllu5x9h6H4XJS" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice for testing purposes we entered our localhost URL (&lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;). If you are doing the same, make sure you click on the _ &lt;strong&gt;LOCAL TESTING&lt;/strong&gt; _ option. This will ensure to treat HTTP localhost as HTTPS for testing.&lt;/p&gt;

&lt;p&gt;Under _ &lt;strong&gt;Permission Prompt Setup&lt;/strong&gt; _, you will see three vertical blue dots under the _ &lt;strong&gt;Actions&lt;/strong&gt; _ header on the far right side of the screen. Click on the blue dots and select _ &lt;strong&gt;Edit&lt;/strong&gt; _ from the drop-down menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2F6Q-7jclZMqvoD24KH57eVv4q8ukagEGnBDTS9uUavzcfOEdpkS37tzkRCOJfMxW8MvgPvcSCSAx8_YYuejpSuzTzGGF8F-5akheLvfUSqZgKtaeS0BRR9Xm8HootlJh4ZLQsxU3b" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2F6Q-7jclZMqvoD24KH57eVv4q8ukagEGnBDTS9uUavzcfOEdpkS37tzkRCOJfMxW8MvgPvcSCSAx8_YYuejpSuzTzGGF8F-5akheLvfUSqZgKtaeS0BRR9Xm8HootlJh4ZLQsxU3b" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A window will open with the configuration of our &lt;a href="https://documentation.onesignal.com/docs/slide-prompt" rel="noopener noreferrer"&gt;push notification Slide Prompt&lt;/a&gt;. Confirm that Auto-prompt is enabled (toggled to the right).&lt;/p&gt;

&lt;p&gt;Under _ &lt;strong&gt;Show When&lt;/strong&gt; _, you can choose how long your slide prompt will delay after a user visits your page. You can leave it as it is, or you can reduce the seconds so that your prompt appears sooner. Once you've chosen your delay time, click the grey _ &lt;strong&gt;Done&lt;/strong&gt; _ button located at the bottom right corner of the window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FcTuOP8OAeU1cLGPrriHQxlOT9KZyN2zLx9ykhPk4WE09GmMJdSaby3TrVonvECrXGr6My-b0bmO77MYt0aqy-VrVQQdnrcHysGTirzV2_1DC-I7Sqsj6xbENiiMwQpl9LkNl9anj" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FcTuOP8OAeU1cLGPrriHQxlOT9KZyN2zLx9ykhPk4WE09GmMJdSaby3TrVonvECrXGr6My-b0bmO77MYt0aqy-VrVQQdnrcHysGTirzV2_1DC-I7Sqsj6xbENiiMwQpl9LkNl9anj" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking _ &lt;strong&gt;Done&lt;/strong&gt; _, scroll down to the bottom of the page and click Save to save your auto-prompt configurations.&lt;/p&gt;

&lt;p&gt;You will be redirected to a different page with an important step: Downloading the SDK files. Click _ &lt;strong&gt;DOWNLOAD ONESIGNAL SDK FILES&lt;/strong&gt; _ and save them on your computer to retrieve later. We'll show you where to put them in a bit after we set up our site's directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Frjy18yLZ02IzXIQf_wr510klgSn3_E6CeeLoDGCxFKGm5JOmXzgCsEdeRdp4zV2oqubj6fOXCiZGXOo5eVLuckXYSjvlRwQ7BOV7fAr5S-lqsE26dYrLjC1W7BcX-C9_tyLrh4pl" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Frjy18yLZ02IzXIQf_wr510klgSn3_E6CeeLoDGCxFKGm5JOmXzgCsEdeRdp4zV2oqubj6fOXCiZGXOo5eVLuckXYSjvlRwQ7BOV7fAr5S-lqsE26dYrLjC1W7BcX-C9_tyLrh4pl" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the section entitled _ &lt;strong&gt;Add Code to Site&lt;/strong&gt; _, you will see a grey button that allows you to copy the code snippet. Click the grey _ &lt;strong&gt;COPY CODE&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FPJf3soh268xIaTuLz8RYn3jkLqzUJxeFsG6Hf4Fvx_5EgBqSYmX5xNCL8CFKtX5k300UjYA6cJ3YRiIGeK6t9Bx6Aqfa24dF7JJ6TugaAHn2wwAgfuzUvrKoa-P4efY8y8-sZ76F" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FPJf3soh268xIaTuLz8RYn3jkLqzUJxeFsG6Hf4Fvx_5EgBqSYmX5xNCL8CFKtX5k300UjYA6cJ3YRiIGeK6t9Bx6Aqfa24dF7JJ6TugaAHn2wwAgfuzUvrKoa-P4efY8y8-sZ76F" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Create a New TakeShape Project
&lt;/h2&gt;

&lt;p&gt;To set up that pipeline we mentioned earlier, we needed to find the right API. For this project, we were thinking of using something more fun and quirky like the PokeAPI, but we ended up settling on something a little more useful (well, I suppose that depends on how you spend your free time) with the &lt;a href="https://github.com/trevorblades/countries" rel="noopener noreferrer"&gt;CountriesAPI&lt;/a&gt; designed by &lt;a href="https://trevorblades.com/" rel="noopener noreferrer"&gt;Trevor Blades&lt;/a&gt; at Apollo. We’ve outlined our steps below so you can follow along.&lt;/p&gt;

&lt;p&gt;To get started, go to &lt;a href="http://takeshape.io/" rel="noopener noreferrer"&gt;takeshape.io&lt;/a&gt; and started a new project like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F9vgn-5frm93NGXhQ6XU4RlpPyGx2wxrHy9q5DCGrIXNj03AyLU_9GHaypFHwnd95ySI0d6LO_qp6w_JQJurO7SDCKAYQNVsoaYAoSo36ijbshfjhyW9nvJozO_8forE5ihopqGuS" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F9vgn-5frm93NGXhQ6XU4RlpPyGx2wxrHy9q5DCGrIXNj03AyLU_9GHaypFHwnd95ySI0d6LO_qp6w_JQJurO7SDCKAYQNVsoaYAoSo36ijbshfjhyW9nvJozO_8forE5ihopqGuS" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you’re making a new blank project instead of following a predefined pattern.&lt;/p&gt;

&lt;p&gt;Once that’s done, you can connect your two services. There's a shortcut _ &lt;strong&gt;Connect Service&lt;/strong&gt; _ button on the homepage of the project that will take you to a form that you must fill out once for OneSignal and once for the CountriesAPI. This is what the latter config looked like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FVLp7GNUJzgzyg5x30CzKBH5net7O6Ip_ItoEIR5m5Av14QH7gZodTBYXbD_d5L397BIq_7k_MVvwvKhjS7nEmwsUvFbKde5R1ea6O8jVyfQHU7P__1SO8PB0RWTOamQrSjU5mjYj" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FVLp7GNUJzgzyg5x30CzKBH5net7O6Ip_ItoEIR5m5Av14QH7gZodTBYXbD_d5L397BIq_7k_MVvwvKhjS7nEmwsUvFbKde5R1ea6O8jVyfQHU7P__1SO8PB0RWTOamQrSjU5mjYj" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s basically Plug’n’Play. The OneSignal's setup is just as easy because the API key is actually sent along with the JSON body — we'll get to that in a bit.&lt;/p&gt;

&lt;p&gt;Next, you’ll need to create the GraphQL mutation that will: 1) look up a country's data from the CountriesAPI and 2) ping OneSignal with the country’s data, plus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your API key.&lt;/li&gt;
&lt;li&gt;The hash that identifies which device to send the notification to.&lt;/li&gt;
&lt;li&gt;the country code to insert into the URL of the &lt;a href="https://www.countryflags.io/" rel="noopener noreferrer"&gt;CountryFlags&lt;/a&gt; API so that you can get automatically add an image to the push notification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Here's the text of the query in the schema's JSON file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
    Obviously JSON doesn't have comments, but I'm going to add a
    few JavaScript-style comments to explain what each line does
*/

"mutations": { // this is the mutations object in the root of our schema JSON file
    "sendPushNotification": { // the name of this mutation
      "description": "Sends a push notification to the given subscribed user with the given image and content.",
      "args": {
        "type": "object",
        "properties": { 
                    /*
                        these are the arguments coming into the mutation
                        usually you'd make a shape for it and just put "args": "NameOfInputShape"
                        here I've opted to list the arguments in the mutation
                        no reason other than that it feels right
                        we have two arguments defined below, both strings
                    */
          "user": {"type": "string"},
          "countryCode": {"type": "string"}
        },
        "required": ["user", "countryCode"] // both arguments are required
      },
      "shape": "OneSignalResult", 
            /* ^^^^^ is the shape of the result, 
            but we don't really care about our output from onesignal here */
      "resolver": { // aka how we fill in the output steps
        "compose": [ // we're going to do that by following this array of steps
          {
            "name": "graphql:query", // use graphql
            "service": "countries", // to send a ping to the countries service
            "options": {
              "fieldName": "country", // to get this type with the following query
              "selectionSet": "{ name native continent { name } capital currency }"
            },
                        // below, map the `countryCode` from our input to `code` so CountriesAPI will understand
            "argsMapping": {"code": [["get", {"path": "args.countryCode"}]]}
          },
          { // after finishing the request to CountriesAPI, start step 2 of the resolver
            "name": "rest:post", // it's a post request
            "service": "onesignal", // to the onesignal service
            "options": {"path": "notifications"}, // specifically to the /notifications endpoint
            "argsMapping": {
              "json.chrome_web_icon": [ // send an argument called "chrome_web_icon" to onesignal
                [
                  "expressionEval",
                  { // "chrome_web_icon" should be a URL to countryflags.io with the original country code in it
                    "expression": "'https://www.countryflags.io/' + args.countryCode + '/flat/64.png'"
                  }
                ]
              ],
              "json.app_id": [ // set our app_id to a constant (redacted here for obvious reasons)
                ["set", {"value": "MY-REDACTED-ONESIGNAL-APP-KEY"}]
              ],
                            // send our original input user id as the only element in an array called "include_player_ids"
              "json.include_player_ids[0]": [["get", {"path": "args.user"}]], 
              "json.contents.en": [ // send along an object called "contents" with a key "en"
                [
                  "expressionEval",
                  { // set the key "en" to this long message with data from the CountriesAPI
                    "expression": "steps[0].native + '(' + steps[0].name + ') is in ' + steps[0].continent.name + '. In the capital, ' + steps[0].capital + ', the people like to spend ' + steps[0].currency + '.'"
                  }
                ]
              ]
            }
          }
        ],
        "resultsMapping": {"id": [["get", {"path": "steps[1].id"}]]} // send the notification id to our output
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That JSON without all the comments is uploaded into TakeShape. We actually just did it through the editor in the project, but you can do it through the terminal as well if you prefer.&lt;/p&gt;

&lt;p&gt;To summarize, this process allows you to send this GraphQL query to the TakeShape API mesh endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
sendPushNotification (
user: "my-onesignal-user-id-from-the-sdk",
countryCode: "US"
) {
id
}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, TakeShape will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the Countries API and get some data about the country we've been given using its abbreviation.&lt;/li&gt;
&lt;li&gt;Turn that data into a message and send it along with an image of the country's flag and the device's ID to OneSignal.&lt;/li&gt;
&lt;li&gt;Return the ID that OneSignal returns.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although that may seem tough at first, it is actually fairly intuitive. All you have left to do is to make the GraphQL call in JavaScript!&lt;/p&gt;

&lt;p&gt;Another feature we wanted to implement was to add a &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; file on the page with a list of all the country codes, because who really remembers the abbreviation of the country they're looking up? Before we get to that, we first finished setting up the OneSignal SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Set Up the OneSignal SDK in Your App
&lt;/h2&gt;

&lt;p&gt;In your Web project folder, navigate to the &lt;code&gt;index.html&lt;/code&gt; file. Inside of the head HTML tag, paste the code you previously copied from the OneSignal page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
window.OneSignal = window.OneSignal || [];
OneSignal.push(function() {
OneSignal.init({
appId: "YOUR-APP-ID",
});
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, locate the SDK files you downloaded on your computer and insert them inside the root folder of your Web app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FELjFq3D6rZBZLdRJfetfnlyP28UZGXx5zQLPaEVo2t-JmRogiZ9TWRqlfVTu-7FEacjud3fpu3AdgksFsv3hZbUYXZSwSte-ZJ5z0XtbByrR6Gg5zy6BVsl6n9vbsxIipOsZSdGR" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FELjFq3D6rZBZLdRJfetfnlyP28UZGXx5zQLPaEVo2t-JmRogiZ9TWRqlfVTu-7FEacjud3fpu3AdgksFsv3hZbUYXZSwSte-ZJ5z0XtbByrR6Gg5zy6BVsl6n9vbsxIipOsZSdGR" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you have inserted the SDK files into your Web project, you'll need to add a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; to send the notification to yourself. Inside of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, add the following code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;button onclick="sendPush()" id="send-push"&amp;gt;SEND PUSH&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;br&gt;&lt;br&gt;
This button will now call a function called &lt;code&gt;sendPush()&lt;/code&gt; that we will create inside of the index.js file. Add the following code to the top of your file. This code contains the API key, the GraphQL endpoint from TakeShape, and the project ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const projectID = "YOUR-PROJECT-ID";
const apiKey = "YOUR_API_KEY";
const takeShapeURL = `https://api.takeshape.io/project/${projectID}/v3/graphql`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have added the code above, it's time for you to use it inside of our &lt;code&gt;sendPush()&lt;/code&gt; function. Create the &lt;code&gt;sendPush()&lt;/code&gt; function by adding the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sendPush = async () =&amp;gt; {
await fetch(
takeShapeURL,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
},
body: JSON.stringify({
query: `
mutation {
sendPushNotification (
user: "${await OneSignal.getUserId()}",
countryCode: "${select.value}"
) {
id
}
}
`
})
}
);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this code is making a POST call to the TakeShape GraphQL endpoint. The input to our POST request is the mutation containing the information needed to display our push notification. The countryCode property is the value from the &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;  dropdown. For testing purposes, the value of the user property is going to be your current userID that you get by calling the &lt;a href="https://documentation.onesignal.com/docs/web-push-sdk#user-ids" rel="noopener noreferrer"&gt;getUserId()&lt;/a&gt; method for the device you are using to view this web application. In other words, you will send a push notification to your device that has registered with OneSignal. Keep in mind that OneSignal allows sending mass push notifications to all the subscribed users of a website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow Web Push Notifications
&lt;/h3&gt;

&lt;p&gt;Run the app and visit your website. You should see the following prompt appear after your chosen time delay interval:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUnFCt6yS_cWIUhY3RYDCI1sk6WPKBZQ4EY_Iu1iLr243BJLIgvB6z0oAjQX1qr8jbLMlPjir8saxXiQFXUT3gdI40rF-BDV83AAIBx3VRku9qUM8mInmhzVbYbCdteSTfF2CTMyb" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUnFCt6yS_cWIUhY3RYDCI1sk6WPKBZQ4EY_Iu1iLr243BJLIgvB6z0oAjQX1qr8jbLMlPjir8saxXiQFXUT3gdI40rF-BDV83AAIBx3VRku9qUM8mInmhzVbYbCdteSTfF2CTMyb" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the blue Allow button to enable push notifications on your browser.&lt;/p&gt;

&lt;p&gt;If you want to get started by sending a message or two manually, check out &lt;a href="https://documentation.onesignal.com/docs/sending-notifications" rel="noopener noreferrer"&gt;this awesome docs page&lt;/a&gt; for help.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: Add Country Code Data to Your Application
&lt;/h1&gt;

&lt;p&gt;Now it's time to fill that &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; with actual data! If you go back into the homepage of your TakeShape project, right above the Connect Service button I clicked earlier, you should see OneSignal connected!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FTypLnxKB4pxlUNhcsM_1Zga6xrdo27Yur21jXhlhWlw8eIuhGKMz8Ocu6aUK1xuiYAQK9XsB9t9oSCrk72PcKeDsbohyMd3Sne-i3JlAMrv2y5RDOlpyZLZykrwEttY3Pf2EpAsD" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FTypLnxKB4pxlUNhcsM_1Zga6xrdo27Yur21jXhlhWlw8eIuhGKMz8Ocu6aUK1xuiYAQK9XsB9t9oSCrk72PcKeDsbohyMd3Sne-i3JlAMrv2y5RDOlpyZLZykrwEttY3Pf2EpAsD" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click on the _ &lt;strong&gt;Countries&lt;/strong&gt; _ service to get back to the form you originally filled out to add the service in the first place. At the very bottom of that form, there's a button that will let you select queries from the GraphQL service to duplicate inside TakeShape. In the GraphQL service, select the countries query. Doing this will make it so that the countries query from the CountriesAPI is now the &lt;code&gt;Countries_countries&lt;/code&gt; query in your API mesh, which you can then use to get a list of countries. That's a little confusing to explain in text, but it's actually the most intuitive way to go about this because this setup will let you choose what queries should be directly accessible through the API mesh. It also avoids creating any conflicts with query names when you start adding more services because they're all namespaced.&lt;/p&gt;

&lt;p&gt;With that out of the way, you can just add this to the JavaScript and load the dropdown with the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const loadCountries = async () =&amp;gt; {
const resp = await fetch(
`https://api.takeshape.io/project/${projectID}/v3/graphql`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`
},
body: JSON.stringify({
query: `
query {
Countries_countries {
code
}
}
`
})
}
);
const results = await resp.json();
results.data.Countries_countries.map(x =&amp;gt; x.code).forEach(code =&amp;gt; {
const option = document.createElement("option");
option.innerText = code;
select.insertAdjacentElement("beforeend", option);
});
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's pretty much it! You can take a look at the &lt;a href="https://github.com/OneSignalDevelopers/TakeShape-OneSignal-Sample" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; for the full code. You can also &lt;a href="https://takeshape-onesignal-country-lookup.vercel.app/" rel="noopener noreferrer"&gt;see the finished product&lt;/a&gt; in action.&lt;/p&gt;

&lt;p&gt;Let's test it out quick! If you go the page, it should ask you for permission to send push notifications. In the background, that &lt;code&gt;loadCountries&lt;/code&gt; function is running, which loads up the dropdown. If you choose one and press the _ &lt;strong&gt;Send Push&lt;/strong&gt; _ button like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FEyqEn3B5DYfIyB-zvTIkq9PV5ihKEdxkSXVg_40MWYwCuH4uwTU6BRlu6E3uCfgDa-YCvysmp5WK_yH-YAyKDmqIq3M-1Jniy9wmVpXHDKPCss04wwkqWi4EkFaA-NhiBgWEguRo" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FEyqEn3B5DYfIyB-zvTIkq9PV5ihKEdxkSXVg_40MWYwCuH4uwTU6BRlu6E3uCfgDa-YCvysmp5WK_yH-YAyKDmqIq3M-1Jniy9wmVpXHDKPCss04wwkqWi4EkFaA-NhiBgWEguRo" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then this happens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Ftnw2qdpvM16tO8rVPazYDsGVNVjwWQr5H4vlbftuW6O7zOYvuN-jg5WYVkq0xTAv2kDSkDGdikgxO05KzklDuXe5zimKWKVV-eUjuEM8_2lLCOvYLp4NEua9o9JlY_Z8itFWZ2wA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Ftnw2qdpvM16tO8rVPazYDsGVNVjwWQr5H4vlbftuW6O7zOYvuN-jg5WYVkq0xTAv2kDSkDGdikgxO05KzklDuXe5zimKWKVV-eUjuEM8_2lLCOvYLp4NEua9o9JlY_Z8itFWZ2wA" alt="GraphQL and Push Notifications with OneSignal and TakeShape" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;p&gt;Now, you can keep expanding your code to make use of different features of the OneSignal SDK across your web app. To learn more about the Web Push SDK, visit &lt;a href="https://documentation.onesignal.com/docs/web-push-sdk" rel="noopener noreferrer"&gt;OneSignal's documentation&lt;/a&gt;. If you want to check out more of TakeShape's abilities and how it makes working with APIs much easier in the long run, check out the &lt;a href="https://app.takeshape.io/docs/" rel="noopener noreferrer"&gt;TakeShape's documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>graphql</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Send Push Notifications with the OneSignal REST API</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Mon, 18 Apr 2022 13:00:00 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-send-push-notifications-with-the-onesignal-rest-api-16lf</link>
      <guid>https://dev.to/onesignal/how-to-send-push-notifications-with-the-onesignal-rest-api-16lf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F6la4zac9ucnf7zop431w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6la4zac9ucnf7zop431w.jpg" alt="How to Send Push Notifications with the OneSignal REST API" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s no secret that push notifications can help you engage and retain app users. In this tutorial, we'll show you how to use the &lt;a href="https://documentation.onesignal.com/reference/create-notification" rel="noopener noreferrer"&gt;OneSignal REST API&lt;/a&gt; using NodeJS.  &lt;/p&gt;

&lt;p&gt;Using the OneSignal REST API is very useful because it can help you integrate OneSignal into different workflows that your applications may have. The OneSignal REST API is friendly with different technologies including front and backend. Basically, if the tech stack you are using supers API calls, then you can use the OneSignal REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  OneSignal &amp;amp; Your Browser's Push API
&lt;/h3&gt;

&lt;p&gt;The Push API gives applications the ability to receive messages from a server whether or not the app is in the foreground or currently loaded on a user agent. This lets you deliver asynchronous notifications and updates to users who opt-in, resulting in better engagement with timely new content.&lt;/p&gt;

&lt;p&gt;This tutorial will cover an overview of our OneSignal REST API reference and the usage of our API with a NodeJS server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Part 1: OneSignal REST API Overview&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;REST API reference&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Part 2: Push Notification In NodeJS&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Setup a NodeJS Application&lt;/li&gt;
&lt;li&gt;Send Push Notifications&lt;/li&gt;
&lt;li&gt;View Notification insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires some basic knowledge of NodeJS and usage of REST APIs. Below is a list of platforms that I'm using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App with OneSignal integrated (mobile, web, or game)&lt;/li&gt;
&lt;li&gt;NPM&lt;/li&gt;
&lt;li&gt;I’m using NPM version v6.14.11&lt;/li&gt;
&lt;li&gt;NodeJS&lt;/li&gt;
&lt;li&gt;I’m using NodeJS v16.14.2&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: OneSignal REST API Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Send Notifications
&lt;/h3&gt;

&lt;p&gt;The OneSignal Push API allows you to programmatically send &lt;a href="https://documentation.onesignal.com/reference/create-notification" rel="noopener noreferrer"&gt;push notifications&lt;/a&gt;. The push notifications can be sent to different &lt;a href="https://documentation.onesignal.com/reference/create-notification#send-to-segments" rel="noopener noreferrer"&gt;segments&lt;/a&gt; (by default you send them to all &lt;em&gt;&lt;strong&gt;Subscribed Users)&lt;/strong&gt;&lt;/em&gt; and even specific devices using the User ID. Another cool feature of the OneSignal REST API is the ability to &lt;a href="https://documentation.onesignal.com/reference/cancel-notification" rel="noopener noreferrer"&gt;cancel&lt;/a&gt; notifications that have been scheduled.&lt;/p&gt;

&lt;h3&gt;
  
  
  View Notification
&lt;/h3&gt;

&lt;p&gt;One of my favorite endpoints to use with the OneSignal REST API is the &lt;a href="https://documentation.onesignal.com/reference/view-notification" rel="noopener noreferrer"&gt;view notification&lt;/a&gt; endpoint. This endpoint allows you to gather information about the notifications and outcomes associated with them. For example, the returned data can tell you see the number of notifications that have not been sent out, the number of notifications that got delivered, the number of confirmed deliveries, and much more information. If you want to learn more about all the &lt;a href="https://documentation.onesignal.com/reference/view-notification#returned-fields" rel="noopener noreferrer"&gt;data returned&lt;/a&gt; by this endpoint visit our rest API reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; POST&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;a href="https://onesignal.com/api/v1/notifications" rel="noopener noreferrer"&gt;&lt;code&gt;https://onesignal.com/api/v1/notifications&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our API can do a lot more than just send a notification and view data from that notification. If you want to learn more about our whole REST API, visit the &lt;a href="https://documentation.onesignal.com/docs/onesignal-api" rel="noopener noreferrer"&gt;OneSignal REST API overview&lt;/a&gt; page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your NodeJS App
&lt;/h3&gt;

&lt;p&gt;Inside your terminal run the following commands to create a new NodeJS project using NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After entering the previous npm command, answer all the questions that will appear on your terminal. These questions will generate the values of your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your package.json file will look like similar to this:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "myapp",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    “type”: “module”
    "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
    },
    "author": "",
    "license": "ISC"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Setup your NodeJS App&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The first thing you need to do is to create an &lt;code&gt;index.js&lt;/code&gt; file. This file will contain all code necessary to send and view your notifications.&lt;/p&gt;

&lt;p&gt;At the top of this file, add the request npm package. This package will help us make API calls to the OneSignal endpoints in an easier way than doing it with NodeJS natively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run &lt;code&gt;npm install axios&lt;/code&gt; to add the &lt;code&gt;axios&lt;/code&gt; npm package into your project. After you have installed the &lt;code&gt;axios&lt;/code&gt; NPM package, add the following three variables to your index.js after the &lt;code&gt;axios&lt;/code&gt; import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const API_KEY = "YOUR ONE SIGNAL API KEY";
const ONE_SIGNAL_APP_ID = "YOUR ONE SIGNAL APP ID";
const BASE_URL = "https://onesignal.com/api/v1";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the API KEY and the APP ID from OneSignal, navigate to the OneSignal Dashboard and click on the app you created inside of OneSignal. Once you have selected the app you want to work with, click the &lt;strong&gt;&lt;em&gt;S&lt;/em&gt;&lt;/strong&gt; _ &lt;strong&gt;ettings&lt;/strong&gt; _ tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FGmzXLp6PIMzhztSRsvfbm5vuDNzNOpc7NlRnMYtUMJ4frAvLNd_ZbY9NSdRj_rXFaFCI0Z5z1EOvi55Vd-CfoRaBi0jbA-8DSVQnBwnltWf_MsxpIovT48w3YmKdZNbdksnEJvxm" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FGmzXLp6PIMzhztSRsvfbm5vuDNzNOpc7NlRnMYtUMJ4frAvLNd_ZbY9NSdRj_rXFaFCI0Z5z1EOvi55Vd-CfoRaBi0jbA-8DSVQnBwnltWf_MsxpIovT48w3YmKdZNbdksnEJvxm" alt="How to Send Push Notifications with the OneSignal REST API" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this page, click on &lt;strong&gt;&lt;em&gt;Keys &amp;amp; IDs&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUP60T5nA4EqhL35YXMayKUZoA9gq_qvtldUhLMNyMwOiz3npa7hXaoHi0ogiY7-EXheBV3yvfZRckMRtnVeojsVN6eCsx7QmStexn2FNChAR66G3ZyaaiCrxXof1LWG9b3a2yEX1" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FUP60T5nA4EqhL35YXMayKUZoA9gq_qvtldUhLMNyMwOiz3npa7hXaoHi0ogiY7-EXheBV3yvfZRckMRtnVeojsVN6eCsx7QmStexn2FNChAR66G3ZyaaiCrxXof1LWG9b3a2yEX1" alt="How to Send Push Notifications with the OneSignal REST API" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;strong&gt;OneSignal App ID&lt;/strong&gt; and the &lt;strong&gt;REST API KEY&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FHYxlRKKp86qbNNhWML82Aw3ZgpuGRzTdrzcv1xHPjcghxVBt_U9OcXkRCMAECw9lGRGl-q3gsBMNu0I1NkRYIYC12AT7XSDKypK1nvNu3aYb0lLGgBqwx_MIE8PXPzofTZkY2inp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FHYxlRKKp86qbNNhWML82Aw3ZgpuGRzTdrzcv1xHPjcghxVBt_U9OcXkRCMAECw9lGRGl-q3gsBMNu0I1NkRYIYC12AT7XSDKypK1nvNu3aYb0lLGgBqwx_MIE8PXPzofTZkY2inp" alt="How to Send Push Notifications with the OneSignal REST API" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Another quick and easy way to access your OneSignal App ID is by copying it from the URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fia4xoDWkmAj1D3DrklCJzCwcS7x3sxIJlUXS7MsDsMNdkDZ2urwfjz7lCt7GB2933dFi2aTUFydoi6HcdB7VQCrPaR1cg0q79dA4-_Xxi9lC1zS9g6SeOTwbJjYF_jasznHu09SS" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fia4xoDWkmAj1D3DrklCJzCwcS7x3sxIJlUXS7MsDsMNdkDZ2urwfjz7lCt7GB2933dFi2aTUFydoi6HcdB7VQCrPaR1cg0q79dA4-_Xxi9lC1zS9g6SeOTwbJjYF_jasznHu09SS" alt="How to Send Push Notifications with the OneSignal REST API" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Options Builder
&lt;/h3&gt;

&lt;p&gt;This function is not mandatory in order to use the OneSignal REST API. This function will be in charge of creating the options that you will pass to your API calls. This is a generic function that will build the JSON object based on the parameters that you have passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {string} method&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {string} path&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {object} body&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Returns:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@returns {object} options
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const optionsBuilder = (method, path, body) =&amp;gt; {
    return {
        method,
        'url': `${BASE_URL}/${path}`,
        'headers': {
        'Content-Type': 'application/json',
        'Authorization': `Basic ${API_KEY}`,
        },
        body: body ? JSON.stringify(body) : null
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Notification
&lt;/h3&gt;

&lt;p&gt;Create a push notification and send it to the users of your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; POST&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;a href="https://onesignal.com/api/v1/notifications" rel="noopener noreferrer"&gt;&lt;code&gt;https://onesignal.com/api/v1/notifications&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Postman Collection
&lt;/h3&gt;

&lt;p&gt;To send a push notification, you will &lt;a href="https://www.postman.com/onesignaldevs/workspace/onesignal-api/request/16845437-c4f3498f-fd80-4304-a6c1-a3234b923f2c" rel="noopener noreferrer"&gt;add the following function that will make a call to the OneSignal REST API&lt;/a&gt;. This function takes a body parameter that represents the information that the push notification will contain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {object} body&lt;/li&gt;
&lt;li&gt;@returns {object} response
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const createNotication = async (data) =&amp;gt; {
const options = optionsBuilder("post","notifications", data);
try {
        const response = await axios(options);
        return response.data;
    } catch (error) {
        console.error(error);
        return error;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a sample body object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const body = {
    app_id: ONE_SIGNAL_APP_ID,
    included_segments: ['Subscribed Users'],
    data: {
        foo: 'bar',
    },
    contents: {
        en: 'Sample Push Message',
    },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View Notification
&lt;/h3&gt;

&lt;p&gt;Create a push notification and send it to the users of your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; GET&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;a href="https://onesignal.com/api/v1/notifications" rel="noopener noreferrer"&gt;&lt;code&gt;https://onesignal.com/api/v1/notifications&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Postman Collection
&lt;/h3&gt;

&lt;p&gt;To send a push notification, you will &lt;a href="https://www.postman.com/onesignaldevs/workspace/onesignal-api/request/16845437-c4f3498f-fd80-4304-a6c1-a3234b923f2c" rel="noopener noreferrer"&gt;add the following function that will make a call to the OneSignal REST API&lt;/a&gt;. This function takes a body parameter that represents the information that the push notification will contain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt; {string} notificationId
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const viewNotifcation = async (notificationId) =&amp;gt; {
    const path = `notifications/${notificationId}?  app_id=${ONE_SIGNAL_APP_ID}`;
        const options = optionsBuilder("get", path);
    try {
        const response = await axios(options);
        console.log(response.data);
    } catch (error) {
        console.log(error);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run Your Code
&lt;/h3&gt;

&lt;p&gt;At the end of the file, add the following lines of code. The first &lt;code&gt;createNotification()&lt;/code&gt; function will return the notification's basic information when you send push notifications. I’m using this function to call the OneSignal API. As you can see, I’m using object destructuring to grab the notification ID from the notification object returned from the &lt;code&gt;createNotification()&lt;/code&gt;, that will be used to call the &lt;code&gt;viewNotifcation()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {id} = await createNotication(body);
await viewNotifcation(id);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to test other &lt;a href="https://documentation.onesignal.com/reference/create-notification" rel="noopener noreferrer"&gt;OneSignal REST API&lt;/a&gt; endpoints and let us know what you think!&lt;/p&gt;

&lt;h3&gt;
  
  
  Join the OneSignal Developers Community
&lt;/h3&gt;

&lt;p&gt;Want to learn more about the OneSignal products and other technologies? Join our &lt;a href="https://onesignal.com/onesignal-developers" rel="noopener noreferrer"&gt;OneSignal Developers Community&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The OneSignal Developer community is a group of passionate individuals who work with OneSignal products. Community members have the opportunity to expand their network and knowledge across different technologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stay Connected
&lt;/h3&gt;

&lt;p&gt;Follow our &lt;a href="https://twitter.com/OneSignalDevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt; to learn more about the OneSignal product, technical tips, and the latest events from our developers.&lt;/p&gt;

&lt;p&gt;The OneSignal Developer community gathers on our public chat server, available on Discord. &lt;a href="https://discord.gg/EP7gf6Uz7G" rel="noopener noreferrer"&gt;Our Discord server&lt;/a&gt; is a safe environment to network with other members, ask questions, and learn from each other. It is also a place to engage with the OneSignal product development team.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>mobiledev</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Add Push Notifications into an iOS App</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Mon, 14 Mar 2022 18:36:55 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-add-push-notifications-into-an-ios-app-a3k</link>
      <guid>https://dev.to/onesignal/how-to-add-push-notifications-into-an-ios-app-a3k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fzrl5wl9yk2z8yr1g4gck.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzrl5wl9yk2z8yr1g4gck.jpg" alt="How to Add Push Notifications into an iOS App" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Push Notifications are a great tool to engage and retain your users. In this tutorial, we’ll show you how to add push notifications to your iOS app for free using OneSignal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Creating an Apple iOS Push Certificate&lt;/li&gt;
&lt;li&gt;Setting up Your OneSignal Account&lt;/li&gt;
&lt;li&gt;Setting up Push Notification in iOS&lt;/li&gt;
&lt;li&gt;Linking an External User ID to the OneSignal Player ID&lt;/li&gt;
&lt;li&gt;Allowing Notifications&lt;/li&gt;
&lt;li&gt;Sending Notificaitons&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First off, let’s create an Xcode project as a demo in order to use the SDK. This is going to be an UIKit app, but you can use SwiftUI as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fgaid5xchf2b9rqgtouqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fgaid5xchf2b9rqgtouqr.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Apple iOS Push Certificate
&lt;/h2&gt;

&lt;p&gt;Before sending push notifications, you'll need to generate an iOS Push Certificate. To do that, you'll need to ask Apple to give you a production certificate. Go to the &lt;a href="https://idmsa.apple.com/IDMSWebAuth/signin?appIdKey=891bd3417a7776362562d2197f89480a8547b108fd934911bcbea0110d07f757&amp;amp;path=%2Faccount%2F&amp;amp;rv=1" rel="noopener noreferrer"&gt;developer portal&lt;/a&gt;, click on &lt;strong&gt;&lt;em&gt;Certificates, IDs &amp;amp; Profiles&lt;/em&gt;&lt;/strong&gt; , and then click on &lt;strong&gt;&lt;em&gt;Identifiers&lt;/em&gt;&lt;/strong&gt;. Look for the app ID you just created in Xcode. If you can’t find it, click on the &lt;strong&gt;+&lt;/strong&gt; button in order to add it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkyvi59iog5dllny3w5a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkyvi59iog5dllny3w5a5.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Locate your app ID or add it by clicking the "+" button&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the _ &lt;strong&gt;Identifiers&lt;/strong&gt; _ and &lt;strong&gt;&lt;em&gt;Profiles&lt;/em&gt;&lt;/strong&gt; page, the &lt;em&gt;App IDs&lt;/em&gt; option should already be selected. Simply click on the _ &lt;strong&gt;Continue&lt;/strong&gt; _ button and you’ll be redirected to the type of app you want to create the ID for. Click on &lt;strong&gt;&lt;em&gt;Continue&lt;/em&gt;&lt;/strong&gt; once again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyyotzc8mb06534awptdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyyotzc8mb06534awptdi.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Check that "App IDs" is selected before pressing continue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now you’ll land on the App ID registration page where you’ll see two form fields for &lt;strong&gt;&lt;em&gt;Description&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Bundle ID&lt;/em&gt;&lt;/strong&gt;. Fill them with the correct information, being sure that the &lt;strong&gt;&lt;em&gt;Bundle ID&lt;/em&gt;&lt;/strong&gt; exactly matches the one you create previously in Xcode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Firid7jyuz5xbng5ku0co.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Firid7jyuz5xbng5ku0co.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Enter an app "Description" and "Bundle ID."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you click the _ &lt;strong&gt;Continue&lt;/strong&gt; _ button, you should see a review page. Click on _ &lt;strong&gt;Register&lt;/strong&gt; _ and voilà — you should now see your app in the _ &lt;strong&gt;Identifiers&lt;/strong&gt; _ list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F6fzzcms1jaivxscji1eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6fzzcms1jaivxscji1eg.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Click "Register" to register your app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyaj7gbi3hqpnxv54i6d6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyaj7gbi3hqpnxv54i6d6.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Your app is now viewable from the Identifiers menu.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll need to generate a certificate for OneSignal. To do so, open the &lt;strong&gt;&lt;em&gt;Keychain Access&lt;/em&gt;&lt;/strong&gt; app, select &lt;strong&gt;&lt;em&gt;Certificate Assistant&lt;/em&gt;&lt;/strong&gt; from the drop-down menu, and click on &lt;strong&gt;&lt;em&gt;Request a Certificate From a Certificate Authority&lt;/em&gt;&lt;/strong&gt;. This option just means that your machine is going to be the one with the private key for this particular certificate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fj2d1vfmnqkybt1f5kofz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fj2d1vfmnqkybt1f5kofz.png" alt="How to Add Push Notifications into an iOS App" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Select "Certificate Assistant" and "Request a Certificate From a Certificate Authority."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A window should appear asking you to provide certificate information. Enter your email address and check the _ &lt;strong&gt;Save to disk&lt;/strong&gt; _ option. You will also be prompted to choose where you want to save the certificate request. Make sure to save it somewhere safe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftilfwa6xpahsabqvjtch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftilfwa6xpahsabqvjtch.png" alt="How to Add Push Notifications into an iOS App" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you'll need to go back to Apple's developer portal and create a certificate. To do so, click on the &lt;strong&gt;&lt;em&gt;+&lt;/em&gt;&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fwdis90o1634hix6xhikt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwdis90o1634hix6xhikt.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll be redirected to the _ &lt;strong&gt;Certificates&lt;/strong&gt; _ creation page. Scroll down on this page until you see the Services header. Under this header, select the option entitled &lt;em&gt;&lt;strong&gt;Apple Push Notification service SSL (Sandbox &amp;amp; Production)&lt;/strong&gt;&lt;/em&gt; and then click the _ &lt;strong&gt;Continue&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fddsa7rdlfrg0jkull5ft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fddsa7rdlfrg0jkull5ft.png" alt="How to Add Push Notifications into an iOS App" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next page, it’ll ask you for the App ID that you want to create the certificate for. Select the one you created earlier from the drop-down menu and click the _ &lt;strong&gt;Continue&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fnwiw7w4u2nma2063w01s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnwiw7w4u2nma2063w01s.png" alt="How to Add Push Notifications into an iOS App" width="800" height="575"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Select your App ID to create a new Apple Push Notification certificate.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, you’ll be prompted to upload the Certificate Signing Request. Choose the file you saved previously and click _ &lt;strong&gt;Continue&lt;/strong&gt;._&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1vi17h622whz7og019ws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1vi17h622whz7og019ws.png" alt="How to Add Push Notifications into an iOS App" width="800" height="575"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Upload your Certificate Signing Request.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If everything works just fine, you should be redirected to the download page. Click on the _ &lt;strong&gt;Download&lt;/strong&gt; _ button to download it and double-click to open it in the &lt;strong&gt;&lt;em&gt;Keychain Access&lt;/em&gt;&lt;/strong&gt; app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzm2s7s07mhzur9rvt1jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzm2s7s07mhzur9rvt1jk.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Download your push notification certificate.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the _ &lt;strong&gt;Keychain Access&lt;/strong&gt; _ app, navigate to the _ &lt;strong&gt;My Certificates&lt;/strong&gt; _ tab and find the certificate you just create which has your app bundle ID in the name. Right-click on it to see the options, then click _ &lt;strong&gt;Export&lt;/strong&gt; _ from the menu that appears_._ It’ll prompt you to provide the location of the certificate. Select somewhere on your machine and type a password for the certificate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1tc797wcdarxj38k6s97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1tc797wcdarxj38k6s97.png" alt="How to Add Push Notifications into an iOS App" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up Your OneSignal Account
&lt;/h2&gt;

&lt;p&gt;In order to add push notifications to your iOS app, you'll need to have a OneSignal account. If you don't have a OneSignal account, you can easily &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; or simply &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;log in&lt;/a&gt; to an existing account to get started.&lt;/p&gt;
&lt;h3&gt;
  
  
  iOS Configuration
&lt;/h3&gt;

&lt;p&gt;In the OneSignal dashboard, click on the _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fnt1p9y1z4eaygx5cilno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnt1p9y1z4eaygx5cilno.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Configure a new app/website in OneSignal.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the next page, type the name of your app and select the &lt;em&gt;&lt;strong&gt;Apple iOS (APNs)&lt;/strong&gt;&lt;/em&gt; option for the platform and click on the _ &lt;strong&gt;Next: Configure Your Platform&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff44t2ga91ckakoy0yiof.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff44t2ga91ckakoy0yiof.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Select Apple iOS (APNs) as your chosen platform.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You’ll be prompted to upload the Apple certificate file you created in the first part of this tutorial. Locate the certificate on your machine, type in the password for the certificate, then click the _ &lt;strong&gt;Save &amp;amp; Continue&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fldscicx1zvvkf2qj8iqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fldscicx1zvvkf2qj8iqg.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Upload your Apple push notification certificate.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll be prompted to choose your target SDK. Select &lt;strong&gt;&lt;em&gt;Native iOS&lt;/em&gt;&lt;/strong&gt; as the target SDK and click on _ &lt;strong&gt;Save &amp;amp; Continue&lt;/strong&gt; _ button at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3hc3wx08hujcabdjh8f4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3hc3wx08hujcabdjh8f4.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Select Native iOS as your target SDK.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this final step, under 1. Install the SDK, you should see the App ID provided by OneSignal. Copy it somewhere where it's easy to retrieve — you’ll use it in the code later. Once you've saved the ID, you can click on _ &lt;strong&gt;Done&lt;/strong&gt; _.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkaed1vtwasqd2l9tpku4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkaed1vtwasqd2l9tpku4.png" alt="How to Add Push Notifications into an iOS App" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you’ve successfully configured your OneSignal project and you’re almost ready to send your first push notification 🥳 ! The last step is to go back to our iOS project and configure it so that it can receive notifications from OneSignal.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Push Notifications in iOS
&lt;/h2&gt;

&lt;p&gt;Go back to the iOS project you created earlier and select the main target. Under the &lt;strong&gt;&lt;em&gt;Signing &amp;amp; Capabilities&lt;/em&gt;&lt;/strong&gt; tab, click on the &lt;strong&gt;&lt;em&gt;+ Capability&lt;/em&gt;&lt;/strong&gt; button, then select &lt;strong&gt;&lt;em&gt;Push Notifications.&lt;/em&gt;&lt;/strong&gt; This will enable your app to receive push notifications from OneSignal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3234i7nylqrvphcl23p2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3234i7nylqrvphcl23p2.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll need to add a Notification Extension to the app. Go back to the &lt;strong&gt;&lt;em&gt;General&lt;/em&gt;&lt;/strong&gt; tab and click the plus icon at the bottom of the &lt;strong&gt;&lt;em&gt;Targets&lt;/em&gt;&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F9be9d851pn0yfgqrukqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9be9d851pn0yfgqrukqe.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll be prompted to select the template for your new target. Select _ &lt;strong&gt;Notification Service Extension&lt;/strong&gt; _ then click _ &lt;strong&gt;Next&lt;/strong&gt;._&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyss28g380cfx27iflu5v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyss28g380cfx27iflu5v.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next window, use _ &lt;strong&gt;OneSignalNotificationServiceExtension&lt;/strong&gt; _ as the name of the extension (as the docs suggest) and click the _ &lt;strong&gt;Finish&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5my3xersr49bmthwyaxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5my3xersr49bmthwyaxd.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A message will appear asking if you want to activate the scheme. You don’t want to activate the push notification scheme because you just want to run your application (not the notification), so click on the &lt;strong&gt;&lt;em&gt;Cancel&lt;/em&gt;&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbyzqpramdsst9auxt4aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbyzqpramdsst9auxt4aj.png" alt="How to Add Push Notifications into an iOS App" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The notification extension will come with a &lt;code&gt;NotificationService.swift&lt;/code&gt;&lt;em&gt;.&lt;/em&gt; Open it and replace the content with the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import OneSignal
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -&amp;gt; Void)?
    var receivedRequest: UNNotificationRequest!
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -&amp;gt; Void) {
        self.receivedRequest = request
        self.contentHandler = contentHandler
        self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {   
            OneSignal.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            OneSignal.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you build the project, you’ll get a compilation error since the project doesn’t yet know the OneSignal module. To fix that error, you'll need to install the module via Swift Package Manager.&lt;/p&gt;

&lt;p&gt;In Xcode, go to _ &lt;strong&gt;File&lt;/strong&gt; _ &amp;gt; _ &lt;strong&gt;Add Packages&lt;/strong&gt; _ and enter the package URL  &lt;a href="https://github.com/OneSignal/OneSignal-XCFramework" rel="noopener noreferrer"&gt;https://github.com/OneSignal/OneSignal-XCFramework&lt;/a&gt; and click on &lt;strong&gt;&lt;em&gt;Add Package&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyes9uloeecsd6q0z1gx7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyes9uloeecsd6q0z1gx7.png" alt="How to Add Push Notifications into an iOS App" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Add the OneSignal XCFramework in Xcode.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will add the OneSignal library to the main target. You also need to add the OneSignal library to the extension target. Select the &lt;code&gt;OneSignalNotificationServiceExtension&lt;/code&gt; target. Under the &lt;strong&gt;&lt;em&gt;Frameworks and Libraries&lt;/em&gt;&lt;/strong&gt; section, click on the _ &lt;strong&gt;+&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxzj69ldqt3pixsa9kjlt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxzj69ldqt3pixsa9kjlt.png" alt="How to Add Push Notifications into an iOS App" width="800" height="580"&gt;&lt;/a&gt;&lt;br&gt;
_Add the OneSignal library to the extension target in Xcode. _&lt;/p&gt;

&lt;p&gt;After clicking on the + button, a menu should appear. The OneSignal library should be one of the choices in this list. Select &lt;strong&gt;&lt;em&gt;OneSignal&lt;/em&gt;&lt;/strong&gt; and click _ &lt;strong&gt;Add&lt;/strong&gt;._&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fytcb31xblk1dvh7phxxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fytcb31xblk1dvh7phxxs.png" alt="How to Add Push Notifications into an iOS App" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you build and run, the error should have disappeared.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Feamf0eitftwfu2y9b0l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Feamf0eitftwfu2y9b0l1.png" alt="How to Add Push Notifications into an iOS App" width="800" height="584"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Build Succeeded message in Xcode.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's one last step you must complete to finish the setup process: configuring the SDK inside your &lt;code&gt;AppDelegate&lt;/code&gt;. To do so, open your &lt;code&gt;AppDelegate&lt;/code&gt;, import the OneSignal library, and paste the following initialization code to &lt;code&gt;didFinishLaunchingWithOptions&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {

    OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)

    OneSignal.initWithLaunchOptions(launchOptions)
    OneSignal.setAppId("YOUR_ONESIGNAL_APP_ID")

    OneSignal.promptForPushNotifications(userResponse: { accepted in
      print("User accepted notifications: \(accepted)")
    })

    return true
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code snippet, you'll need to provide the App ID OneSignal generated for you earlier. You can find this information in your project’s dashboard under the _ &lt;strong&gt;Keys &amp;amp; IDs&lt;/strong&gt; _ menu. Because this is sensitive data, make sure to obscure it in some way so that it isn’t visible directly in the source code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking an External User ID to the OneSignal Player ID
&lt;/h2&gt;

&lt;p&gt;OneSignal creates and stores device and channel level data under a unique OneSignal ID called the &lt;code&gt;player_id&lt;/code&gt;. A single user can have multiple &lt;code&gt;player_id&lt;/code&gt; records based on how many devices, email addresses, and phone numbers they use to interact with your app or website.&lt;/p&gt;

&lt;p&gt;Create a method that generates a random string as your external user ID and register it to OneSignal. Your final &lt;code&gt;AppDelegate&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
    initializeOneSignal()
    setupExternalId()

    return true
  }

  private func initializeOneSignal() {
    OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)

    OneSignal.initWithLaunchOptions(launchOptions)
    OneSignal.setAppId("YOUR_ONESIGNAL_APP_ID")

    OneSignal.promptForPushNotifications(userResponse: { accepted in
      print("User accepted notifications: \(accepted)")
    })
  }

  private func setupExternalId() {
    let externalUserId = randomString(of: 10)

    OneSignal.setExternalUserId(externalUserId, withSuccess: { results in
      print("External user id update complete with results: ", results!.description)
      if let pushResults = results!["push"] {
        print("Set external user id push status: ", pushResults)
      }
      if let emailResults = results!["email"] {
        print("Set external user id email status: ", emailResults)
      }
      if let smsResults = results!["sms"] {
        print("Set external user id sms status: ", smsResults)
      }
    }, withFailure: {error in
      print("Set external user id done with error: " + error.debugDescription)
    })
  }


  private func randomString(of length: Int) -&amp;gt; String {
    let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    var s = ""
    for _ in 0 ..&amp;lt; length {
      s.append(letters.randomElement()!)
    }
    return s
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Allowing Notifications
&lt;/h2&gt;

&lt;p&gt;The moment of truth has arrived — it's time to put your setup work to the test by sending a notification. To begin, launch your app directly on your iOS device. You should see the following prompt appear asking if you would like to receive notifications from your app. Click on the blue &lt;strong&gt;&lt;em&gt;Allow&lt;/em&gt;&lt;/strong&gt; button to enable push notifications on your device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2rk81he89kc1f0i0vsts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2rk81he89kc1f0i0vsts.png" alt="How to Add Push Notifications into an iOS App" width="747" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Notifications
&lt;/h2&gt;

&lt;p&gt;It’s now time to send your first push notification! To do so, login to your OneSignal account and navigate to the _ &lt;strong&gt;Dashboard&lt;/strong&gt; _ tab. On the Dashboard page, click on the blue button at the top right corner entitled +_ &lt;strong&gt;New Push&lt;/strong&gt; _.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fgc91o8wfy1554m0nobd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fgc91o8wfy1554m0nobd1.png" alt="How to Add Push Notifications into an iOS App" width="800" height="639"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Click the "+New Push" button to create a new notification.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to a new window that will allow you to create and customize your push notification.&lt;/p&gt;

&lt;p&gt;Under the section entitled _ &lt;strong&gt;Audience&lt;/strong&gt; _, make sure that _ &lt;strong&gt;Send to Subscribed Users&lt;/strong&gt; _ is selected. Then, create your message by adding your message title, content, and image. Because this is the first notification your subscribers will receive, you may choose to craft a simple welcome message to confirm that they've been subscribed and reinforce the value that notifications will provide.&lt;/p&gt;

&lt;p&gt;Under the _ &lt;strong&gt;Delivery Schedule&lt;/strong&gt; _ section, select _ &lt;strong&gt;Immediately&lt;/strong&gt; _ and _ &lt;strong&gt;Send to everyone at the same time&lt;/strong&gt; _ to send to all your current push subscribers. If you have just finished setting up your OneSignal account, chances are you're the first and only subscriber. If your app is heavily trafficked and other users have already opted in to receive push notifications, you may want to select &lt;em&gt;&lt;strong&gt;Send to a particular segment(s)&lt;/strong&gt;&lt;/em&gt; to test your message out on a select audience. When you're ready to send your message, click on the blue _ &lt;strong&gt;Review and Send&lt;/strong&gt; _ button at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftraks5y43kufxi2cgl6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftraks5y43kufxi2cgl6a.png" alt="How to Add Push Notifications into an iOS App" width="800" height="1142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small popup will appear prompting you to review your message. Once you are satisfied, click on the blue _ &lt;strong&gt;Send Message&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffv5wy138rblkvoqcewjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffv5wy138rblkvoqcewjr.png" alt="How to Add Push Notifications into an iOS App" width="800" height="1142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should receive a push notification on your iOS device! 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv0f8zpk58jvnui0spt5n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv0f8zpk58jvnui0spt5n.png" alt="How to Add Push Notifications into an iOS App" width="750" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Get Support &amp;amp; Share Your Feedback&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To learn more about our iOS mobile push SDK, please visit our iOS push &lt;a href="https://documentation.onesignal.com/docs/ios-sdk-setup" rel="noopener noreferrer"&gt;iOS Mobile Push SDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'd love to know what you think and answer any additional questions you have. Ping us on the &lt;a href="https://discord.com/invite/EP7gf6Uz7G" rel="noopener noreferrer"&gt;OneSignalDevs Discord server&lt;/a&gt; to share your experience.  We appreciate any insight you can share to help us better serve you!&lt;/p&gt;

&lt;p&gt;To stay in the loop with the latest product updates and innovations, follow the &lt;a href="https://twitter.com/onesignaldevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt;. For additional support and dev inspiration, tap into our global developer community.&lt;/p&gt;

&lt;p&gt;This post was guest authored by &lt;strong&gt;Ibrahima Ciss&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>mobiledev</category>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>How To Add Android Push Notifications to a React Native Expo App</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Wed, 22 Dec 2021 21:32:10 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-add-android-push-notifications-to-a-react-native-expo-app-4o1k</link>
      <guid>https://dev.to/onesignal/how-to-add-android-push-notifications-to-a-react-native-expo-app-4o1k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fedeymysn5wx54iyrzxqr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fedeymysn5wx54iyrzxqr.jpg" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s no secret that push notifications can help you engage and retain app users. In this tutorial, we'll show you how to integrate with the React-OneSignal NPM package to leverage push notifications in your React app for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;OneSignal &amp;amp; Your Browser's Push API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A mobile push API gives mobile applications the ability to receive messages from a server whether or not the app is in the foreground. This lets you deliver asynchronous notifications and updates to users who opt-in, resulting in better engagement with timely new content.&lt;/p&gt;

&lt;p&gt;This tutorial will cover how to integrate the new &lt;a href="https://github.com/OneSignal/onesignal-expo-plugin" rel="noopener noreferrer"&gt;React Native Expo OneSignal Plugin&lt;/a&gt; to add mobile push notifications into your application using our typical setup process. Part one of this guide covers the OneSignal setup process. Part two of this guide covers how to integrate OneSignal with React using our npm package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Part 1: Set Up Your OneSignal Account&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Google Android FCM Configuration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Part 2: Set Up Push Notifications in React Native Expo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create Your React Native App&lt;/li&gt;
&lt;li&gt;Install the OneSignal Expo Plugin&lt;/li&gt;
&lt;li&gt;Configure the Plugin&lt;/li&gt;
&lt;li&gt;Run and Build Your Application&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send Push Notifications to Android Devices&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Connect With Our Developer Community&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires some basic knowledge of React Native (Expo). I'm using the &lt;a href="https://docs.expo.dev/get-started/installation/#installing-expo-cli" rel="noopener noreferrer"&gt;Expo CLI&lt;/a&gt; to generate my project and &lt;strong&gt;NodeJS version 14.16&lt;/strong&gt;. &lt;strong&gt;Additional React&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Setup Resources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/OneSignalDevelopers/OneSignal-React-NPM-Sample" rel="noopener noreferrer"&gt;React Native (Expo) plugin Sample Ap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Part 1: Set Up Your OneSignal Account&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To begin, &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;log in&lt;/a&gt; to your OneSignal account or &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt;. Then, click on the blue button entitled _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ to configure your OneSignal account to fit your app or website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F30rSEw3USzJOb2Xt7gr_AH9M7dWQQBYBWOOfCwT4oVNJAowzpvDhbeKThTIpSp-zrzjUd7lFxotlCujJ4MFKBZeULraqvVF9Wg4_5Mr-EW6FgpUoTl8nLgw619zbROKes39Pa2DH" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2F30rSEw3USzJOb2Xt7gr_AH9M7dWQQBYBWOOfCwT4oVNJAowzpvDhbeKThTIpSp-zrzjUd7lFxotlCujJ4MFKBZeULraqvVF9Wg4_5Mr-EW6FgpUoTl8nLgw619zbROKes39Pa2DH" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Insert the name of your app or website. Select _ &lt;strong&gt;Google Android&lt;/strong&gt; _ as your platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fc7nrKHFzPjeo7bJkfz4N2z8wH7XaatQdV-RHbSq9u46HvvDrSsKnAJYghrvgkziCMVY_HFre5rXVjCyRkhmNGnRTi1FpzXG-bzF2w9tJzdFWwAupgbTFPxhAIToS4FRlAM66TG2y" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fc7nrKHFzPjeo7bJkfz4N2z8wH7XaatQdV-RHbSq9u46HvvDrSsKnAJYghrvgkziCMVY_HFre5rXVjCyRkhmNGnRTi1FpzXG-bzF2w9tJzdFWwAupgbTFPxhAIToS4FRlAM66TG2y" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the blue button entitled, _ &lt;strong&gt;Next: Configure Your Platform&lt;/strong&gt; _.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Google Android FCM Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It’s time to configure your Android app using a Firebase Server key. All Android apps require this key and the server ID in order to send push notifications. If you don’t have the Firebase Server API Keys, take a look at our documentation to learn &lt;a href="https://documentation.onesignal.com/docs/generate-a-google-server-api-key" rel="noopener noreferrer"&gt;how to generate a Firebase server API key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FTHZKoWNEWC9QlbD-Ghnhf7yvk-9c8bVqVgyaHDp9z2ZE_ddBjo9Nng0DSEqxK7Qy85AJvr7THK_8ebhXvSUQKnlaDd9VhgsGy9t1BPtck662YZmXaik01IovQfoSOKl3T74_JAHs" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FTHZKoWNEWC9QlbD-Ghnhf7yvk-9c8bVqVgyaHDp9z2ZE_ddBjo9Nng0DSEqxK7Qy85AJvr7THK_8ebhXvSUQKnlaDd9VhgsGy9t1BPtck662YZmXaik01IovQfoSOKl3T74_JAHs" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now select your target SDK. We'll take you through the steps to get your first user and send your first test notification later in this guide.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FfJ6kweiFQFLPI2w1t1YzmwlWIChFgxCIIde7nVRzhEWdNEgZ2c5ItuktUaEiqI4HS7Px8fJMMPOOVWdTEn9_ihUS_yLcqML42WKRVy8Wm25O-74-N85vl4ba-f6hRppmpAm02osX" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FfJ6kweiFQFLPI2w1t1YzmwlWIChFgxCIIde7nVRzhEWdNEgZ2c5ItuktUaEiqI4HS7Px8fJMMPOOVWdTEn9_ihUS_yLcqML42WKRVy8Wm25O-74-N85vl4ba-f6hRppmpAm02osX" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next screen that appears, you will see your App ID — copy that App ID because you will use it inside of your Expo Application. &lt;strong&gt;DO NOT click&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;Check Subscribed Users&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;Done&lt;/em&gt;&lt;/strong&gt; yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2Fb7naSr2_MDfnGERBjK0zuu9-CScalOsxkSSKe32bwLvaVk4foIaalrCNWu0M-6AR2QmblGworiUnw2M9Qbjs2kMXm1cexTAoKJxC0Zh1dSmBjp0QiXf3Im93YJOY98POngnBRWXJ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2Fb7naSr2_MDfnGERBjK0zuu9-CScalOsxkSSKe32bwLvaVk4foIaalrCNWu0M-6AR2QmblGworiUnw2M9Qbjs2kMXm1cexTAoKJxC0Zh1dSmBjp0QiXf3Im93YJOY98POngnBRWXJ" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Set Up Push Notification in React Native Expo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Your React Native App
&lt;/h3&gt;

&lt;p&gt;Inside of your terminal run the following commands to create a new React project using &lt;strong&gt;&lt;em&gt;Create&lt;/em&gt;&lt;/strong&gt;.   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expo App:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo init onesignal-rn-expo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When asked, select any of the options under the &lt;strong&gt;&lt;em&gt;Managed Workflow&lt;/em&gt;&lt;/strong&gt;. In my case, I selected the first option, which is blank &lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FiZTo7mTkCNBrnmTD8cBAAH1DGIJvGzX5ct9VMmCULaG7EheSEZdJvdtOooJCrEc1CMEUmOcOe2ncUTa695Py49orFLqD9GAEiObBg7EMMDnkIh9OPtVdd3Ef83E1-Awe96oYKL-y" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FiZTo7mTkCNBrnmTD8cBAAH1DGIJvGzX5ct9VMmCULaG7EheSEZdJvdtOooJCrEc1CMEUmOcOe2ncUTa695Py49orFLqD9GAEiObBg7EMMDnkIh9OPtVdd3Ef83E1-Awe96oYKL-y" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd onesignal-rn-expo
expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For additional guidance, check out Expo's official documentation on &lt;a href="https://docs.expo.dev/get-started/create-a-new-app/" rel="noopener noreferrer"&gt;how to create a new Expo App&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the OneSignal Expo Plugin
&lt;/h3&gt;

&lt;p&gt;Inside of your project folder, open your terminal and run the following command to install the &lt;a href="https://github.com/OneSignal/onesignal-expo-plugin" rel="noopener noreferrer"&gt;OneSignal Expo Plugin&lt;/a&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo install onesignal-expo-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the signal-expo-plugin, install now the react-native-onesignal plugin by running 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;yarn add react-native-onesignal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though &lt;code&gt;onesignal-expo-plugin&lt;/code&gt; defines &lt;code&gt;react-native-onesignal&lt;/code&gt; as a dependency and it gets put into the &lt;code&gt;node_module&lt;/code&gt; it will make sure the native parts get built.&lt;/p&gt;

&lt;p&gt;If you forgot to run the following command after you have built your project, you can fix this by running expo prebuild — clean. This should delete android and ios and do a clean native build, then run the yarn add &lt;code&gt;react-native-onesignal&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the Plugin
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;app.json/app.config.js&lt;/code&gt; file, add the plugin to the &lt;a href="https://docs.expo.dev/versions/latest/config/app/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;plugin array&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "plugins": [
        [
            "onesignal-expo-plugin",
            {
                "mode": "development",
                "devTeam": "91SW8A37CR"
            }
        ]
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App.config.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
...
    plugins: [
        [
            "onesignal-expo-plugin",
            {
                mode: process.env.NODE_ENV || "development",
                devTeam: "91SW8A37CR"
            }
        ]
    ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Plugin Options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mode&lt;/code&gt;: used to configure &lt;a href="https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment" rel="noopener noreferrer"&gt;APNs environment&lt;/a&gt; entitlement.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"development"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"production"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;devTeam&lt;/code&gt;: *optional* — used to configure Apple Team ID. You can find your Apple Team ID by running &lt;code&gt;expo credentials:manager&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "extra": {
        "oneSignalAppId": "&amp;lt;YOUR APP ID HERE&amp;gt;"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then access the value to pass to the &lt;code&gt;setAppId&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import OneSignal from 'react-native-onesignal';
import Constants from "expo-constants";
OneSignal.setAppId(Constants.manifest.extra.oneSignalAppId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, pass the OneSignal App ID directly to the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OneSignal.setAppId("YOUR-ONESIGNAL-APP-ID");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run and Build your Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo prebuild
# Build your native iOS project
$ expo run:ios
# Build your native Android project
expo run:android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send Push Notifications to Android Devices
&lt;/h2&gt;

&lt;p&gt;I recommend you run the application on an actual Android device to test the notifications. To do so, you will need to connect your Android device and enable &lt;a href="https://developer.android.com/studio/debug/dev-options" rel="noopener noreferrer"&gt;developer mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have connected to the device and enabled developer mode, run the application on your device by selecting your device as the target device. In my example, I’m running the app on a &lt;strong&gt;Google Pixel 5&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FBTnNNWuxdRVv8fQYvuwVA7psLZRYGtX-M5QcV9yQui37dEnNQXJy36rn9jx6mJKI9SF6n5uZnUP4Z3-WxdKxdvqWvNNc_ne4ue3Yv_3qWzyGr7j5uWTDXZ0NNmucEy2W8KBdfjef" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FBTnNNWuxdRVv8fQYvuwVA7psLZRYGtX-M5QcV9yQui37dEnNQXJy36rn9jx6mJKI9SF6n5uZnUP4Z3-WxdKxdvqWvNNc_ne4ue3Yv_3qWzyGr7j5uWTDXZ0NNmucEy2W8KBdfjef" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have opened the application on your device, the device will be automatically subscribed to the notification. Now, your device will be able to receive notifications sent by OneSignal.  &lt;/p&gt;

&lt;p&gt;To complete the setup process, return to your OneSignal dashboard to the point at which you previously left off. Click on the _ &lt;strong&gt;Check Subscribed Users&lt;/strong&gt; _ and a green message will appear like the one in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FxlDL-bdjyC5zGltl2QJM1GRaTrCqKsOynV0P-3hsnOy3AqrRewBs8QzD9w1gvPu-0oQDoTp98uNvEBn2sk91-WtpIdsff3S0wlpjDH0q69fyjX2USfHYKtWm8yX4VU-8XOnToJJL" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FxlDL-bdjyC5zGltl2QJM1GRaTrCqKsOynV0P-3hsnOy3AqrRewBs8QzD9w1gvPu-0oQDoTp98uNvEBn2sk91-WtpIdsff3S0wlpjDH0q69fyjX2USfHYKtWm8yX4VU-8XOnToJJL" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the _ &lt;strong&gt;Done&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send Your First Notification
&lt;/h3&gt;

&lt;p&gt;It’s time to send your first push notification! To do so, log in to your OneSignal account and navigate to the _ &lt;strong&gt;Dashboard&lt;/strong&gt; _ tab. On the dashboard page, click on the blue button that says _ &lt;strong&gt;New Push&lt;/strong&gt; _.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Notifications are enabled on Android devices by default if you have disabled your notifications, make sure you &lt;a href="https://support.google.com/android/answer/9079661?hl=en#zippy=%2Coption-show-all-notifications" rel="noopener noreferrer"&gt;enable them again&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fry_XclmRp64E3pMBK6AJF3nPgBxJ17hTTAL2WZH4np3Rp42FquanSFSrOzE9aFLlrVoA5w5Eal8EkP2T2fHNRAnGCf_vcVWVVkJE7MOqMPBDdqcygwT1TQkSNSPwprmO2VGJ5kLC" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2Fry_XclmRp64E3pMBK6AJF3nPgBxJ17hTTAL2WZH4np3Rp42FquanSFSrOzE9aFLlrVoA5w5Eal8EkP2T2fHNRAnGCf_vcVWVVkJE7MOqMPBDdqcygwT1TQkSNSPwprmO2VGJ5kLC" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to a new window that will allow you to customize your push notification. Under _ &lt;strong&gt;Audience&lt;/strong&gt; _, make sure that _ &lt;strong&gt;Send to Subscribed Users&lt;/strong&gt; _ is selected. Then, create your message by adding your message title, content, and image. Because this is the first notification your subscribers will receive, you may choose to craft a simple welcome message to confirm that they've been subscribed and reinforce the value that notifications will provide.&lt;/p&gt;

&lt;p&gt;Under the _ &lt;strong&gt;Delivery Schedule&lt;/strong&gt; _ section, select _ &lt;strong&gt;Immediately&lt;/strong&gt; _ and _ &lt;strong&gt;Send to everyone at the same time&lt;/strong&gt; _ to send to all your current push &lt;strong&gt;subscribers&lt;/strong&gt;. If you have just finished setting up your OneSignal account, chances are you're the first and only &lt;strong&gt;subscriber&lt;/strong&gt;. If your app or website is heavily trafficked and other users have already opted in to receive push notifications, you may want to select &lt;em&gt;&lt;strong&gt;Send to a particular segment(s)&lt;/strong&gt;&lt;/em&gt; to test your message out on a specific audience. When you're ready to send your message, click on the blue _ &lt;strong&gt;Review and Send&lt;/strong&gt; _ button at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FgxcVZhczYuEkW_iKYfqDpUtliEH9lXKYpX_weRmFdyEaLpZq7mOYKILJFg4droUpNSsIYrGN8oY46QX7aKS_0QqRwoaGKkPfW8rNnT_R1f-pLSKE1LNEvyAZEr5NEZpchjAZCvFU" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FgxcVZhczYuEkW_iKYfqDpUtliEH9lXKYpX_weRmFdyEaLpZq7mOYKILJFg4droUpNSsIYrGN8oY46QX7aKS_0QqRwoaGKkPfW8rNnT_R1f-pLSKE1LNEvyAZEr5NEZpchjAZCvFU" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small popup will appear for you to review your message. Once you are satisfied, click on the blue _ &lt;strong&gt;Send Message&lt;/strong&gt; _ button. You should receive a push notification on your device! 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fcbcps5xvy2ovezv2f0ul.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcbcps5xvy2ovezv2f0ul.jpg" alt="How To Add Android Push Notifications to a React Native Expo App" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can keep expanding your code to make use of different features of the OneSignal SDK across your Expo app bypassing the &lt;code&gt;OneSignal&lt;/code&gt; variable to different components.&lt;/p&gt;

&lt;p&gt;To learn more about the OneSignal Expo plugin, visit our &lt;a href="https://documentation.onesignal.com/docs/react-native-sdk-setup" rel="noopener noreferrer"&gt;React Native (Expo)  push SDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect with Our Developer Community
&lt;/h2&gt;

&lt;p&gt;To stay in the loop with the latest product updates and innovations, follow the &lt;a href="https://twitter.com/onesignaldevs" rel="noopener noreferrer"&gt;OneSignal Developers Twitter&lt;/a&gt; and join our &lt;a href="https://discord.gg/EP7gf6Uz7G" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt;. Learn more about the OneSignal developer community and how to stay connected by following the link below.&lt;/p&gt;

&lt;h3&gt;
  
  
  &amp;gt;&amp;gt; &lt;a href="https://onesignal.com/onesignal-developers" rel="noopener noreferrer"&gt;Learn About the OneSignal Developer Community&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>mobile</category>
      <category>android</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>How to add push notifications In Android using Ionic + Capacitor (React)</title>
      <dc:creator>Pato</dc:creator>
      <pubDate>Thu, 02 Sep 2021 20:15:31 +0000</pubDate>
      <link>https://dev.to/onesignal/how-to-add-push-notifications-in-android-using-ionic-capacitor-react-50pf</link>
      <guid>https://dev.to/onesignal/how-to-add-push-notifications-in-android-using-ionic-capacitor-react-50pf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2F78oszyoznldy40li8wtu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F78oszyoznldy40li8wtu.jpg" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Push notifications can help you engage and retain app users. This tutorial will show you how to integrate with OneSignal to leverage push notifications in your Android app.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;OneSignal &amp;amp; Your Browser's Push API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The browser's Push API gives web applications the ability to receive messages from a server whether or not the web app is in the foreground or currently loaded on a user agent. This lets you deliver asynchronous notifications and updates to users who opt-in, resulting in better engagement with timely new content.&lt;/p&gt;

&lt;p&gt;This tutorial will cover how to integrate OneSignal push notifications into your app using our setup process for Android apps. Part one of this guide covers the OneSignal setup process. Part two of this guide covers the integration of OneSignalwith Ionic + Capacitor (React) for your Android app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guide Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Part 1: Set Up Your OneSignal Account&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Part 2: Push Notification Setup For Android In Ionic + Capacitor (React)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires some basic knowledge of React. I'm using the &lt;a href="https://ionicframework.com/docs/cli" rel="noopener noreferrer"&gt;Ionic CLI&lt;/a&gt; to generate my project and &lt;strong&gt;NodeJS version 14.16&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Github Repository Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/OneSignalDevelopers/OneSignal-Ionic-Capacitor-React-Android-Sample" rel="noopener noreferrer"&gt;Ionic + Capacitor (React) OneSignal Setup&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Set Up Your OneSignal Account
&lt;/h2&gt;

&lt;p&gt;To begin, &lt;a href="https://app.onesignal.com/login" rel="noopener noreferrer"&gt;log in&lt;/a&gt; to your OneSignal account or &lt;a href="https://app.onesignal.com/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt;. Then, click on the blue button entitled _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ to configure your OneSignal account to fit your app or website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FmhI6zOntpAWlfgoErrPokTv0gvYxRKMU4ljMcwTfhc14SCtJDZFUXZNRjeXLeEuxpRjh-kE8HYN_P3edHFGCHtH9VnWQP0EWQRRPMptWcK4Vo2yGMaTbNkcgM3pUpdDbfostIwJ8" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FmhI6zOntpAWlfgoErrPokTv0gvYxRKMU4ljMcwTfhc14SCtJDZFUXZNRjeXLeEuxpRjh-kE8HYN_P3edHFGCHtH9VnWQP0EWQRRPMptWcK4Vo2yGMaTbNkcgM3pUpdDbfostIwJ8" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Insert the name of your app or website. Select _ &lt;strong&gt;Google Android&lt;/strong&gt; _ as your platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FQbM-Tk5yUSYZjPaeqMG6xqEBz9d8KSQ_zSCTgEUecTAaQ2EZRKYD6J0Wam5wwF94TOXATJ-AsL09zDX30PRKCabxxG2C6aEW24uT-KN9PNR2BID3V7J_70H5WnORGd8rYpmQanD8" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FQbM-Tk5yUSYZjPaeqMG6xqEBz9d8KSQ_zSCTgEUecTAaQ2EZRKYD6J0Wam5wwF94TOXATJ-AsL09zDX30PRKCabxxG2C6aEW24uT-KN9PNR2BID3V7J_70H5WnORGd8rYpmQanD8" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the blue button entitled, _ &lt;strong&gt;Next: Configure Your Platform&lt;/strong&gt; _.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Android FCM Configuration
&lt;/h3&gt;

&lt;p&gt;It’s time to configure your Android app using a Firebase Server key. All Android apps require this key and the server ID if you want to send push notifications. If you don’t have the Firebase Server Keys, take a look at our documentation to learn &lt;a href="https://documentation.onesignal.com/docs/generate-a-google-server-api-key" rel="noopener noreferrer"&gt;how to generate a Firebase server API key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fh-7LN5XOhPFWwOg36UEfIT-Y45u9ys3OmH5fLUd6hvqT3QXXPGY9S6IExelurxGqYRR_W5fPsP5UQ8T6TdFBzgsUd23X4q3XWFoX_rud-Upp6i1uYWEdRTHa4EVXuI8xW2G0SxHr" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2Fh-7LN5XOhPFWwOg36UEfIT-Y45u9ys3OmH5fLUd6hvqT3QXXPGY9S6IExelurxGqYRR_W5fPsP5UQ8T6TdFBzgsUd23X4q3XWFoX_rud-Upp6i1uYWEdRTHa4EVXuI8xW2G0SxHr" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now select your target SDK. We'll take you through the steps to get your first user and send your first test notification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F_F8otpdYtkPg5uBIGAxQuHQUW--RZt6DV6S5xUADtKAeUOJBccM9O8oUUTs3r0jSlvkQvc4kfFqmEFbTXnDLkAIvh3q0TM3R00WvhQuTM0NWAiKzc0YwAPBNs5jC4BEkHTjq5qaZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F_F8otpdYtkPg5uBIGAxQuHQUW--RZt6DV6S5xUADtKAeUOJBccM9O8oUUTs3r0jSlvkQvc4kfFqmEFbTXnDLkAIvh3q0TM3R00WvhQuTM0NWAiKzc0YwAPBNs5jC4BEkHTjq5qaZ" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next screen that appears, you will see your app ID — copy that app ID because you will use it inside of your Ionic application. &lt;strong&gt;DO NOT&lt;/strong&gt; click to _ &lt;strong&gt;Check Subscribed Users&lt;/strong&gt; _ or _ &lt;strong&gt;Done&lt;/strong&gt; _ yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F819gWMwbG1dm0mLoQ891BHeC0ZnT_YMi0gkKBumKck-K-SVXPkZ4V690RH4LmuPvt5p65X0y6UMbqTdi1m3e7F58kIpzbmbLc8hyp0-7qVla4kOXEjvng8Rvpm_PtBrMw6Fpl_7-" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F819gWMwbG1dm0mLoQ891BHeC0ZnT_YMi0gkKBumKck-K-SVXPkZ4V690RH4LmuPvt5p65X0y6UMbqTdi1m3e7F58kIpzbmbLc8hyp0-7qVla4kOXEjvng8Rvpm_PtBrMw6Fpl_7-" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Push Notification Setup For Android
&lt;/h2&gt;

&lt;p&gt;Now that you’ve collected the necessary items to add push notifications to your Android app, the next step is to make your Ionic app aware of OneSignal so that it can receive notifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your Ionic + Capacitor (React) App
&lt;/h3&gt;

&lt;p&gt;Inside your terminal, run the following command to add the Ionic project globally in your machine to use Ionic in your command line.&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 -g @ionic/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run the following command to create a new Ionic + Capacitor (React) project using the &lt;code&gt;Ionic CLI&lt;/code&gt;. You will be asked to select a framework, select &lt;code&gt;React&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ionic start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FYtZNkVheZzs743i2IDdv8q4qsZpF6kISVA4M3PeuH1H60cqeXcH5Xrt1yvaaEQqdOIw_EVQawEq2AEySwI6ub6YwazmSNyMW0d56ecQs-J8RQ0xKHJKFutaZsphYTs5YJP9Yv-Jk" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FYtZNkVheZzs743i2IDdv8q4qsZpF6kISVA4M3PeuH1H60cqeXcH5Xrt1yvaaEQqdOIw_EVQawEq2AEySwI6ub6YwazmSNyMW0d56ecQs-J8RQ0xKHJKFutaZsphYTs5YJP9Yv-Jk" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When asked to enter a project name, you can enter whatever name you want. In my case, I named my project &lt;strong&gt;​​&lt;/strong&gt; &lt;code&gt;OneSignal-Ionic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FloJcqHEZqBsUcUXz4qWbUAIdx2mfpiPBTUL_dZocKnN8ZmVcj4iG6Up8WRsbD5yOl-NnKBke4FMx7RYE6Cm4KB0WZVz1PTVYbsn5sxTQDpR_36Z-XnExGekuQOOblwZTJlLPv9Wa" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FloJcqHEZqBsUcUXz4qWbUAIdx2mfpiPBTUL_dZocKnN8ZmVcj4iG6Up8WRsbD5yOl-NnKBke4FMx7RYE6Cm4KB0WZVz1PTVYbsn5sxTQDpR_36Z-XnExGekuQOOblwZTJlLPv9Wa" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will also be asked to select a template. Feel free to select whatever template you’d like. In the example below, I have selected &lt;code&gt;tabs&lt;/code&gt; as the template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FcYo3fcj1IuPnioH1SJ0-MNA-54tuSpH--xWhDGKUixFRujm7kmpuUrbdPUZTtE7LohzjT9oLn_WR0HsP2ZadrN5ejJ1-L-zkcX8-z7UMhvDIe3WLNdkRmPVG7roozZSA2WflueO6" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FcYo3fcj1IuPnioH1SJ0-MNA-54tuSpH--xWhDGKUixFRujm7kmpuUrbdPUZTtE7LohzjT9oLn_WR0HsP2ZadrN5ejJ1-L-zkcX8-z7UMhvDIe3WLNdkRmPVG7roozZSA2WflueO6" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding OneSignal To Your Ionic Application
&lt;/h3&gt;

&lt;p&gt;To guide you through this process, I’m using a simple Ionic React Android app that illustrates how to integrate the OneSignal SDK. It is running on the Cordova npm package &lt;a href="https://documentation.onesignal.com/docs/step-by-step-cordova-2x-to-300-upgrade-guide" rel="noopener noreferrer"&gt;onesignal-cordova-plugin&lt;/a&gt; release.&lt;/p&gt;

&lt;p&gt;To begin, add your desired platform to the project. For my app, I chose Android as my desired platform by running: &lt;code&gt;ionic capacitor add android&lt;/code&gt;. Then, install the OneSignal Cordova plugin inside the project by running &lt;code&gt;npm install onesignal-cordova-plugin&lt;/code&gt;. The &lt;code&gt;ionic capacitor build android&lt;/code&gt; command will open the &lt;strong&gt;Android build&lt;/strong&gt; in Android Studio.&lt;/p&gt;

&lt;p&gt;After building your Ionic application into a new Android app, run the &lt;code&gt;cap sync&lt;/code&gt; command (one time only) by entering &lt;code&gt;npx cap sync&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At the top of you &lt;code&gt;App.tsx&lt;/code&gt; file, import the &lt;code&gt;OneSignal&lt;/code&gt; &lt;strong&gt;npm&lt;/strong&gt; package to your component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import OneSignal from 'onesignal-cordova-plugin';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following initialization code to the &lt;code&gt;App.tsx&lt;/code&gt; file. &lt;strong&gt;Make sure to add your app ID, which you previously copied during Google Android FCM Configuration.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Call this function when your app starts
function OneSignalInit(): void {
  // NOTE: Update the setAppId value below with your OneSignal AppId.
  OneSignal.setAppId("YOUR_ONESIGNAL_APP_ID");
  OneSignal.setNotificationOpenedHandler(function(jsonData) {
      console.log('notificationOpenedCallback: ' + JSON.stringify(jsonData));
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the &lt;code&gt;OneSignalInit()&lt;/code&gt; function, you are going to call it when your app starts. In the &lt;code&gt;App.tsx&lt;/code&gt; file, add the following line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OneSignalInit();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, build your app again by running &lt;code&gt;ionic capacitor build android&lt;/code&gt; and opening the Android Studio project.&lt;/p&gt;

&lt;p&gt;I recommend you run the application on an actual Android device to test the notifications. To do so, you will need to connect your Android device and enable &lt;a href="https://developer.android.com/studio/debug/dev-options" rel="noopener noreferrer"&gt;developer mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have connected to the device and enabled developer mode, run the application on your device by selecting your device as the target device. In my example, I’m running the app on a &lt;strong&gt;Google Pixel 5&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FjUSaNRl_EzCcpAkW6Wnl6Fk1aF_y6FsvYJzZBrJNLHoj4EolmbO8xCQt27HRIz-OyQIR39iqVl36dyUuqkPpWx5ZGGnF18jSocPx8WiQQr3sHIlCPkQMmpEnAMiDUqcesBmJg3Rz" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FjUSaNRl_EzCcpAkW6Wnl6Fk1aF_y6FsvYJzZBrJNLHoj4EolmbO8xCQt27HRIz-OyQIR39iqVl36dyUuqkPpWx5ZGGnF18jSocPx8WiQQr3sHIlCPkQMmpEnAMiDUqcesBmJg3Rz" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have opened the application on your device, the device will be automatically subscribed to the notification. Now, your device will be able to receive notifications sent by OneSignal.  &lt;/p&gt;

&lt;p&gt;To complete the setup process, return to your OneSignal dashboard to the point at which you previously left off. Click on the _ &lt;strong&gt;Check Subscribed Users&lt;/strong&gt; _ and a green message will appear like the one in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FM3eX87alenkBspvpBfvwavh2_6z12l2RU6hF7M_yOPus_rqv46Pdev3qNs-JBSDWyihMP3b9kUp2p_1PFinkg-G72_eDqX7kfPEJ_oSg6u4ecctESL5JEbnVp3rLGYlpizqtZvQD" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FM3eX87alenkBspvpBfvwavh2_6z12l2RU6hF7M_yOPus_rqv46Pdev3qNs-JBSDWyihMP3b9kUp2p_1PFinkg-G72_eDqX7kfPEJ_oSg6u4ecctESL5JEbnVp3rLGYlpizqtZvQD" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the _ &lt;strong&gt;Done&lt;/strong&gt; _ button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send A Push Notification
&lt;/h3&gt;

&lt;p&gt;It’s time to send your first web push notification! To do so, log in to your OneSignal account and navigate to the _ &lt;strong&gt;Dashboard&lt;/strong&gt; _ tab. On the dashboard page, click on the blue button that says _ &lt;strong&gt;New Push&lt;/strong&gt; _.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Notifications are enabled on Android devices by default, but can be disabled by users via their phone settings. If you have manually disabled your notifications, make sure you &lt;a href="https://support.google.com/android/answer/9079661?hl=en#zippy=%2Coption-show-all-notifications" rel="noopener noreferrer"&gt;enable notifications again&lt;/a&gt; in order to test how they work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FSJFDXoXqxPvC5wPYuIH9STjVUXQEhzEdlMngO0WrOcoYwtxSHd63qbRqsTBy0FVp41FcyIr10wIb563Efp-9gWVsX-V_ExsXxT3wZa3GcpKC7SQbde-B_nBkjpLo3I2IDynpRlU-" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FSJFDXoXqxPvC5wPYuIH9STjVUXQEhzEdlMngO0WrOcoYwtxSHd63qbRqsTBy0FVp41FcyIr10wIb563Efp-9gWVsX-V_ExsXxT3wZa3GcpKC7SQbde-B_nBkjpLo3I2IDynpRlU-" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to a new window that will allow you to customize your push notification. Under _ &lt;strong&gt;Audience&lt;/strong&gt; _, make sure that _ &lt;strong&gt;Send to Subscribed Users&lt;/strong&gt; _ is selected. Then, create your message by adding your message title, content, and image. Because this is the first notification your subscribers will receive, you may choose to craft a simple welcome message to confirm that they've been subscribed and reinforce the value that notifications will provide.&lt;/p&gt;

&lt;p&gt;Under the _ &lt;strong&gt;Delivery Schedule&lt;/strong&gt; _ section, select _ &lt;strong&gt;Immediately&lt;/strong&gt; _ and _ &lt;strong&gt;Send to everyone at the same time&lt;/strong&gt; _ to send to all your current push &lt;strong&gt;subscribers&lt;/strong&gt;. If you have just finished setting up your OneSignal account, chances are you're the first and only &lt;strong&gt;subscriber&lt;/strong&gt;. If your app or website is heavily trafficked and other users have already opted in to receive push notifications, you may want to select &lt;em&gt;&lt;strong&gt;Send to a particular segment(s)&lt;/strong&gt;&lt;/em&gt; to test your message out on a specific audience. When you're ready to send your message, click on the blue _ &lt;strong&gt;Review and Send&lt;/strong&gt; _ button at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FVJ6nDCVDWT0QPoR8JSnyYgH-ei5_iJoL-HBa1tiFIBf_EfX83Zm0Go7VbGM7gQS7F4nmV9PyIr-RuA4Fn8LvopNH4bF1TCJOaB6XPO6F2KEk2xTGrKjcWsOm6gbZQR6cUVdVidV2" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2FVJ6nDCVDWT0QPoR8JSnyYgH-ei5_iJoL-HBa1tiFIBf_EfX83Zm0Go7VbGM7gQS7F4nmV9PyIr-RuA4Fn8LvopNH4bF1TCJOaB6XPO6F2KEk2xTGrKjcWsOm6gbZQR6cUVdVidV2" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small popup will appear for you to review your message. Once you are satisfied, click on the blue _ &lt;strong&gt;Send Message&lt;/strong&gt; _ button. You should receive a web push notification on your device! 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FXmNhnDZk3XcrJzf3Z9r6GkGcCsdydNXDMb9HyIFp3GLt8RGYcoEtSDTggPh8XZA-Lg4Umb2If2DngvZr99Br-8OhbBrS84XzZ3WneupjORJZVUCjIe-NComTnIanoHm6hT-RcoSS" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FXmNhnDZk3XcrJzf3Z9r6GkGcCsdydNXDMb9HyIFp3GLt8RGYcoEtSDTggPh8XZA-Lg4Umb2If2DngvZr99Br-8OhbBrS84XzZ3WneupjORJZVUCjIe-NComTnIanoHm6hT-RcoSS" alt="How to add push notifications In Android using Ionic + Capacitor (React)" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can keep expanding your code to make use of different features of the OneSignal SDK across your Ionic app by passing the &lt;code&gt;OneSignal&lt;/code&gt; variable to different components. To learn more about the Ionic SDK visit our Ionic push &lt;a href="https://documentation.onesignal.com/docs/ionic-sdk-setup" rel="noopener noreferrer"&gt;SDK documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>ionic</category>
      <category>react</category>
      <category>mobiledev</category>
    </item>
  </channel>
</rss>
