<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: OneSignal</title>
    <description>The latest articles on Forem by OneSignal (@onesignal).</description>
    <link>https://forem.com/onesignal</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%2Forganization%2Fprofile_image%2F4022%2F23214b83-b368-4449-81dc-ceb39bcaf9f1.png</url>
      <title>Forem: OneSignal</title>
      <link>https://forem.com/onesignal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/onesignal"/>
    <language>en</language>
    <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://forem.com/onesignal/how-to-add-in-app-messages-to-a-flutter-app-2fg0</link>
      <guid>https://forem.com/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>Fixing Memory Leaks in Rust</title>
      <dc:creator>onesignaldevs</dc:creator>
      <pubDate>Mon, 23 May 2022 23:35:29 +0000</pubDate>
      <link>https://forem.com/onesignal/fixing-memory-leaks-in-rust-38l</link>
      <guid>https://forem.com/onesignal/fixing-memory-leaks-in-rust-38l</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W9vOCkyX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/05/fixing-memory-leaks-in-rust.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W9vOCkyX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/05/fixing-memory-leaks-in-rust.jpeg" alt="Fixing Memory Leaks in Rust" width="880" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At OneSignal, we love Rust. We have blogged before about &lt;a href="https://onesignal.com/blog/rust-at-onesignal/"&gt;pivoting some of our core business systems to Rust&lt;/a&gt;, &lt;a href="https://onesignal.com/blog/4-years-of-rust-at-onesignal/"&gt;how the language has changed over the past several years&lt;/a&gt;, and interesting things we’ve learned about the &lt;a href="https://onesignal.com/blog/thread-safety-rust/"&gt;thread safety model&lt;/a&gt;. Other than Onepush, the core of our push notification delivery system, we also use Rust for a gRPC service and multiple Kafka consumers. In this article, we’re going to talk about a stumbling block that we ran into with one of our newest Rust projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;Near the end of February, we announced the general availability of &lt;a href="https://onesignal.com/blog/consistently-drive-value-with-journeys/"&gt;our Journeys feature&lt;/a&gt;. Journeys allows customers to easily build complex messaging workflows with a no-code UI. It is powered by a few gRPC services and a Kafka consumer written in Rust, called JourneyX. Journeys is an event-driven system, so everything that happens within a journey workflow is triggered by an event on a Kafka stream. These events are consumed by JourneyX (journey executor).&lt;/p&gt;

&lt;p&gt;A few weeks ago, as Journeys adoption started to increase and JourneyX started to process more events, we began to notice a disturbing pattern in its memory usage. The most active processes were consistently utilizing lots of memory, then getting killed by the kernel. The Linux kernel has a piece of functionality called the OOM (out-of-memory) killer, which will automatically kill processes when they consume too much of the system memory. This prevents the system from becoming unstable or locking up due to resource starvation. In our case, the JourneyX processes were constantly being killed, restarted, and killed again by the OOM killer. This showed up on a graph as a sawtooth pattern of rapid allocation and near-instant deallocation when the process was killed. Memory usage would spike up to 17 GiB in the busiest processes, but we expect one of these worker processes to need under 1 GiB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N2MS3CQ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1650487816016_Screen%2BShot%2B2022-04-20%2Bat%2B13.50.01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N2MS3CQ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1650487816016_Screen%2BShot%2B2022-04-20%2Bat%2B13.50.01.png" alt="Fixing Memory Leaks in Rust" width="880" height="370"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Graph of memory usage for a single JourneyX process over 24 hours&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This caused a few issues for us. Obviously from a theoretical perspective, we didn’t want a system that was constantly being killed by the OS. The operations it performed were idempotent, so we weren’t necessarily worried about sending multiple notifications due to this problem. The issue did create alert spam for us, which led us to over-provision on memory. The constant crashing also caused concern about the long-term health of the service.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BUT WAIT!&lt;/em&gt; I hear you say — doesn’t Rust’s borrow checker prevent memory errors? Isn’t Rust supposed to be “safe?” It turns out that, according to Rust’s rules, leaking memory is completely safe! In fact, we can purposely leak as much memory as we want using the function &lt;code&gt;std::mem::forget&lt;/code&gt;. The only thing “unsafe” about memory leaks is that they might eventually result in your program being killed by the kernel (as JourneyX does in this case). A program ending in a predictable way is also considered safe behavior. Rust’s safety guarantees exist to protect us from invalid memory access, not resource starvation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Troubleshooting with Distributed Tracing
&lt;/h2&gt;

&lt;p&gt;In addition to Rust, we’re big fans of distributed tracing. If you’re not familiar with tracing concepts, check out this document from Honeycomb's &lt;a href="https://www.honeycomb.io/blog/an-introduction-to-distributed-tracing/"&gt;Introduction to Distributed Tracing&lt;/a&gt;. All of our services report trace data and send &lt;a href="https://www.w3.org/TR/trace-context/"&gt;W3C trace propagation headers&lt;/a&gt; to one another so that we can tie operations together through our system. Tracing data in Honeycomb is now our first stop when our on-call team gets paged. Here is an example trace from our Journeys processing system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t_bzTa18--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1651174008475_Screen%2BShot%2B2022-04-28%2Bat%2B12.26.40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t_bzTa18--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1651174008475_Screen%2BShot%2B2022-04-28%2Bat%2B12.26.40.png" alt="Fixing Memory Leaks in Rust" width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In some languages, tracing instrumentation can be accomplished largely through automated means. In our Ruby on Rails codebase, the Honeycomb and OpenTelemetry libraries use ActiveSupport hooks to add trace spans around operations like HTTP handlers and ActiveRecord queries. Rust is a lot of things, but it's not really “runtime configurable.” There are libraries that allow you to write Rust code that can be configured at runtime, but most Rust code is not written in this way. Because of this, we need to add a lot of manual instrumentation to our Rust apps. We need to manually delineate operations into spans and add fields on those spans.&lt;/p&gt;

&lt;p&gt;We have a few choices for adding these data to our codebases. We could use the Rust &lt;code&gt;opentelemetry&lt;/code&gt; library, which is generic and standardized according to the OpenTelemetry specification. Instead, we use the tracing library, which is a façade crate, similar to &lt;code&gt;log&lt;/code&gt;. It allows us to connect and configure multiple tracing backends, and it captures data from the &lt;code&gt;log&lt;/code&gt; crate straight out of the box.&lt;/p&gt;

&lt;p&gt;If we had some Rust code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;http_handler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;perform_expensive_computation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you wanted to put a span around the &lt;code&gt;perform_expensive_computation&lt;/code&gt; function, you could do so like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info_span&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;http_handler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;info_span!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"perform_expensive_computation"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;perform_expensive_computation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;enter&lt;/code&gt; function returns a guard that marks the time in which the span is active. It begins when you first call &lt;code&gt;enter&lt;/code&gt;, and ends when the guard value is dropped as it goes out of scope. Rust’s &lt;code&gt;Drop&lt;/code&gt; trait allows it to easily provide the functionality to run at the time it’s deallocated.&lt;/p&gt;

&lt;p&gt;Within JourneyX, surrounding the “send a notification” HTTP request, we had the following snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;query_span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info_span!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send HTTP request"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.client&lt;/span&gt;&lt;span class="nf"&gt;.request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.into_parts&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 experienced users of the tracing library may already know the issue, but to those of us who aren’t intimately familiar with the API, this looks quite reasonable based on what I’ve already told you. If we look at the documentation for the enter method though, we may notice something that calls this into question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt; : in asynchronous code that uses &lt;a href="https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html"&gt;async/await syntax&lt;/a&gt;, Span::enter should be used very carefully or avoided entirely. Holding the drop guard returned by Span::enter across .await points will result in incorrect traces.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice the last line of the block above uses &lt;code&gt;.await&lt;/code&gt; when calling the &lt;code&gt;request&lt;/code&gt; method. This is going to cause a problem for us. To see why, we need to look at the conceptual models for &lt;code&gt;tracing&lt;/code&gt; and async Rust.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.enter&lt;/code&gt; method from &lt;code&gt;tracing&lt;/code&gt; returns what is conventionally referred to as a “guard” type. One of the great benefits of Rust’s ownership and lifetime system is that it provides the ability to write destructors for any type and to be sure about when those destructors are going to run. We can do this by implementing the Drop trait for any type. The interface looks (very, very roughly) like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;EnterGuard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;EnterGuard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;begin_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;EnterGuard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.id&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;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;EnterSpan&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;end_span&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;Because of Rust’s destructor rules, the &lt;code&gt;EnterSpan&lt;/code&gt; type will call the &lt;code&gt;end_span&lt;/code&gt; function whenever the variable it’s attached to goes out of scope. Here is an annotated example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// begin_span called&lt;/span&gt;
    &lt;span class="nf"&gt;do_expensive_computation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// end_span called by the Drop of `_guard`&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// begin_span called&lt;/span&gt;
  &lt;span class="nf"&gt;more_compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// end_span called by the Drop of `_guard`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great because it means that most of the time, we just don’t need to worry about remembering to mark a span as complete. It just works (tm). For synchronous code, that’s definitely the case, but it falls apart for async code. To see why that's the case, let’s look at the pseudocode for &lt;code&gt;begin_span&lt;/code&gt; and &lt;code&gt;end_span&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;thread_local!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ACTIVE_SPANS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RefCell&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpanId&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RefCell&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;begin_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SpanId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ACTIVE_SPANS&lt;/span&gt;&lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.borrow_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;end_span&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ACTIVE_SPANS&lt;/span&gt;&lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.borrow_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.pop&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 this is incredibly simplified (please don’t get mad at me, tracing maintainers) but the general idea is that each thread maintains a stack of span IDs that represents the hierarchy of spans currently active. This works great for synchronous code, when each OS thread can maintain this state independently. When we use async code, however, we have multiple tasks running concurrently on top of the same OS thread, sharing thread locals. And the &lt;code&gt;Drop&lt;/code&gt; handler for our &lt;code&gt;EnterGuard&lt;/code&gt; won’t be called when context switches happen. That means if we were to write code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;FuturesUnordered&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;info_span!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_millis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="k"&gt;.await&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="nn"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;future&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;join_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s consider what happens to our thread-local stack at each stage in the task execution. For simplicity's sake, we’ll assume for now that these five tasks are executed in the order that they were enqueued, although this typically isn't the case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p3WhJVXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1651519448041_tracing-real-path.drawio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p3WhJVXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1651519448041_tracing-real-path.drawio.png" alt="Fixing Memory Leaks in Rust" width="880" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that at both the beginning and end of the spans there are large discrepancies in the state of the stack. When spans are beginning, we create a hierarchy on the stack that indicates all of the tasks have a parent/child relationship with one another, but this is not accurate. When spans end, we pop the wrong task span off of the stack, because the state of the stack is inconsistent with reality.&lt;/p&gt;

&lt;p&gt;In our production code, this issue caused memory usage to skyrocket, because our span tree was essentially expanding endlessly and never able to shrink. Because of how quickly concurrent operations were occurring, the stack was continuously having new spans added to it, and previous spans (now with tens of thousands of children) would never be dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;So what’s the fix? It’s very simple. Recall that the original code looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;query_span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info_span!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send HTTP request"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;_guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.client&lt;/span&gt;&lt;span class="nf"&gt;.request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.into_parts&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 need to update it to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;query_span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info_span!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send HTTP request"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.client&lt;/span&gt;&lt;span class="nf"&gt;.request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_span&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.into_parts&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;It’s a subtle change, but absolutely critical. Let’s see how this works. This is once again simplified for the sake of brevity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Instrument&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Instrumented&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Instrumented&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&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;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Instrumented&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Instrumented&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;T&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Pin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&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;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Poll&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Output&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;let&lt;/span&gt; &lt;span class="n"&gt;_enter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.span&lt;/span&gt;&lt;span class="nf"&gt;.enter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.inner&lt;/span&gt;&lt;span class="nf"&gt;.poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&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;There are a few things going on here. First off, we have the &lt;code&gt;Instrument&lt;/code&gt; trait. This is an extension trait that exists only to allow us to build an &lt;code&gt;Instrumented&lt;/code&gt; struct from an arbitrary &lt;code&gt;Future&lt;/code&gt;. &lt;code&gt;Instrumented&lt;/code&gt; is a wrapper future that allows us to have tight control over the polling logic. In this case, we use &lt;code&gt;.enter&lt;/code&gt; to begin the span while the underlying future is polled, and end the span when the context switches.&lt;/p&gt;

&lt;p&gt;This works because &lt;code&gt;poll&lt;/code&gt; is the context-switching boundary of a future. While &lt;code&gt;poll&lt;/code&gt; is being called, this future and its children are the only things burning CPU time on the thread. Other futures may be sleeping in the background, but nothing else can preempt the currently running future’s &lt;code&gt;poll&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tracing’s &lt;code&gt;.enter&lt;/code&gt; method isn’t the only instance of this. There are many types that were not designed to be held across await points. &lt;code&gt;Mutex&lt;/code&gt;, &lt;code&gt;RwLock&lt;/code&gt;, and &lt;code&gt;RefCell&lt;/code&gt; for example all have guard types that hold a lock on a resource and could result in deadlocks if held across await points.&lt;/p&gt;

&lt;p&gt;So where do we go from here? There’s a subtle code difference that results in both incorrect observability results and potentially extreme memory usage. Normally, issues like this could be caught by the Rust compiler. There is an RFC to add a lint to the compiler called &lt;a href="https://github.com/rust-lang/rust/issues/83310"&gt;&lt;code&gt;must_not_suspend&lt;/code&gt;&lt;/a&gt; which will allow developers to mark types as being unsafe to hold across await points. But there is still a lot of work remaining before this will land, so what should we do in the meantime?&lt;/p&gt;

&lt;p&gt;Rust’s standard linting tool, Clippy, has existing lints for the &lt;code&gt;Mutex&lt;/code&gt; and &lt;code&gt;RefCell&lt;/code&gt; types, but we don’t want to have to create a custom Clippy lint for every type like this. A few weeks ago, I submitted &lt;a href="https://github.com/rust-lang/rust-clippy/pull/8707"&gt;rust-lang/clippy#8707&lt;/a&gt; which allows Clippy users to provide a list of types that are not allowed to be held across await points. Once this makes it to Clippy’s stable release branch, users will be able to add the following to their &lt;code&gt;clippy.toml&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;holding&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;invalid&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"tracing::trace::Entered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"tracing::trace::EnteredSpan"&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 will provide users with a warning if a span’s enter guard is held across an await point when they run cargo Clippy. The warnings will 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;error: `tracing::trace::Entered` may not be held across an `await` point per `clippy.toml`
  --&amp;gt; main.rs:10:9
   |
LL | let _guard = span.enter();
   | ^^^^^^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides some amount of safeguarding, though the &lt;code&gt;must_not_suspend&lt;/code&gt; lint will be a welcome improvement, as it will not require an explicit configuration in order to work.&lt;/p&gt;

&lt;p&gt;Thank you for coming with me on this journey of memory leak discovery! I’ll leave you with a four-day graph of the memory usage of our JourneyX processes. It’s quite clear when this change was deployed that we instantly fixed the issue with this very subtle code change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xm_-yHow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1650305781135_Screen%2BShot%2B2022-04-18%2Bat%2B10.03.19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xm_-yHow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_A27BFDF87D2127DCD6BB2EBAD04C599513C407E65763082467920C2770D2212C_1650305781135_Screen%2BShot%2B2022-04-18%2Bat%2B10.03.19.png" alt="Fixing Memory Leaks in Rust" width="880" height="363"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A graph of the memory usage of our JourneyX processes over four days.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you’re interested in working on using Rust in production to create high-throughput evented systems, distributed systems, or any other areas of engineering, please check out the OneSignal careers page!&lt;/p&gt;

&lt;h3&gt;
  
  
  &amp;gt;&amp;gt; &lt;a href="https://onesignal.com/careers"&gt;Browse OneSignal Careers&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>rust</category>
      <category>backend</category>
      <category>programming</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://forem.com/onesignal/how-to-add-in-app-messages-in-react-native-expo-o6c</link>
      <guid>https://forem.com/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://forem.com/onesignal/how-to-send-push-notifications-with-the-onesignal-nodejs-client-sdk-448g</link>
      <guid>https://forem.com/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://forem.com/onesignal/graphql-and-push-notifications-with-onesignal-and-takeshape-5gcm</link>
      <guid>https://forem.com/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://forem.com/onesignal/how-to-send-push-notifications-with-the-onesignal-rest-api-16lf</link>
      <guid>https://forem.com/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://forem.com/onesignal/how-to-add-push-notifications-into-an-ios-app-a3k</link>
      <guid>https://forem.com/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 Push Notifications to a Flutter App</title>
      <dc:creator>onesignaldevs</dc:creator>
      <pubDate>Mon, 14 Mar 2022 18:35:30 +0000</pubDate>
      <link>https://forem.com/onesignal/how-to-add-push-notifications-to-a-flutter-app-1jag</link>
      <guid>https://forem.com/onesignal/how-to-add-push-notifications-to-a-flutter-app-1jag</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XYBl0Z09--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/03/how-to-add-push-notifications-to-a-flutter-app.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XYBl0Z09--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/03/how-to-add-push-notifications-to-a-flutter-app.jpg" alt="How to Add Push Notifications to a Flutter App" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Push notifications have proved to be one of the most effective ways to enhance your user experience, improve app engagement, and boost retention. In this tutorial, we’ll show you how to integrate &lt;a href="https://onesignal.com/mobile"&gt;push notifications&lt;/a&gt; in your iOS and Android apps with minor configuration changes using the &lt;a href="https://documentation.onesignal.com/docs/flutter-sdk-setup"&gt;OneSignal Flutter SDK&lt;/a&gt;. In no time, you'll be able to send out transactional and promotional push notifications to users for free!&lt;/p&gt;

&lt;p&gt;If you are a Flutter developer and want to leverage push notifications to engage with your users, follow along to add this amazing functionality to your apps.&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: Creating a Flutter App&lt;/strong&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"&gt;log in&lt;/a&gt; to your OneSignal account or &lt;a href="https://app.onesignal.com/signup"&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://res.cloudinary.com/practicaldev/image/fetch/s--cccs2Dzj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/SuayEKKWaLijFKYhGF4ijppOJqfprFUswRNI6DTWaLimqGtYmG55d-yYIw2DmIog9_X674_h3c7NW0ITCET5rdGBnzC1eZ8ycxsbkzqFMry8LPLSFNqg-eDguOkaf4PArmRe2FIC" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cccs2Dzj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/SuayEKKWaLijFKYhGF4ijppOJqfprFUswRNI6DTWaLimqGtYmG55d-yYIw2DmIog9_X674_h3c7NW0ITCET5rdGBnzC1eZ8ycxsbkzqFMry8LPLSFNqg-eDguOkaf4PArmRe2FIC" alt="How to Add Push Notifications to a Flutter App" width="880" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add your app name, select _ &lt;strong&gt;Google Android&lt;/strong&gt; _ if the target is Android devices or select _ &lt;strong&gt;Apple iOS&lt;/strong&gt; _ if the target is iOS devices. Then click, &lt;strong&gt;&lt;em&gt;Next: Configure Your Platform&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oxUzrzho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/W9bhSNrbKFrkTMfVcxScu5x2GzRVj9_T7cVnkQKtlHU_V5_BFkHRsV2jkXaJD9BfulmUSVhYK26xDfEzXPqy2mw4RKBFE99vd87FVHBnrjf-CFGiDXWhN1-ymH-2-PzNFCx58rUK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oxUzrzho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/W9bhSNrbKFrkTMfVcxScu5x2GzRVj9_T7cVnkQKtlHU_V5_BFkHRsV2jkXaJD9BfulmUSVhYK26xDfEzXPqy2mw4RKBFE99vd87FVHBnrjf-CFGiDXWhN1-ymH-2-PzNFCx58rUK" alt="How to Add Push Notifications to a Flutter App" width="880" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For iOS, you will need to &lt;strong&gt;add an iOS push certificate&lt;/strong&gt;. If you're not sure about this step, read OneSignal's &lt;a href="https://documentation.onesignal.com/docs/generate-an-ios-push-certificate"&gt;instructions on how to generate an iOS push certificate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ZA8Z_Hu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/SS9EXmNZn6BPiaVQZaDUvNHWVH8Ba9IaoVKWlu0B1Wzc-52TK5IoJbhsomskMQ1tjsa2yBpFAMtgr72VB3AppQuI-LWhrccmNL7958EhKBZc4gs_Ee-N5WItgFxLxdbcTabp6P1m" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ZA8Z_Hu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/SS9EXmNZn6BPiaVQZaDUvNHWVH8Ba9IaoVKWlu0B1Wzc-52TK5IoJbhsomskMQ1tjsa2yBpFAMtgr72VB3AppQuI-LWhrccmNL7958EhKBZc4gs_Ee-N5WItgFxLxdbcTabp6P1m" alt="How to Add Push Notifications to a Flutter App" width="880" height="316"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Apple iOS (APNs) Configuration in OneSignal&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For Android, you will need to enter &lt;strong&gt;Firebase Server Key&lt;/strong&gt; and &lt;strong&gt;Server ID&lt;/strong&gt; that you can get by creating a new project on Firebase Console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B27kDBTc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/QSh1iDrnoIL5yuThK1hKjbHU67sxkuVLC4WtTjwLQ3TDnTE1sM6rsYtso3GmUo7VtbZ98o5byyRYlLm5M3OVW-Cynb4TeIfz4GfWlkUFtS2o-hv4szJ7GjKFmDAsH5A5NDJ7m_Fo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B27kDBTc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/QSh1iDrnoIL5yuThK1hKjbHU67sxkuVLC4WtTjwLQ3TDnTE1sM6rsYtso3GmUo7VtbZ98o5byyRYlLm5M3OVW-Cynb4TeIfz4GfWlkUFtS2o-hv4szJ7GjKFmDAsH5A5NDJ7m_Fo" alt="How to Add Push Notifications to a Flutter App" width="880" height="334"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Google Android (FCM) Configuration in OneSignal&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To find the Firebase service key, log in to the Firebase console and click on &lt;strong&gt;&lt;em&gt;Add Project&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rZ9UhZ9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/HCgbFkPibXItPV_rMXZ4I5UhZ_VMJdLvDTvLkSOwWNbTUSz3pcUzjkymdFuFWhRcCQZ1wlpFIwAKltrc4zr6GzwXaHTtHe3Wnqbh4mwzaetwkeM15Vtpe4fLmEpqO-Q0f8ECuw4I" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rZ9UhZ9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/HCgbFkPibXItPV_rMXZ4I5UhZ_VMJdLvDTvLkSOwWNbTUSz3pcUzjkymdFuFWhRcCQZ1wlpFIwAKltrc4zr6GzwXaHTtHe3Wnqbh4mwzaetwkeM15Vtpe4fLmEpqO-Q0f8ECuw4I" alt="How to Add Push Notifications to a Flutter App" width="880" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the name of your project and turn off &lt;strong&gt;&lt;em&gt;Enable Google Analytics for this project&lt;/em&gt;&lt;/strong&gt; if you want,  then click on &lt;strong&gt;&lt;em&gt;Create Project&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--leKp6AaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/7NimhzKwTi82XolqEwokp2pL_wU7vf2glRxVp6ldi4KQhKVu5zhXyB4IMzBS6qTxuibP3IEijZYRzLoDj-yQZUjvXY88yQQlsXYejTdxP-olVQ91GqE-TqSEn_VDBv3wUIxIF3Fc" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--leKp6AaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/7NimhzKwTi82XolqEwokp2pL_wU7vf2glRxVp6ldi4KQhKVu5zhXyB4IMzBS6qTxuibP3IEijZYRzLoDj-yQZUjvXY88yQQlsXYejTdxP-olVQ91GqE-TqSEn_VDBv3wUIxIF3Fc" alt="How to Add Push Notifications to a Flutter App" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WYkrTygJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/NOI1N2J8u3Bip_-PzMNTvO2gvH49U0q77YKtHvu3JNXxZUMELoTrsAgFQEC_CVIchdW8mYMs5e8iYKT7sDyUyoOqSJgbapCZhKsp7ReAK9BtKCBg6eK-HV1TkN5oYkGBdYLqhcpu" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WYkrTygJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/NOI1N2J8u3Bip_-PzMNTvO2gvH49U0q77YKtHvu3JNXxZUMELoTrsAgFQEC_CVIchdW8mYMs5e8iYKT7sDyUyoOqSJgbapCZhKsp7ReAK9BtKCBg6eK-HV1TkN5oYkGBdYLqhcpu" alt="How to Add Push Notifications to a Flutter App" width="880" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click _ &lt;strong&gt;Create project&lt;/strong&gt; _ to save the new entry, then click _ &lt;strong&gt;continue&lt;/strong&gt; _.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ldx8YZ3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/R3gzEUHXu6FLVzT4YA3yE2rq7t9FlJEwKeueprwAFRhXF-cT5MxaTD-H-gOoPzypzBAIqPbAnnSDTfrOmpXUfKm31_u-PjCMVS-tVnyDWMzf2yhLoGureWuAl029DYUETpRC6Wlz" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ldx8YZ3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/R3gzEUHXu6FLVzT4YA3yE2rq7t9FlJEwKeueprwAFRhXF-cT5MxaTD-H-gOoPzypzBAIqPbAnnSDTfrOmpXUfKm31_u-PjCMVS-tVnyDWMzf2yhLoGureWuAl029DYUETpRC6Wlz" alt="How to Add Push Notifications to a Flutter App" width="880" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll be directed to the project dashboard where you have to click on the Setting icon next to _ &lt;strong&gt;Project Overview&lt;/strong&gt; _ and click on _ &lt;strong&gt;Project Settings&lt;/strong&gt; _ from the menu that appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7igylNaH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/xgBbRkPvoy5yrtjZgPrT_RHDWm2TnlJiQsMu2eHMid8ZrDjwuAtbQVfrNmdov-ZgVQfdeHphFFpcVLV7vXDafHApaj6QS8_VKcaU0SgVUTPwBekHbRiOQg4_KOIrhF1knue18zB5" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7igylNaH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/xgBbRkPvoy5yrtjZgPrT_RHDWm2TnlJiQsMu2eHMid8ZrDjwuAtbQVfrNmdov-ZgVQfdeHphFFpcVLV7vXDafHApaj6QS8_VKcaU0SgVUTPwBekHbRiOQg4_KOIrhF1knue18zB5" alt="How to Add Push Notifications to a Flutter App" width="880" height="289"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Navigate to the project settings menu in the Firebase console.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;Cloud Messaging&lt;/em&gt;&lt;/strong&gt; tab, you’ll be able to find the &lt;strong&gt;&lt;em&gt;Firebase Server Key&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Server ID&lt;/em&gt;&lt;/strong&gt;. Navigate back to your OneSignal dashboard and copy and paste those values into the appropriate fields under &lt;strong&gt;&lt;em&gt;OneSignal Google Android(FCM) Configuration&lt;/em&gt;&lt;/strong&gt; like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t6ocd7YL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/ASOexI_mhJTL_5onk8wRc9V2vf1IMGT2ENa5dHo6E7nkrx0YqVCTkwWdLD9rCohZwWbKkOzvJv-GidMq7i6kw2ZwXsd1qGhPlvHxjZGSuCrF-4Y4EsIrvT1VH8KUTtgGLMvoGJNg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t6ocd7YL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/ASOexI_mhJTL_5onk8wRc9V2vf1IMGT2ENa5dHo6E7nkrx0YqVCTkwWdLD9rCohZwWbKkOzvJv-GidMq7i6kw2ZwXsd1qGhPlvHxjZGSuCrF-4Y4EsIrvT1VH8KUTtgGLMvoGJNg" alt="How to Add Push Notifications to a Flutter App" width="880" height="344"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Input your Firebase Server Key and Sender ID in OneSignal.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After clicking on &lt;strong&gt;&lt;em&gt;Save &amp;amp; Continue&lt;/em&gt;&lt;/strong&gt; , you’ll be asked to select your target SDK. Choose &lt;strong&gt;&lt;em&gt;Flutter&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CLUyx1oN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/WccnkK7Gq2_BySBjkOYOt05_ELqpNySyF-ILU4-rkt1T5pUgBFemOV8IKS8DKZQHC9aLH6vUNcj5QEYyS_0dK5EB4W-vJqKCjilpFwh2Zj1YvH3o20TVp7OFpaNp7lkYyH5j8AxB" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CLUyx1oN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/WccnkK7Gq2_BySBjkOYOt05_ELqpNySyF-ILU4-rkt1T5pUgBFemOV8IKS8DKZQHC9aLH6vUNcj5QEYyS_0dK5EB4W-vJqKCjilpFwh2Zj1YvH3o20TVp7OFpaNp7lkYyH5j8AxB" alt="How to Add Push Notifications to a Flutter App" width="880" height="390"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Choose Flutter as your target SDK.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;&lt;em&gt;Save &amp;amp; Continue&lt;/em&gt;&lt;/strong&gt; again and then click &lt;strong&gt;&lt;em&gt;Done&lt;/em&gt;&lt;/strong&gt; at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UQUAncBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/SYLtgXBKUAImb3MNUWVAoO0VuzFuSJw9-ZQ9OarySTix_pYGiniLb10SueR0-LAEtW7W8rsjmfRHvMVUQuSvVGs6YREP1gvzXs9R_Phs0rgeyzhz2insoyqxR0CuCdQth4vEaHWO" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UQUAncBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/SYLtgXBKUAImb3MNUWVAoO0VuzFuSJw9-ZQ9OarySTix_pYGiniLb10SueR0-LAEtW7W8rsjmfRHvMVUQuSvVGs6YREP1gvzXs9R_Phs0rgeyzhz2insoyqxR0CuCdQth4vEaHWO" alt="How to Add Push Notifications to a Flutter App" width="880" height="356"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;View your app ID in OneSignal to finish the Google Android FCM configuration process.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, you should see your app dashboard on OneSignal under the _ &lt;strong&gt;Settings&lt;/strong&gt; &lt;em&gt;&amp;gt;&lt;/em&gt; &lt;strong&gt;Platforms&lt;/strong&gt; _ tab. On this page under _ &lt;strong&gt;Native App&lt;/strong&gt; _ _ &lt;strong&gt;platforms&lt;/strong&gt; &lt;em&gt;, you should see an **_Active&lt;/em&gt;** tag next to _ &lt;strong&gt;Google Android,&lt;/strong&gt; _ which means you’re ready to send notifications to users using the Android version of your Flutter app. If you followed the iOS setup, you should see an _ &lt;strong&gt;Active&lt;/strong&gt; _ tag next to _ &lt;strong&gt;Apple iOS&lt;/strong&gt; _.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bOKNeprp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/dfx8y7Ye_Ce1QSPauqCq4s9ULg8MDI6vA8_dkjjFMB3-vgOWyGvRfWZSIA5GRFx7qwIFNf88OkEZ71R6V0Xtd1DcwpFeIUBOck3VFkdHz3Ck3Sf3-dW3IeJ4d9chg08Ur5HPei5U" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bOKNeprp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/dfx8y7Ye_Ce1QSPauqCq4s9ULg8MDI6vA8_dkjjFMB3-vgOWyGvRfWZSIA5GRFx7qwIFNf88OkEZ71R6V0Xtd1DcwpFeIUBOck3VFkdHz3Ck3Sf3-dW3IeJ4d9chg08Ur5HPei5U" alt="How to Add Push Notifications to a Flutter App" width="880" height="420"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An "Active" tag is displayed next to Google Android in the OneSignal dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 2: Creating a Flutter App
&lt;/h2&gt;

&lt;p&gt;So the first thing you need to do after creating a new Flutter project is to add the &lt;code&gt;onesignal_flutter&lt;/code&gt; dependency. To do that, visit &lt;a href="https://pub.dev/"&gt;pub.dev&lt;/a&gt; and search for &lt;strong&gt;&lt;em&gt;onesignal_flutter&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cYWYAPNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/b6AGMy9QnDBPYEgM4Eb5ik9UbU6Dis24p3W2-VhGAo7PUUwT7ekALaYP1CY_lQBeFvA5j6QovvAErgLmzQKuvyJ_0wixkiLsqPM43VbwWYzyUnlKV-YrsLrPXgCbcqDPwVrQ0ZXv" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cYWYAPNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/b6AGMy9QnDBPYEgM4Eb5ik9UbU6Dis24p3W2-VhGAo7PUUwT7ekALaYP1CY_lQBeFvA5j6QovvAErgLmzQKuvyJ_0wixkiLsqPM43VbwWYzyUnlKV-YrsLrPXgCbcqDPwVrQ0ZXv" alt="How to Add Push Notifications to a Flutter App" width="880" height="365"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Shows onesignal_flutter 3.2.7 in pub.dev.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Add the latest version of &lt;code&gt;onesignal_flutter&lt;/code&gt; to &lt;code&gt;pubspec.yaml&lt;/code&gt; under the dependencies section with the version number from pub.dev.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--knGAiIDa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/Wp19ZvWDqfDQLnCkiaoCMbmMoqn-4D7LjHSVn03MdclYlQek5_3fA_WliBvaA1ceFvrL2rseaK0PJ2uytpodAL_hkalirkQb1ShSsq1r51uvtUqYj5uGEodXSdJJUR6efEZfBEUE" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--knGAiIDa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/Wp19ZvWDqfDQLnCkiaoCMbmMoqn-4D7LjHSVn03MdclYlQek5_3fA_WliBvaA1ceFvrL2rseaK0PJ2uytpodAL_hkalirkQb1ShSsq1r51uvtUqYj5uGEodXSdJJUR6efEZfBEUE" alt="How to Add Push Notifications to a Flutter App" width="880" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now open &lt;code&gt;main.dart&lt;/code&gt; and remove &lt;code&gt;MyHomePage()&lt;/code&gt; class (or just its contents).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FGzuSXUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/9vBLaNXdBvwEfBfJV5WrZXHpkUob1UffT3-t7BHSuGqtM5QGxcK3BEEs7LCTHH0mqSAOXZ5PhKbbrfmpYIRKMgL4BBRsyM000KzTL481jKF2Dynf28eKoFJZkLaOvqMMuzNtlAAB" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FGzuSXUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/9vBLaNXdBvwEfBfJV5WrZXHpkUob1UffT3-t7BHSuGqtM5QGxcK3BEEs7LCTHH0mqSAOXZ5PhKbbrfmpYIRKMgL4BBRsyM000KzTL481jKF2Dynf28eKoFJZkLaOvqMMuzNtlAAB" alt="How to Add Push Notifications to a Flutter App" width="880" height="453"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Remove the content of MyHomePage() from main.dart.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Create a new dart file named &lt;code&gt;home.dart&lt;/code&gt; (or continue in the &lt;code&gt;main.dart&lt;/code&gt; file) and create a stateful widget by the name &lt;code&gt;Home&lt;/code&gt; 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;class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
_HomeState createState() =&amp;gt; _HomeState();
}
class _HomeState extends State&amp;lt;Home&amp;gt; {
@override
Widget build(BuildContext context) {
return Container();
}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, build a simple UI by adding a few widgets like &lt;code&gt;Container&lt;/code&gt;, &lt;code&gt;Column&lt;/code&gt; and &lt;code&gt;Text&lt;/code&gt; in the &lt;code&gt;Home class&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;@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text("Hello"),
],
),
),
);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can add the &lt;strong&gt;&lt;em&gt;OneSignal App ID&lt;/em&gt;&lt;/strong&gt; which you can find in your OneSignal dashboard under the &lt;strong&gt;&lt;em&gt;Keys &amp;amp; IDs&lt;/em&gt;&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c291on8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/yqe9Or5bCachnjJN4PJeDNgV4gRnNdj0aTgCnQxewYEHX5u2n3gtfDK-Ie49aP0lnrY0ULOAmxPnPtdIcnABwKiO8dT8JSnPjcFkkyrUDYTYZqwZJc7gdtdbAtXHjBnQfcPuSElA" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c291on8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/yqe9Or5bCachnjJN4PJeDNgV4gRnNdj0aTgCnQxewYEHX5u2n3gtfDK-Ie49aP0lnrY0ULOAmxPnPtdIcnABwKiO8dT8JSnPjcFkkyrUDYTYZqwZJc7gdtdbAtXHjBnQfcPuSElA" alt="How to Add Push Notifications to a Flutter App" width="880" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;strong&gt;&lt;em&gt;OneSignal App ID&lt;/em&gt;&lt;/strong&gt; and add it into your Flutter app in &lt;code&gt;main.dart&lt;/code&gt; as a constant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static final String oneSignalAppId = "16090413-4b70-4c0b-a9f4-dd43c445ccee";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add SDK initialization code to your &lt;code&gt;XXX&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;Future&amp;lt;void&amp;gt; initPlatformState() async {
   OneSignal.shared.setAppId(oneSignalAppId);
   OneSignal.shared
       .promptUserForPushNotificationPermission()
       .then((accepted) {});
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, initialize state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
 void initState() {
   super.initState();
   initPlatformState();
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Complete Code(main.dart)
&lt;/h3&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';

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

 @override
 _HomeState createState() =&amp;gt; _HomeState();
}

class _HomeState extends State&amp;lt;Home&amp;gt; {
 @override
 void initState() {
   super.initState();
   initPlatformState();
 }

 static final String oneSignalAppId = "16090413-4b70-4c0b-a9f4-dd43c445ccee";
 Future&amp;lt;void&amp;gt; initPlatformState() async {
   OneSignal.shared.setAppId(oneSignalAppId);
   OneSignal.shared
       .promptUserForPushNotificationPermission()
       .then((accepted) {});
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     body: Container(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         crossAxisAlignment: CrossAxisAlignment.center,
         children: const [
           Text("Hello"),
         ],
       ),
     ),
   );
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your Flutter app on your physical device or emulator.&lt;/p&gt;

&lt;p&gt;In case you recieve &lt;code&gt;compileSdkVersion error&lt;/code&gt; then go to your &lt;code&gt;app-level build.gradle&lt;/code&gt; file and update &lt;code&gt;compileSDKVersion&lt;/code&gt; to &lt;strong&gt;31&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;defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.flutter_onesignal"
minSdkVersion 16
compileSdkVersion 31
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get &lt;code&gt;Kotlin Version error&lt;/code&gt; then go to your &lt;code&gt;build.gradle&lt;/code&gt; file in the root of your Android directory and upgrade your &lt;code&gt;Kotlin_version&lt;/code&gt; to the latest version (&lt;code&gt;ext.kotlin_version = '1.5.10'&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;For the iOS version, there’s are some additional steps that need to be completed. The first one is to add an iOS service extension.&lt;/p&gt;

&lt;p&gt;The OneSignalNotificationServiceExtension allows your application (in iOS) to receive rich notifications with images and buttons, along with badges and &lt;a href="https://documentation.onesignal.com/docs/confirmed-deliveries"&gt;Confirmed Deliveries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first step is to navigate to your Flutter project's iOS folder and open the &lt;code&gt;.xcworkspace&lt;/code&gt; file in Xcode. You can use the &lt;code&gt;open ios/Runner.xcworkspace&lt;/code&gt; command in the terminal to do the same.&lt;/p&gt;

&lt;p&gt;Then select &lt;strong&gt;&lt;em&gt;File&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;New&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;Target&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KCoAsNB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/2ahVy90kNsCUL-FvxQhdZnD_1BMhepqGL27kHRoiawMzuYssIT0jYtMIPxLm3-iJkAcioce66I_RJj4hAYqI7RGLmNCf5xC9iNy8YJy1ZYdIIJpcHizth0GeSB3wOgxpGfuQ9xpK" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KCoAsNB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/2ahVy90kNsCUL-FvxQhdZnD_1BMhepqGL27kHRoiawMzuYssIT0jYtMIPxLm3-iJkAcioce66I_RJj4hAYqI7RGLmNCf5xC9iNy8YJy1ZYdIIJpcHizth0GeSB3wOgxpGfuQ9xpK" alt="How to Add Push Notifications to a Flutter App" width="880" height="637"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;&lt;em&gt;Notification Service Extension&lt;/em&gt;&lt;/strong&gt; and press &lt;strong&gt;&lt;em&gt;Next&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KYJ2te2f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/-HhMpA3cmMlEDakFbw55JB1QVkHfpYDG-aUYtrqLYfZc9GQJrsXVSmfuKRGBUkouYNm-MOoyLNV6DPi8Jzh6SmBKAqv5bSzL4e-TkA0ksFLt3UHDjt0OEbaPODqYxfjZ8AcjWCDP" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KYJ2te2f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/-HhMpA3cmMlEDakFbw55JB1QVkHfpYDG-aUYtrqLYfZc9GQJrsXVSmfuKRGBUkouYNm-MOoyLNV6DPi8Jzh6SmBKAqv5bSzL4e-TkA0ksFLt3UHDjt0OEbaPODqYxfjZ8AcjWCDP" alt="How to Add Push Notifications to a Flutter App" width="880" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the product name as &lt;strong&gt;&lt;em&gt;OneSignalNotificationExtension&lt;/em&gt;&lt;/strong&gt; and change the language to _ &lt;strong&gt;Object-C&lt;/strong&gt; _ or &lt;strong&gt;&lt;em&gt;Swift&lt;/em&gt;&lt;/strong&gt; according to your needs. The team account should be your account or your organization’s account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b34Tgg93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/1akC8xbAiWfhyifJMOCqso3-eW9m3hhHcpRGqu4qanre1Q997EIPGvP5yN0VJFjxJkgfeDN24oAd6z_-NIDQ0S3yUEhtiTQUTHIRISxaBg5R-fQiFPsj7cxeTkJ4FArjOnz3BRDE" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b34Tgg93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/1akC8xbAiWfhyifJMOCqso3-eW9m3hhHcpRGqu4qanre1Q997EIPGvP5yN0VJFjxJkgfeDN24oAd6z_-NIDQ0S3yUEhtiTQUTHIRISxaBg5R-fQiFPsj7cxeTkJ4FArjOnz3BRDE" alt="How to Add Push Notifications to a Flutter App" width="880" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Add the product name as OneSignalNotificationExtension in Flutter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the _ &lt;strong&gt;Finish&lt;/strong&gt; _ at the bottom right corner of the window, but when prompted to “Activate” scheme click on _ &lt;strong&gt;Cancel&lt;/strong&gt; _.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uZEJ1mrX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/_lrzrxMW6I41eYSoPBx5kGdmk2j1HYCZHr64toNYOzwFevPFi68e8zZez_hw4Feqzido91O5Ks_c5CYe8s0BjYfFwCCZG21g332n-X53JqjujSIRjeH5qZovFnQj8k0XYf_H3UaP" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uZEJ1mrX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/_lrzrxMW6I41eYSoPBx5kGdmk2j1HYCZHr64toNYOzwFevPFi68e8zZez_hw4Feqzido91O5Ks_c5CYe8s0BjYfFwCCZG21g332n-X53JqjujSIRjeH5qZovFnQj8k0XYf_H3UaP" alt="How to Add Push Notifications to a Flutter App" width="880" height="930"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Click "Cancel" when prompted to activate the scheme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By canceling, you are keeping Xcode set to debug your app rather than using the extension. If you select _ &lt;strong&gt;Activate&lt;/strong&gt; _ by accident, you can simply switch back to debug your app in Xcode (next to the Play button).&lt;/p&gt;

&lt;p&gt;Now, open the Xcode project settings and select the _ &lt;strong&gt;OneSignalNotificationServiceExtension&lt;/strong&gt; _ target. Under the _ &lt;strong&gt;Deployment info&lt;/strong&gt; _ section on this page, select iOS 10.0 as the target unless there are any reason for using higher versions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_CwebazN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/pm2Nwawvmko5SA50hUUKzzLEdWA4yVF83qTSk4ORSLGgu7xWVY2ahRKiNls8xidSL6wcI2E4SchyoRr0nzpUnaS9bCBBzN0iDWCYmaSock0CRJrDLBplqx3Wxs6g6ZqlhOBXUYIw" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_CwebazN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/pm2Nwawvmko5SA50hUUKzzLEdWA4yVF83qTSk4ORSLGgu7xWVY2ahRKiNls8xidSL6wcI2E4SchyoRr0nzpUnaS9bCBBzN0iDWCYmaSock0CRJrDLBplqx3Wxs6g6ZqlhOBXUYIw" alt="How to Add Push Notifications to a Flutter App" width="880" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, close the Xcode project and go back to your Flutter development IDE. In the &lt;code&gt;/ios&lt;/code&gt; directory of your project, open the &lt;strong&gt;&lt;em&gt;Podfile&lt;/em&gt;&lt;/strong&gt; and add the following lines outside of the main target (they should be at the same level as your main target):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target 'OneSignalNotificationServiceExtension' do
use_frameworks!
pod 'OneSignalXCFramework', '&amp;gt;= 3.4.3', '&amp;lt; 4.0'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DbProiqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/YYa5t-_B9sK-Ca-tdjFUxSfnB0iumq7FPZ86YKkJty66WTyw5liQTv_dKyjcznYXOhxOvG2SYUfKZ7yvmzZWjP7uau9CzHdmicoWKIbWnpAL4Hwy8TOr-VUrBK0V5KTt6T8Hq0K_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DbProiqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/YYa5t-_B9sK-Ca-tdjFUxSfnB0iumq7FPZ86YKkJty66WTyw5liQTv_dKyjcznYXOhxOvG2SYUfKZ7yvmzZWjP7uau9CzHdmicoWKIbWnpAL4Hwy8TOr-VUrBK0V5KTt6T8Hq0K_" alt="How to Add Push Notifications to a Flutter App" width="880" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, make sure to uncomment the platform line at the top of the &lt;strong&gt;&lt;em&gt;Podfile&lt;/em&gt;.&lt;/strong&gt; It can be iOS version 9.0 or higher according to your needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lUqMNHPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/kbNDzO4R_o82ntNP04yqr07iV1ajyFDc3TQsqq07dNfbR77ZvI_2aV8oDdNNDIN1_PBHXD4CsFkQlnS7hzmLBGAjwCXp_6bO6y61QkwxG4_Jv40aENiwASNujDLTM2OfxXLd-JH7" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lUqMNHPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/kbNDzO4R_o82ntNP04yqr07iV1ajyFDc3TQsqq07dNfbR77ZvI_2aV8oDdNNDIN1_PBHXD4CsFkQlnS7hzmLBGAjwCXp_6bO6y61QkwxG4_Jv40aENiwASNujDLTM2OfxXLd-JH7" alt="How to Add Push Notifications to a Flutter App" width="880" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now Open the terminal, cd to the ios directory, and run pod install.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7p7kULp3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/bMNOc-BQBzq0F19UZg-Q2ctZGX2M43GB3xLx5pgnOEOZLn2PNXiNotZGZ0vkXng0c8M-qkE_Vd8cc2NqMEwQVbDBW6tRioxz7XS9TrEJlOkRGdFaXeMf4_ChF6hppuQ13dWFnjW9" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7p7kULp3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/bMNOc-BQBzq0F19UZg-Q2ctZGX2M43GB3xLx5pgnOEOZLn2PNXiNotZGZ0vkXng0c8M-qkE_Vd8cc2NqMEwQVbDBW6tRioxz7XS9TrEJlOkRGdFaXeMf4_ChF6hppuQ13dWFnjW9" alt="How to Add Push Notifications to a Flutter App" width="880" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see the error below, remove &lt;code&gt;#&lt;/code&gt; from the above in front of &lt;code&gt;use_frameworks!&lt;/code&gt; and try again.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;- Runner (true) and OneSignalNotificationServiceExtension (false) do not both set use_frameworks!.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;&amp;lt;project-name&amp;gt;.xcworkspace&lt;/code&gt; file. In your project, in the &lt;code&gt;OneSignalNotificationServiceExtension/&lt;/code&gt; folder, open &lt;code&gt;NotificationService.m&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mh9P5mko--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/6LNQ1cUOlh4Wsp4rVr6Y1wgVPtDCRpgOR48BWeTqtoOHrEoUGHReEyN5sVJfha1SqbEa1tV4G0KAqnHhSQxvvb8-oNttLBTGk6EKvSAQhtgfjta_N5EmFqln7Bg0anT_c7HxUVp4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mh9P5mko--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/6LNQ1cUOlh4Wsp4rVr6Y1wgVPtDCRpgOR48BWeTqtoOHrEoUGHReEyN5sVJfha1SqbEa1tV4G0KAqnHhSQxvvb8-oNttLBTGk6EKvSAQhtgfjta_N5EmFqln7Bg0anT_c7HxUVp4" alt="How to Add Push Notifications to a Flutter App" width="708" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Replace the whole file contents with the following code for Objective-C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#import &amp;lt;OneSignal/OneSignal.h&amp;gt;
#import "NotificationService.h"
@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNNotificationRequest *receivedRequest;
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
   self.receivedRequest = request;
   self.contentHandler = contentHandler;
   self.bestAttemptContent = [request.content mutableCopy];

   //If your SDK version is &amp;lt; 3.5.0 uncomment and use this code:
   /*
   [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest
                      withMutableNotificationContent:self.bestAttemptContent];
   self.contentHandler(self.bestAttemptContent);
   */

   /* DEBUGGING: Uncomment the 2 lines below and comment out the one above to ensure this extension is excuting
                 Note, this extension only runs when mutable-content is set
                 Setting an attachment or action buttons automatically adds this */
   // NSLog(@"Running NotificationServiceExtension");
   // self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body];

   // Uncomment this line to set the default log level of NSE to VERBOSE so we get all logs from NSE logic
   //[OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_NONE];
   [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest
                      withMutableNotificationContent:self.bestAttemptContent
                                  withContentHandler:self.contentHandler];
}
- (void)serviceExtensionTimeWillExpire {
   // Called just before the extension will be terminated by the system.
   // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.

   [OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];

   self.contentHandler(self.bestAttemptContent);
}
@end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Swift, replace it with:&lt;br&gt;
&lt;/p&gt;

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

import OneSignal

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 {
           //If your SDK version is &amp;lt; 3.5.0 uncomment and use this code:
           /*
           OneSignal.didReceiveNotificationExtensionRequest(self.receivedRequest, with: self.bestAttemptContent)
           contentHandler(bestAttemptContent)
           */

           /* DEBUGGING: Uncomment the 2 lines below to check this extension is excuting
                         Note, this extension only runs when mutable-content is set
                         Setting an attachment or action buttons automatically adds this */
           //OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)
           //bestAttemptContent.body = "[Modified] " + bestAttemptContent.body

           OneSignal.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
       }
   }

   override func serviceExtensionTimeWillExpire() {
       // Called just before the extension will be terminated by the system.
       // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
       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;You also need to enable an &lt;strong&gt;App Group&lt;/strong&gt; to use &lt;a href="https://documentation.onesignal.com/docs/confirmed-deliveries"&gt;Confirmed Deliveries&lt;/a&gt; and increment/decrement &lt;a href="https://documentation.onesignal.com/docs/badges"&gt;Badges&lt;/a&gt; through push notifications. For that, you can follow the &lt;a href="https://documentation.onesignal.com/docs/ios-sdk-app-groups-setup"&gt;iOS SDK App Groups setup guide&lt;/a&gt; to add the OneSignal App Group in your app.&lt;/p&gt;

&lt;p&gt;Now you need to enable &lt;strong&gt;push capability for iOS apps&lt;/strong&gt;. Open your &lt;code&gt;.xcworkspace file&lt;/code&gt; in Xcode.&lt;/p&gt;

&lt;p&gt;In the main app target, select &lt;strong&gt;&lt;em&gt;Signing &amp;amp; Capabilities&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;All&lt;/em&gt;&lt;/strong&gt; &amp;gt; &lt;strong&gt;&lt;em&gt;+ Capability&lt;/em&gt;&lt;/strong&gt; and then search "push." Double-click on _ &lt;strong&gt;Push Notifications&lt;/strong&gt; _ to enable it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IMNfvYae--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/DWJI_pmSWCdbnZCYSqZbJRjrQk1qfmCaT1KHQRTxeTfVJBBKgL9_AVB6j4SdLjTsZEymjfrXu9orM9T7NzfxFQew2_yI6H_TCgtjk4RlpXSKi9d-jldSLpRL93ozoRPMbOmfttcX" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IMNfvYae--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/DWJI_pmSWCdbnZCYSqZbJRjrQk1qfmCaT1KHQRTxeTfVJBBKgL9_AVB6j4SdLjTsZEymjfrXu9orM9T7NzfxFQew2_yI6H_TCgtjk4RlpXSKi9d-jldSLpRL93ozoRPMbOmfttcX" alt="How to Add Push Notifications to a Flutter App" width="880" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, enable &lt;strong&gt;&lt;em&gt;Background Modes&lt;/em&gt;&lt;/strong&gt; and check &lt;strong&gt;&lt;em&gt;Remote Notifications&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O6pGTd_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/oaedkTvazpCH9OaAEJ2mTnEH1k5KCcDkuDEWzBgQTSIRUNa1gUJji9G9ljuXsZEXIhctWjSPIG5sUY4TKx28dn7juuDPrA8BHSU1H-a51Kdr7157o-PLOKLovp6w7mIJT-5zuppa" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O6pGTd_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/oaedkTvazpCH9OaAEJ2mTnEH1k5KCcDkuDEWzBgQTSIRUNa1gUJji9G9ljuXsZEXIhctWjSPIG5sUY4TKx28dn7juuDPrA8BHSU1H-a51Kdr7157o-PLOKLovp6w7mIJT-5zuppa" alt="How to Add Push Notifications to a Flutter App" width="880" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you are ready to send notifications from the OneSignal dashboard!&lt;/p&gt;

&lt;p&gt;Back in your OneSignal dashboard, click on &lt;strong&gt;Messages&lt;/strong&gt; in the top navigation menu and select _ &lt;strong&gt;Push&lt;/strong&gt; _ from the sub-menu. Click the &lt;strong&gt;&lt;em&gt;+New Push&lt;/em&gt;&lt;/strong&gt; button to create your first notification.&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"&gt;enable them again&lt;/a&gt;. If you're sending a notification to an iOS device, you will need to opt-in to notifications in your app settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--99MlZA1I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/q5c86f4bIcxmL3rgkG-z-82Go1BiAnOQMLniEecZZBe0rUUewtF8bBY_HuXB83HDS2_AqkBIuvZjn9QoohdwVJAwwM8Sjb-tBD4VSaSyRbxwWm6KrEClQg7wJeR85dSHl8bUe8o_" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--99MlZA1I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/q5c86f4bIcxmL3rgkG-z-82Go1BiAnOQMLniEecZZBe0rUUewtF8bBY_HuXB83HDS2_AqkBIuvZjn9QoohdwVJAwwM8Sjb-tBD4VSaSyRbxwWm6KrEClQg7wJeR85dSHl8bUe8o_" alt="How to Add Push Notifications to a Flutter App" width="880" height="213"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Click the "+New Push" button in your OneSignal dashboard.&lt;/em&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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cv__N2yr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/DniDr03ChMf0gKDZF5slIh9qavCZlMNmm4yFdDHQS4Jowjh2NP3NzJ-Qyf8SfR-5am7PUbkY5dy0TlIXj7RxuQox8UAWvGs4Wnmn5W752ISgtaO1pCw-ENOiRC5JZF2poo1Q2aUr" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cv__N2yr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/DniDr03ChMf0gKDZF5slIh9qavCZlMNmm4yFdDHQS4Jowjh2NP3NzJ-Qyf8SfR-5am7PUbkY5dy0TlIXj7RxuQox8UAWvGs4Wnmn5W752ISgtaO1pCw-ENOiRC5JZF2poo1Q2aUr" alt="How to Add Push Notifications to a Flutter App" width="880" height="419"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Specify the audience for your push notification in OneSignal.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Add your message title and copy and preview how your message looks on your target device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ctvClu1R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/9xiwSSoMPYiEmP0i67DsfmKl5RskyDhPCPxiKkBgIIpRHE0u37n3XFakDxcwIpT5g8IPVCTRv5EPpJke1H25dFd2IKe9MG-mMHl_0Cuh7bLcrOoj_9WMpTlckRZKU1p0gCQU01u3" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ctvClu1R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/9xiwSSoMPYiEmP0i67DsfmKl5RskyDhPCPxiKkBgIIpRHE0u37n3XFakDxcwIpT5g8IPVCTRv5EPpJke1H25dFd2IKe9MG-mMHl_0Cuh7bLcrOoj_9WMpTlckRZKU1p0gCQU01u3" alt="How to Add Push Notifications to a Flutter App" width="880" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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://res.cloudinary.com/practicaldev/image/fetch/s--OVSA7Ds6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/34f-jBgJ13ypRXN0N_FoonL73H8qScgqUENeOPK6hp7MU4fGyn0KCeAsftUlB71jh5kdQwuiQP5_Rw5nH7IL60nUrkV-DFBo7EABsKnDMRg-P9UC-S6pqrCkBGmhnCj0tb7D1AhF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OVSA7Ds6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/34f-jBgJ13ypRXN0N_FoonL73H8qScgqUENeOPK6hp7MU4fGyn0KCeAsftUlB71jh5kdQwuiQP5_Rw5nH7IL60nUrkV-DFBo7EABsKnDMRg-P9UC-S6pqrCkBGmhnCj0tb7D1AhF" alt="How to Add Push Notifications to a Flutter App" width="880" height="224"&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://res.cloudinary.com/practicaldev/image/fetch/s--1jZBX5a8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/gHVM6DAHNffI_bTGhz1SRB5Sa0bxQUkTCrclZpn6vDALkUpjegZspNGOFBHz0jwZmiQpAup_xDBlXmFg1EURwCVRW0S5bramwtss3rH6GJWRZCjjylW24ZaIuhkHjbKjPOwMWkZG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1jZBX5a8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/gHVM6DAHNffI_bTGhz1SRB5Sa0bxQUkTCrclZpn6vDALkUpjegZspNGOFBHz0jwZmiQpAup_xDBlXmFg1EURwCVRW0S5bramwtss3rH6GJWRZCjjylW24ZaIuhkHjbKjPOwMWkZG" alt="How to Add Push Notifications to a Flutter App" width="880" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’re done &lt;strong&gt;🎊&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;You’ll receive the notification on your physical device that you used to run your Flutter app or on the emulator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P3fhGWgL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/Sbz_v6cItylXPlj4D2BvbajJwSX_uGXsvOsriLB9ZjWs4tgB6gmXJrJOaGOWWwN9VccqZMPlJDCLqvuxI5TuRZPLI5ZUGpaoiuTXiqt6Pz49-DGH3V3sVlF2gERENOXgUqE_TMve" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P3fhGWgL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/Sbz_v6cItylXPlj4D2BvbajJwSX_uGXsvOsriLB9ZjWs4tgB6gmXJrJOaGOWWwN9VccqZMPlJDCLqvuxI5TuRZPLI5ZUGpaoiuTXiqt6Pz49-DGH3V3sVlF2gERENOXgUqE_TMve" alt="How to Add Push Notifications to a Flutter App" width="880" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the message sends, you'll be directed to the &lt;strong&gt;&lt;em&gt;Delivery&lt;/em&gt;&lt;/strong&gt; page where you can view the send report and track engagement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Still have questions?
&lt;/h3&gt;

&lt;p&gt;Check out our complete &lt;a href="https://documentation.onesignal.com/docs/flutter-sdk-setup"&gt;OneSignal Flutter SDK Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post was guest authored by &lt;strong&gt;Akanksha Singh&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>mobiledev</category>
      <category>flutter</category>
      <category>dart</category>
      <category>programmer</category>
    </item>
    <item>
      <title>iOS Web Push Notification support is coming soon in 2022</title>
      <dc:creator>George Deglin</dc:creator>
      <pubDate>Tue, 01 Feb 2022 22:36:38 +0000</pubDate>
      <link>https://forem.com/onesignal/ios-web-push-notification-support-is-coming-soon-in-2022-1hp4</link>
      <guid>https://forem.com/onesignal/ios-web-push-notification-support-is-coming-soon-in-2022-1hp4</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uPSTU-8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/ios-web-push-support-coming-soon--1-.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uPSTU-8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/ios-web-push-support-coming-soon--1-.jpg" alt="iOS Web Push Notification support is coming soon in 2022" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On January 27, 2022, Apple seeded the first Beta of iOS 15.4 featuring several updates— including one that we've been looking forward to for a long time.&lt;/p&gt;

&lt;p&gt;iOS 15.4 is expected to introduce many new features, including support for Face ID with a Mask, new emojis, and updates to built-in apps such as Notes and AppleTV.&lt;/p&gt;

&lt;p&gt;However, the most exciting addition is &lt;strong&gt;experimental support for iOS web push notifications&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PmJDtYXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/ios-web-push--2-.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PmJDtYXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/ios-web-push--2-.jpg" alt="iOS Web Push Notification support is coming soon in 2022" width="880" height="671"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The setting to enable Web Notifications support in Safari (WebKit) Preferences can be seen on an iOS 15.4 device running in the Xcode Device Simulator&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Web push notifications are a popular communication channel &lt;a href="https://trends.builtwith.com/widgets/push-notifications"&gt;used by more than 8% of top websites&lt;/a&gt;. They provide an essential mechanism for websites to send timely and personalized messages to users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GXA72jcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GXA72jcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2022/02/image-2.png" alt="iOS Web Push Notification support is coming soon in 2022" width="880" height="431"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An example of Web Push notifications being used to send sports and Covid news stores on a both Windows and an Android Device&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nearly every operating system supports this valuable communication channel. Unfortunately, until recently, Apple was a significant outlier and showed little interest in allowing web push on iOS devices. In the past, Apple has faced &lt;a href="https://onesignal.com/blog/apples-plans-to-support-ios-web-push-in-2021/"&gt;pushback&lt;/a&gt; for falling behind on supporting modern web APIs, including web push.&lt;/p&gt;

&lt;p&gt;Considering that Apple owns &lt;a href="https://www.statista.com/statistics/266572/market-share-held-by-smartphone-platforms-in-the-united-states/"&gt;52%&lt;/a&gt; of the mobile market in the United States and a similarly large market share worldwide, this limitation has dramatically slowed the adoption and utility of web push notifications. As a result, websites have resorted to pressuring users to download apps or provide either an email or SMS number to receive messages.&lt;/p&gt;

&lt;p&gt;This latest addition to iOS 15.4 Beta is a promising sign that Apple will finally enable web push support in Safari on iOS and allow its use in other iOS browsers such as Chrome and Firefox.&lt;/p&gt;

&lt;p&gt;In our tests of this new Beta capability in iOS 15.4, we've determined that web push is disabled by default, and unfortunately, enabling it does not yet work. However, this the introduction of this new option and the newly introduced iOS web push APIs are strong signs that Apple is actively working on introducing full web push support.&lt;/p&gt;

&lt;p&gt;Although the public launch of iOS 15.4 is slated for April 2022, web push support  likely won't be available until later, possibly in iOS 16. If this prediction is correct, we'll see iOS web push introduced with the public launch of iOS 16 in September 2022.&lt;/p&gt;

&lt;p&gt;That might be a while to wait, but nonetheless we're incredibly excited for the opportunities this will unlock for better and more user-friendly mobile web experiences. The OneSignal team is following this news closely and will ensure that all OneSignal customers are prepared to seamlessly leverage web push on iOS when it's available.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ios</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Add Push Notifications to a Vue App</title>
      <dc:creator>William Shepherd</dc:creator>
      <pubDate>Wed, 22 Dec 2021 23:08:44 +0000</pubDate>
      <link>https://forem.com/onesignal/how-to-add-push-notifications-to-a-vue-app-mke</link>
      <guid>https://forem.com/onesignal/how-to-add-push-notifications-to-a-vue-app-mke</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wuv5LDEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2021/12/add-push-notifications-to-a-vue-app-4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wuv5LDEG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2021/12/add-push-notifications-to-a-vue-app-4.jpg" alt="How to Add Push Notifications to a Vue App" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide will help you quickly add push notifications to your Vue application (for free) with the OneSignal-Vue plugin. To follow this tutorial, you will need to have some working knowledge of Vue 2 and its tooling. The focus of this guide is to demonstrate how to push a notification to a Vue app. It does not cover how to create a new Vue app; for that, please refer to Vue's documentation on &lt;a href="https://cli.vuejs.org/guide/creating-a-project.html"&gt;how to create a new Vue project&lt;/a&gt;.&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;Web Configuration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Part 2: Configure Your Vue Application&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Initializing the OneSignal Vue Plugin&lt;/li&gt;
&lt;li&gt;Using the Plugin on Components&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Share Your Feedback&lt;/strong&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"&gt;log in&lt;/a&gt; to your OneSignal account. If you don't have a OneSignal account, you can easily &lt;a href="https://app.onesignal.com/signup"&gt;create a free account&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;To begin, log in to your OneSignal account and click the _ &lt;strong&gt;New App/Website&lt;/strong&gt; _ button on the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---TEX36Y8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/30rSEw3USzJOb2Xt7gr_AH9M7dWQQBYBWOOfCwT4oVNJAowzpvDhbeKThTIpSp-zrzjUd7lFxotlCujJ4MFKBZeULraqvVF9Wg4_5Mr-EW6FgpUoTl8nLgw619zbROKes39Pa2DH" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---TEX36Y8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/30rSEw3USzJOb2Xt7gr_AH9M7dWQQBYBWOOfCwT4oVNJAowzpvDhbeKThTIpSp-zrzjUd7lFxotlCujJ4MFKBZeULraqvVF9Wg4_5Mr-EW6FgpUoTl8nLgw619zbROKes39Pa2DH" alt="How to Add Push Notifications to a Vue App" width="880" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name your app and select &lt;strong&gt;&lt;em&gt;Web&lt;/em&gt;&lt;/strong&gt; as your platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--keyFuoBv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/54HpXgwPpt9ws3onwihy4Q0QbLNkK4v-Fm--xuMpzxkf4f-tH_d0dTRtD08442qmW7SyYfEqECR995fI_oreF0HjmeN9lVat3w9Q0_Hz0KH6zWGGdt7pwCj1IaPPz0oeIrMi7uW5" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--keyFuoBv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/54HpXgwPpt9ws3onwihy4Q0QbLNkK4v-Fm--xuMpzxkf4f-tH_d0dTRtD08442qmW7SyYfEqECR995fI_oreF0HjmeN9lVat3w9Q0_Hz0KH6zWGGdt7pwCj1IaPPz0oeIrMi7uW5" alt="How to Add Push Notifications to a Vue App" width="880" height="891"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the button labeled, &lt;strong&gt;&lt;em&gt;Next: Configure Your Platform&lt;/em&gt;&lt;/strong&gt; so you can choose how you'd like to integrate into your Vue app.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;Web Configuration&lt;/em&gt;&lt;/strong&gt; window, select the &lt;strong&gt;&lt;em&gt;Custom Code&lt;/em&gt;&lt;/strong&gt; integration option and provide a name you'd like to use to refer to your website along with the site URL where the app is hosted. If you don't know your site URL yet, don't worry —you can set it to your localhost and update it once you deploy your Vue app.&lt;/p&gt;

&lt;p&gt;In the meantime, enable _ &lt;strong&gt;Auto Resubscribe&lt;/strong&gt; _ by moving the toggle to the right to ensure that your dev build always gets notified even when you clear your browser’s data. You'll also need to enable _ &lt;strong&gt;Local Testing&lt;/strong&gt; _ so that you can receive push notifications on your dev machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0u6keY01--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/4SoFfEjjqUmsOtSaIhZ0q-qihGn-oNmkt-5r2m2X59_QoFEnghfgOph_9Pnu9E7q4yoxjIeFbv8w-4M-64hndZVge84kYPo4rgzoWub6o3COSg82tdnPMnUxAi4WBS458Rs40lAZ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0u6keY01--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/4SoFfEjjqUmsOtSaIhZ0q-qihGn-oNmkt-5r2m2X59_QoFEnghfgOph_9Pnu9E7q4yoxjIeFbv8w-4M-64hndZVge84kYPo4rgzoWub6o3COSg82tdnPMnUxAi4WBS458Rs40lAZ" alt="How to Add Push Notifications to a Vue App" width="880" height="1011"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;&lt;em&gt;Save&lt;/em&gt;&lt;/strong&gt; button to continue the configuration process.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;em&gt;4. Upload Files&lt;/em&gt;&lt;/strong&gt; section, click the &lt;strong&gt;&lt;em&gt;Download OneSignal SDK Files&lt;/em&gt;&lt;/strong&gt; button to get the service workers needed to receive push notifications or &lt;a href="https://github.com/OneSignal/OneSignal-Website-SDK/files/7585231/OneSignal-Web-SDK-HTTPS-Integration-Files.zip"&gt;download the SDK files from our Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yvKmUYhD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/hUL2GGxAKMNMFR6ZIGaYglYYmQs2HKbLxz-sUgBtfsnDp2xpspV85PD9hxtq0UtFPQ2Q2Z7vB2z8mSeE_83SawnGwOxx3Ebfks_TruSVigOljy4iG_wfnfPwqYaXfLH_FPW1ZrbR" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yvKmUYhD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/hUL2GGxAKMNMFR6ZIGaYglYYmQs2HKbLxz-sUgBtfsnDp2xpspV85PD9hxtq0UtFPQ2Q2Z7vB2z8mSeE_83SawnGwOxx3Ebfks_TruSVigOljy4iG_wfnfPwqYaXfLH_FPW1ZrbR" alt="How to Add Push Notifications to a Vue App" width="880" height="914"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Configure Your Vue Application
&lt;/h2&gt;

&lt;p&gt;Now, you can follow the instructions that ship with the &lt;a href="https://www.npmjs.com/package/onesignal-vue"&gt;onesignal-vue package on npm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;onesignal-vue&lt;/code&gt; in your Vue project using your preferred package manager.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;yarn add onesignal-vue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install --save onesignal-vue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Extract the service worker files from the archive you downloaded from the OneSignal dashboard and copy the files into your project’s &lt;code&gt;public&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the OneSignal Vue Plugin
&lt;/h3&gt;

&lt;p&gt;Now you can set up the plugin by modifying &lt;code&gt;main.js&lt;/code&gt; to import the package and initialize the plugin by setting the &lt;code&gt;appId&lt;/code&gt; property to your OneSignal application identifier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Vue from "vue";
import OneSignal from "onesignal-vue";

import App from "./App.vue";

Vue.config.productionTip = false;

Vue.use(OneSignal);

new Vue({
  render: h =&amp;gt; h(App),
  beforeMount() {
    this.$OneSignal.init({
      appId: "&amp;lt;You OneSignal application identifier",
      allowLocalhostAsSecureOrigin: true,
    });
  },
}).$mount("#app");

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using the Plugin on Components
&lt;/h3&gt;

&lt;p&gt;Once initialized, use the plugin on any component you like. For this tutorial, we're going to call it from the &lt;code&gt;HelloWorld.vue&lt;/code&gt; component to present a &lt;a href="https://documentation.onesignal.com/docs/slide-prompt"&gt;slide prompt&lt;/a&gt; that allows visitors to your site to opt-in to push notifications.&lt;/p&gt;

&lt;p&gt;Find the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag and set a callback for the &lt;code&gt;beforeCreate&lt;/code&gt; lifecycle hook in the exported object.&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-vue";
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
  beforeCreate() {
    this.$OneSignal.showSlidedownPrompt();
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The integration is complete. You can test it out by starting the app using &lt;code&gt;yarn serve&lt;/code&gt; then opting into push notifications.&lt;/p&gt;

&lt;p&gt;You should have received a test push notification indicating the integration is successful.&lt;/p&gt;

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

&lt;p&gt;We'd love to know what you think of this plugin and answer any additional questions you have. To connect with us, &lt;a href="https://github.com/OneSignal/onesignal-vue/issues"&gt;create an issue on GitHub&lt;/a&gt; or ping us on the &lt;a href="https://discord.com/invite/EP7gf6Uz7G"&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"&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;
  
  
  &amp;gt;&amp;gt; &lt;a href="https://onesignal.com/onesignal-developers"&gt;Connect with the OneSignal Developer Community&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</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://forem.com/onesignal/how-to-add-android-push-notifications-to-a-react-native-expo-app-4o1k</link>
      <guid>https://forem.com/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>Effective TypeScript for React Applications</title>
      <dc:creator>Graham Marlow</dc:creator>
      <pubDate>Mon, 13 Sep 2021 17:33:00 +0000</pubDate>
      <link>https://forem.com/onesignal/effective-typescript-for-react-applications-40j1</link>
      <guid>https://forem.com/onesignal/effective-typescript-for-react-applications-40j1</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OldHkpYj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2021/09/effective-typescript-for-react-applications.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OldHkpYj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://onesignal.com/blog/content/images/2021/09/effective-typescript-for-react-applications.png" alt="Effective TypeScript for React Applications"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TypeScript and React are excellent in combination. When you sprinkle React’s expressive component model with a little strong typing, you get fewer bugs and an improved developer experience.&lt;/p&gt;

&lt;p&gt;That said, the amount of techniques and nuances baked into the TypeScript/React combo can be overwhelming. TypeScript offers so much flexibility in structuring your React components that it’s hard to know what’s best in which situation. Those familiar with JavaScript may find themselves banging their heads against stubborn compiler warnings. Others may dread the boilerplate mountain that looms over every component.​&lt;/p&gt;

&lt;p&gt;No matter your level of experience with TypeScript, this guide is here to help you out. We’ve listed below our best practices for working with TypeScript and React, which are based on the same patterns used in our core product.&lt;/p&gt;

&lt;h1&gt;
  
  
  Use Interfaces Until You Need a Type
&lt;/h1&gt;

&lt;p&gt;For the most part, you can use type aliases and interfaces interchangeably, as the &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces"&gt;difference between the two&lt;/a&gt; is subtle. You can extend existing interfaces with new properties, whereas type aliases are off-limits after declaration. Despite their similarity, it’s still useful to define a pattern so that you’re using the two styles consistently.&lt;/p&gt;

&lt;p&gt;Here at OneSignal, we follow the heuristic “use interface until you need to use features from type". We recommend interfaces because they offer a familiar syntax for inheritance that mirrors ES2015 classes. In contrast, types are used to alias primitive values or create unions from other types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&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;h1&gt;
  
  
  Unions Over Enums
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Unlike most TypeScript features, [enum] is not a type-level addition to JavaScript but something added to the language and runtime. Because of this, it’s a feature which you should know exists, but maybe hold off on using unless you are sure.&lt;br&gt;&lt;br&gt;
—&lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums"&gt;TypeScript Handbook&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Union types and enums tend to occupy the same space in React in that they both enforce that a particular prop must be one value of a given set. However, we recommend union types over enums for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are compiler-only constructs, so they won't end up in your application's JS bundle.&lt;/li&gt;
&lt;li&gt;They are extensible to other union types.&lt;/li&gt;
&lt;li&gt;They are less verbose.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Avoid enums:&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;PRIMARY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SECONDARY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&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="c1"&gt;// Prefer union types:&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Extensible to other union types:&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ExtendedButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tertiary&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;Now, there are a few caveats to consider with this rule.&lt;/p&gt;

&lt;p&gt;For one, &lt;code&gt;const enum&lt;/code&gt; is a compile-time only enum that doesn’t increase the size of your JS bundle. Unfortunately, &lt;code&gt;const enum&lt;/code&gt; is a &lt;a href="https://www.typescriptlang.org/tsconfig#isolatedModules"&gt;disabled keyword&lt;/a&gt; for certain build tools, like Babel or esbuild.&lt;/p&gt;

&lt;p&gt;You should also consider that union types and enums are not syntactically the same. You can reference the value of an enum by its declaration, avoiding direct references to a string literal. If this behavior is desirable, look to regular JS objects instead. With a handy utility type from &lt;a href="https://github.com/sindresorhus/type-fest"&gt;type-fest&lt;/a&gt;, you can achieve the same behavior.&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;ButtonStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;PRIMARY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;SECONDARY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&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;as&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;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonStyleType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueOf&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;ButtonStyle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Extending Native HTML Elements
&lt;/h1&gt;

&lt;p&gt;TypeScript ships with tons of helper types that cut down boilerplate for common React idioms. These types are particularly useful when extending native HTML elements like &lt;code&gt;button&lt;/code&gt; or &lt;code&gt;input&lt;/code&gt;, where you’ll want to maintain the component's original props to ensure extensibility.&lt;/p&gt;

&lt;p&gt;Start by implementing a &lt;code&gt;Button&lt;/code&gt; component in the two most important use-cases: clicking the button and defining its text. When typing everything manually, you get the following result:&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&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="k"&gt;void&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&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;children&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;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The first helper type to use here is &lt;code&gt;React.PropsWithChildren&lt;/code&gt;, which automatically adds the &lt;code&gt;children&lt;/code&gt; prop to the component:&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;onClick&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="k"&gt;void&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&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;children&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;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Button&lt;/code&gt; is looking better, but the component still has to redefine props that are native to the HTML element, like &lt;code&gt;onClick&lt;/code&gt;. This is a big problem for foundational components like &lt;code&gt;Button&lt;/code&gt; that make up your application’s design system, as their props will grow wildly with their usage.&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="c1"&gt;// This list tends to grow quickly!&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;onClick&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&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;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Luckily, TypeScript has another utility designed for this exact purpose.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ComponentPropsWithoutRef&lt;/code&gt; is a generic type that supplies props for built-in React handlers and native HTML attributes. By passing in &lt;code&gt;"button"&lt;/code&gt; as the template, you specify that the component is extending the HTML &lt;code&gt;button&lt;/code&gt; element.&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;type&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;children&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;/button&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;The result is a component that is clean and extensible. If additional props are needed, swap the &lt;code&gt;type&lt;/code&gt; for an &lt;code&gt;interface&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="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="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&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="na"&gt;specialProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;specialProp&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Type Refinement and Disjoint Unions
&lt;/h1&gt;

&lt;p&gt;Disjoint unions (or &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions"&gt;discriminated unions&lt;/a&gt;) are a powerful feature that can help you refine the component props of complex structures. In short, they allow your component to support multiple variants of a shared interface.&lt;/p&gt;

&lt;p&gt;Consider a &lt;code&gt;Button&lt;/code&gt; component that has several theme variations, such as "primary" and "secondary". You can express this type as a &lt;code&gt;string&lt;/code&gt; and pass it down as props.&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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="nx"&gt;getStyles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&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;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&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;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&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;invalid button kind&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getStyles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;While this implementation is simple, it presents significant problems.&lt;/p&gt;

&lt;p&gt;For one, you can pass any string value into the component props, even though only "primary" and "secondary" are implemented by the component. TypeScript won't warn you that any other value throws an error.&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="c1"&gt;// This passes compiler checks, yet throws an application error!&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not-a-style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You can instead switch &lt;code&gt;string&lt;/code&gt; to a union type, which offers much-needed improvements. The union type informs TypeScript of all possible values for &lt;code&gt;kind&lt;/code&gt;, preventing any unhandled cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&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="nx"&gt;getStyles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&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;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&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;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Default case is no longer needed!&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getStyles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Looking back at the component instance that is passed an invalid string literal, TypeScript now &lt;a href="https://www.typescriptlang.org/play#code/C4TwDgpgBAQgrsYB7AdgaQJYoCZQLxQDkYAThgLYCGJIhUAPkQM4QDGq21tAUN1sBBIAzSq2gAFEkjBMoEAB4CcsgEoRRwAHQBhJOTCoIKYJOlMA6hmAALJAjVCAPIQBGCZCkIA+KAG9uUFAA1ljYAFyw7qiYONwAvrxCcCiswBioUADmEMAAyqAANhBMABQhOBHwiNGhAJR+AVBMAO5WrNZQZXUNgYGslCxEpBRchGGNvVAkOXAkKENkVDQAtEyFEIQTUP2DhCzsOKPjk4HTwLPze2wcXKvrm4EJCdxJKWkZVR4lvsGhADTbawYArYabzOIRUwyer+PqoNZNdayAjZPJIro4Wq8U4zOZQRxuarzVgFAZMABylHIEDwvjWICKTDiXl87WBoKMcUcAHpCR4vPFEslUul5gBBMBgEowxpnC74z4ZcrYPAAIhQSGAy0odwZEFVXhJGFYQSg1IAhDzFSgBQkgA"&gt;offers a helpful error&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="c1"&gt;// Error: Type '"not-a-style"' is not assignable to type 'ButtonKind'&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not-a-style&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Union types are great at refining props for primitive values. But what about more complex structures?&lt;/p&gt;

&lt;p&gt;Consider that the "primary" button requires a special method, &lt;code&gt;specialPrimaryMethod&lt;/code&gt;, that is not supported by the “secondary” variant. The component calls this special method when handling a click.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&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="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;specialPrimaryMethod&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="k"&gt;void&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;specialPrimaryMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLButtonElement&lt;/span&gt;&lt;span class="o"&gt;&amp;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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specialPrimaryMethod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;specialPrimaryMethod&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;onClick&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="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&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;children&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;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although this component compiles, the type definition of props doesn’t inform the TypeScript compiler when &lt;code&gt;specialPrimaryMethod&lt;/code&gt; is permitted. The TypeScript compiler thinks that both “primary” and “secondary” allow the method, and that the method is optional in either case.&lt;/p&gt;

&lt;p&gt;To further demonstrate why this is problematic, take a look at the following instances of the component. The TypeScript compiler considers all of them valid, even though some of them conflict with the intended implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// Correct use-case
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt; &lt;span class="na"&gt;specialPrimaryMethod=&lt;/span&gt;&lt;span class="s"&gt;{doSpecial}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...

// Invalid use-case: specialPrimaryMethod shouldn't be optional
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...

// Invalid use-case: secondary shouldn't support specialPrimaryMethod
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"secondary"&lt;/span&gt; &lt;span class="na"&gt;specialPrimaryMethod=&lt;/span&gt;&lt;span class="s"&gt;{doSpecial}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...

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

&lt;/div&gt;



&lt;p&gt;This is where the disjoint union comes in handy. By splitting apart the interfaces for the “primary” variant and the “secondary” variant, you can achieve better compile-time type-checking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonKind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Build separate interfaces for Primary &amp;amp; Secondary buttons&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PrimaryButton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;specialPrimaryMethod&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SecondaryButton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secondary&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="c1"&gt;// Create a disjoint union&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PrimaryButton&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SecondaryButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Add built-in HTML props to the disjoin union&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// You can no longer destructure props since specialPrimaryMethod&lt;/span&gt;
&lt;span class="c1"&gt;// doesn't always exist on the object.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&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;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLButtonElement&lt;/span&gt;&lt;span class="o"&gt;&amp;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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&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="c1"&gt;// No extra if check needed!&lt;/span&gt;
      &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specialPrimaryMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onClick&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="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&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;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The additional type refinement provided by the disjoint union now &lt;a href="https://www.typescriptlang.org/play#code/C4TwDgpgBAQgrsYB7AdgaQJYoCZQLxQDkYAThgLYCGJIhUAPkQM4QDGq21tAUN1sBBIAzSq2gAFMlRrxEqKAG9uUKAGss2AFxFSFLoWVQmkVhkoAbSXpoBZCMAAWSLVAAUASnwA+KADckGNjcAL68-IIiYlAAymwcXLLIKIqG6jjahCzsOPohvKCQsAhJ+FBW0iCJ8oyx2Zwyxaj54BIkSGBMpQBKEKLAAHQAwkjkYKgQKMCS7UwA6hiOSAg9QgA8hABGjSiEPgBkRXIovEJwKKzAGPJVKK6kM9rTHZ5KKtlMwFAOlDjmEIPmDCsVSlVwQbQ9Pr9GxLFgAUV8E2AqwAEgAVGwAGRucL+5CRXk8eB8rxUUAwQjc9w6-TSuDwDJ0Un0L0MZKg1KY-WMbDMlmZtnsTmwHjZUGCUAg5hYKXZKk5-VQAKBqgA-P0we4xaEVKFDCR7HASMlVlsjlAlYDgXgFN9fv8rapgl4FArWA4MOZsAaUMFVgB6M1JLx5binc6XeQAQTAYA8sqgBuARuSrjFqxDcqgqxuag0eAARLoKgWvKxHVB8QBCAM3TNynPbPM4QvFrgFowmPnlLh2RbYG3x4mKYLOoRIJC17b19mN810wtZeI0Ds80wWHuC-uDokk0deceT-119P++ta0JAA"&gt;appropriately throws compile-time errors&lt;/a&gt; for invalid cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// All good!
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt; &lt;span class="na"&gt;specialPrimaryMethod=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {}}&amp;gt;foo&lt;span class="nt"&gt;&amp;lt;/Button&amp;gt;&lt;/span&gt;

// Error: Property 'specialPrimaryMethod' is missing
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;click me!&lt;span class="nt"&gt;&amp;lt;/Button&amp;gt;&lt;/span&gt;

// Error: Type '{ ... specialPrimaryMethod: () =&amp;gt; void; }' is not assignable
&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;kind=&lt;/span&gt;&lt;span class="s"&gt;"secondary"&lt;/span&gt; &lt;span class="na"&gt;specialPrimaryMethod=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {}}&amp;gt;click me!&lt;span class="nt"&gt;&amp;lt;/Button&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Don’t Overuse Disjoint Unions
&lt;/h2&gt;

&lt;p&gt;Disjoint unions are a powerful technique that enable general-purpose components. However, take care not to overuse them as they can lead to highly complex components.&lt;/p&gt;

&lt;p&gt;Anytime you reach for disjoint unions, pause and consider whether the single component should instead be separated into two.&lt;/p&gt;

&lt;h1&gt;
  
  
  Accessible Components With Polymorphism
&lt;/h1&gt;

&lt;p&gt;Polymorphic components are great for tuning markup for accessibility.&lt;/p&gt;

&lt;p&gt;Consider a &lt;code&gt;Container&lt;/code&gt; component that applies some styles to a &lt;code&gt;div&lt;/code&gt;. You may want to use this &lt;code&gt;Container&lt;/code&gt; component in situations that are better described by HTML5 elements like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside"&gt;aside&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section"&gt;section&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rather than duplicating the &lt;code&gt;Container&lt;/code&gt; component for slight alterations in its JSX, create a polymorphic component. This is as simple as including a new prop, &lt;code&gt;as&lt;/code&gt;, that accepts a union of HTML element strings.&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aside&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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;children&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;/Component&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The destructured alias, &lt;code&gt;{ as: Component }&lt;/code&gt;, is a convention that helps illustrate that the prop is a React component and not just a string.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Container&lt;/code&gt; component now supports different HTML5 elements to better fit its use-case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Container&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;section content&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Container&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Watch Out for These Bad Practices
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;defaultProps&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Defining &lt;code&gt;defaultProps&lt;/code&gt; on function components &lt;a href="https://twitter.com/dan_abramov/status/1133878326358171650"&gt;is marked for deprecation&lt;/a&gt;. You should instead assign defaults with prop destructuring:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&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="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avoid&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;defaultProps&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;defaultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultProps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the Non-Null Assertion Operator
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-"&gt;non-null assertion operator&lt;/a&gt; subverts TypeScript’s ability to check &lt;code&gt;null&lt;/code&gt; values. Despite how easy it is to type, this operator can cause a ton of harm. Let TypeScript do its job!&lt;/p&gt;

&lt;p&gt;In this case, you should instead rely on &lt;a href="https://paper.dropbox.com/doc/TypeScript-React-Best-Practices--BRJMvtoy~KZbGLSMOvUEiMDyAg-DSpTU8995rN7zqSROwCsl"&gt;refinement&lt;/a&gt; or &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html"&gt;narrowing&lt;/a&gt; and avoid overriding the TypeScript compiler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;liveSafely&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;number&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&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;number expected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toFixed&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="p"&gt;}}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avoid&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;liveDangerously&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;number&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;x&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toFixed&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="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Raising Exceptions for Exhaustive Cases
&lt;/h2&gt;

&lt;p&gt;There are few cases that call for raising an exception within a React component, since it renders a blank screen if handled improperly. You can avoid catastrophic failures with &lt;a href="https://reactjs.org/docs/error-boundaries.html"&gt;Error Boundaries&lt;/a&gt;, but in most cases throwing an exception is unnecessary.&lt;/p&gt;

&lt;p&gt;Instead, default to the closest acceptable user interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&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;&lt;strong&gt;Avoid&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&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;unsupported option&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;At OneSignal, we love empowering developers to refine their workflow and build great software. We hope these patterns help evolve your React and TypeScript codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  &amp;gt;&amp;gt;We’re hiring! Check out our open positions and apply on our careers page: &lt;a href="https://onesignal.com/careers"&gt;https://onesignal.com/careers&lt;/a&gt;&amp;gt;&amp;gt;
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
