<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phil Miller</title>
    <description>The latest articles on DEV Community by Phil Miller (@philmillman).</description>
    <link>https://dev.to/philmillman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F15238%2F791429c5-ac2b-4960-a588-e6ec6e115bd9.png</url>
      <title>DEV Community: Phil Miller</title>
      <link>https://dev.to/philmillman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/philmillman"/>
    <language>en</language>
    <item>
      <title>How to load an external HTML file in an iOS app</title>
      <dc:creator>Phil Miller</dc:creator>
      <pubDate>Thu, 18 Mar 2021 19:43:53 +0000</pubDate>
      <link>https://dev.to/trydaily/how-to-load-an-external-html-file-in-an-ios-app-55j4</link>
      <guid>https://dev.to/trydaily/how-to-load-an-external-html-file-in-an-ios-app-55j4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Daily Keyframes are byte-sized tips from our engineers. We hope they help you remove roadblocks so you can focus on building. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When Apple announced, in iOS 14.3, that WKWebView would have support for &lt;code&gt;navigator.mediaDevices.getUserMedia&lt;/code&gt;, we were ecstatic. It meant that iOS applications which relied on a webview could now use audio and video devices, a crucial element for an audio or video call. We were so excited, in fact, that we built &lt;a href="https://www.daily.co/blog/how-to-load-an-external-html-file-in-an-ios-app/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;Party Line&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, in the course of development we quickly realized there was a known bug. &lt;code&gt;navigator.mediaDevices.getUserMedia&lt;/code&gt; would only work if the HTML file in question was loaded via &lt;code&gt;http(s)&lt;/code&gt; origins. If you were loading a local HTML file (using &lt;code&gt;file://&lt;/code&gt;), &lt;code&gt;getUserMedia&lt;/code&gt; would be denied. Luckily this has been &lt;a href="https://github.com/WebKit/WebKit/commit/ff60f0a9b3a455b56adb95dbab14d404cb024152?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;fixed&lt;/a&gt;, but those fixes can take time to land, and even longer for users to upgrade to the latest OS version. &lt;/p&gt;

&lt;p&gt;So what can be done to get around this today? &lt;/p&gt;

&lt;p&gt;The easiest thing to do is host your file somewhere that serves it via &lt;code&gt;https&lt;/code&gt; (might as well keep it secure, while we’re at it). If you already have a server for your static assets, simply add it there and you’re good to go. If you don’t, and you want an easy solution, &lt;a href="https://www.netlify.com/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; is a great modern platform for static file deployments (among &lt;a href="https://www.daily.co/blog/deploy-an-on-demand-video-meeting-platform-with-dailys-prebuilt-ui-and-netlify/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;other things&lt;/a&gt;) and even has a drag and drop &lt;a href="https://app.netlify.com/drop?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframep" rel="noopener noreferrer"&gt;feature&lt;/a&gt;. For Party Line, our iOS HTML &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;file&lt;/a&gt; is deployed alongside our React web app, which makes it publicly accessible at &lt;a href="https://partyline.daily.co/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;&lt;code&gt;https://partyline.daily.co/ios-bridge.html&lt;/code&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To use it in our iOS app, we reference it in &lt;a href="https://github.com/daily-demos/party-line/blob/main/ios/Party%20Line/API/Client.swift?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe#L173" rel="noopener noreferrer"&gt;&lt;code&gt;Client.swift&lt;/code&gt;&lt;/a&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pageURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;URL&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://partyline.daily.co/ios-bridge.html&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then load it in &lt;a href="https://github.com/daily-demos/party-line/blob/e44761afade3b10b0771dd72898edfc35ccbbd56/ios/Party%20Line/API/Client.swift?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe#L299-L303" rel="noopener noreferrer"&gt;&lt;code&gt;Client.swift&lt;/code&gt;&lt;/a&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pageURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageURL&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;URLRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pageURL&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it! &lt;/p&gt;

&lt;p&gt;If you want to read more about this, check out our &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;html file&lt;/a&gt;, and these related tickets: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://openradar.appspot.com/48813943" rel="noopener noreferrer"&gt;https://openradar.appspot.com/48813943&lt;/a&gt; (rdar://48813943) &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=208667" rel="noopener noreferrer"&gt;https://bugs.webkit.org/show_bug.cgi?id=208667&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=188360" rel="noopener noreferrer"&gt;https://bugs.webkit.org/show_bug.cgi?id=188360&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=752458" rel="noopener noreferrer"&gt;https://bugs.chromium.org/p/chromium/issues/detail?id=752458&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you’re curious about what we built, head over to the &lt;a href="https://github.com/daily-demos/party-line?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;repo&lt;/a&gt; or read the &lt;a href="https://www.daily.co/blog/how-to-build-a-billion-dollar-audio-app-in-a-weekend/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=keyframe" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build a multi-platform audio community in a weekend</title>
      <dc:creator>Phil Miller</dc:creator>
      <pubDate>Fri, 12 Mar 2021 17:36:32 +0000</pubDate>
      <link>https://dev.to/trydaily/build-a-multi-platform-audio-community-in-a-weekend-1gaf</link>
      <guid>https://dev.to/trydaily/build-a-multi-platform-audio-community-in-a-weekend-1gaf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;At Daily, we're seeing a lot of new interest in audio chat and collaboration apps of all kinds. To support people building these apps, we whipped up sample code for a Clubhouse-like (or, Clubhouse-lite) audio room experience on four platforms: web (React), iOS, Android, and React Native. Feel free to try out the &lt;a href="https://partyline.daily.co/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline-web-app" rel="noopener noreferrer"&gt;live demo&lt;/a&gt; on the web, or browse the &lt;a href="https://github.com/daily-demos/party-line?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline-github-repo" rel="noopener noreferrer"&gt;sample code&lt;/a&gt;, then come back and read this post...&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you clicked on this article because of the title, you’re (probably) one of a few possible types of person. You’re a thirsty entrepreneur, ready to see how you can unlock the future. Maybe you’re the curious type and the short timeframe caught your attention. Or in the most likely case you, dear reader, are like your humble author. You’re a cynical developer who loves SEO and being hyperbolic. Hopefully, you’re all three of these people! 🦄&lt;/p&gt;

&lt;p&gt;Unless you’ve been living under a rock (or perhaps an &lt;a href="https://9to5google.com/2021/01/25/clubhouse-plans-to-start-working-on-its-android-app-soon/" rel="noopener noreferrer"&gt;Android phone&lt;/a&gt;), you have undoubtedly heard about some of these audio communities in the news lately. If you haven’t, may I suggest you enter the &lt;a href="https://www.joinclubhouse.com/" rel="noopener noreferrer"&gt;Clubhouse&lt;/a&gt;, grab a &lt;a href="https://capp.fm/" rel="noopener noreferrer"&gt;Cappuccino&lt;/a&gt;, and make a &lt;a href="https://www.beta.wearequilt.com/" rel="noopener noreferrer"&gt;Quilt&lt;/a&gt;? Or you might prefer to take a &lt;a href="https://apps.apple.com/us/app/roadtrip-listen-together/id1390884340" rel="noopener noreferrer"&gt;Roadtrip&lt;/a&gt; to the &lt;a href="https://apps.apple.com/us/app/id1516644054" rel="noopener noreferrer"&gt;Rodeo&lt;/a&gt;. To put it bluntly, audio is hot right now, &lt;a href="https://www.cnn.com/2021/02/14/business/elon-musk-vladmir-putin-clubhouse/index.html" rel="noopener noreferrer"&gt;Musk vs. Putin hot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’ll humor me, I’d like to start by talking about how we approached building Party Line to begin with. So many "weekend" projects go astray because they don’t fully define goals and expectations. So that’s where we’ll begin.&lt;/p&gt;

&lt;p&gt;Then we’ll talk about the overall flow of our applications. Creating a consistent experience across four platforms was important to us, so we’ve built four different demos with a small backend (two serverless functions). Since they all share similar logic, we’ll walk through that before diving into platform-specifics. In each section we’ll link out to the platform specific code if you want to dig deeper. &lt;/p&gt;

&lt;h2&gt;
  
  
  Party on!
&lt;/h2&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%2F0kx0fmmqailqriwocgyf.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%2F0kx0fmmqailqriwocgyf.png" alt="Screenshot of audio app with squares representing participants" width="800" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Party Line allows you to create audio chat rooms and invite your friends. They can join you as a speaker or just listen. The best part is that it works in most browsers without installing anything. And if you want to ship mobile apps, we’ve got you covered with iOS, Android, and React Native.&lt;/p&gt;

&lt;p&gt;Since we wanted to build something in a "weekend", let’s define our goals and call out assumptions to keep the scope manageable. &lt;/p&gt;

&lt;p&gt;Our application should have the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A starting screen where you can either create or join a room&lt;/li&gt;
&lt;li&gt;A prompt to enter your first and last name&lt;/li&gt;
&lt;li&gt;Three user types in a room: moderator, speaker, listener&lt;/li&gt;
&lt;li&gt;The room creator is the moderator&lt;/li&gt;
&lt;li&gt;Moderators can promote listeners to speakers&lt;/li&gt;
&lt;li&gt;Moderators can make other users moderators&lt;/li&gt;
&lt;li&gt;Moderators can demote speakers to listeners&lt;/li&gt;
&lt;li&gt;Listeners can raise (or lower) their hands to speak&lt;/li&gt;
&lt;li&gt;Speakers and moderators can mute/unmute themselves, but only mute others.&lt;/li&gt;
&lt;li&gt;Moderators can end the call for everyone&lt;/li&gt;
&lt;li&gt;All attendees can leave a call and return to the starting screen &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s also consider the following constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No external account management or authentication&lt;/li&gt;
&lt;li&gt;No database&lt;/li&gt;
&lt;li&gt;No backend aside from serverless functions which call the Daily REST API&lt;/li&gt;
&lt;li&gt;Implicit user roles based on meeting tokens&lt;/li&gt;
&lt;li&gt;No list of rooms to join&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have a sense for our MVP scope, let’s look at the overall architecture, from a Daily API perspective. &lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture: methods and events
&lt;/h2&gt;

&lt;p&gt;Since Daily is doing the heavy lifting for us, we can focus on how we’re interacting with Daily and build our interfaces (more on that later). &lt;/p&gt;

&lt;p&gt;There are three different ways we’ll interact with Daily: &lt;/p&gt;

&lt;p&gt;1) Calling methods from &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#using-the-dailyco-front-end-library" rel="noopener noreferrer"&gt;either&lt;/a&gt; &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#using-the-react-native-daily-js-library" rel="noopener noreferrer"&gt;of&lt;/a&gt; the js libraries&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-join" rel="noopener noreferrer"&gt;&lt;code&gt;join()&lt;/code&gt;&lt;/a&gt; - to join the room&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-leave" rel="noopener noreferrer"&gt;&lt;code&gt;leave()&lt;/code&gt;&lt;/a&gt; - to leave the room&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-setlocalaudio" rel="noopener noreferrer"&gt;&lt;code&gt;setLocalAudio()&lt;/code&gt;&lt;/a&gt; - for enabling and disabling the microphone&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-updateparticipant" rel="noopener noreferrer"&gt;&lt;code&gt;updateParticipant()&lt;/code&gt;&lt;/a&gt; - for changing roles&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-setusername" rel="noopener noreferrer"&gt;&lt;code&gt;setUserName()&lt;/code&gt;&lt;/a&gt; - for storing roles and raising hands&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#room" rel="noopener noreferrer"&gt;&lt;code&gt;room()&lt;/code&gt;&lt;/a&gt; - to fetch room information&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-participants" rel="noopener noreferrer"&gt;&lt;code&gt;participants()&lt;/code&gt;&lt;/a&gt; - to fetch participant information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Responding to events sent by the libraries&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#joined-meeting" rel="noopener noreferrer"&gt;&lt;code&gt;joined-meeting&lt;/code&gt;&lt;/a&gt; - when the local participant joins&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#left-meeting" rel="noopener noreferrer"&gt;&lt;code&gt;left-meeting&lt;/code&gt;&lt;/a&gt; - when the local participant leaves&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#error" rel="noopener noreferrer"&gt;&lt;code&gt;error&lt;/code&gt;&lt;/a&gt;- when an error occurs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#participant-joined" rel="noopener noreferrer"&gt;&lt;code&gt;participant-joined&lt;/code&gt;&lt;/a&gt; - when a remote participant joins&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#participant-updated" rel="noopener noreferrer"&gt;&lt;code&gt;participant-updated&lt;/code&gt;&lt;/a&gt; - when a remote participant updates (ex. mic is turned on)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#participant-left" rel="noopener noreferrer"&gt;&lt;code&gt;participant-left&lt;/code&gt;&lt;/a&gt; - when a remote participant leaves&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#active-speaker-change" rel="noopener noreferrer"&gt;&lt;code&gt;active-speaker-change&lt;/code&gt;&lt;/a&gt; - when the active speaker changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3) Creating rooms and tokens using REST endpoints&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#rooms" rel="noopener noreferrer"&gt;&lt;code&gt;/rooms&lt;/code&gt;&lt;/a&gt; - to create the room&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#meeting-tokens" rel="noopener noreferrer"&gt;&lt;code&gt;/meetings-tokens&lt;/code&gt;&lt;/a&gt; - to create the moderator token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s worth noting that for iOS and Android, we’ll be interacting with the methods and events via a WebView "bridge". In React and React Native, we can call &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#using-the-dailyco-front-end-library" rel="noopener noreferrer"&gt;&lt;code&gt;daily-js&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#using-the-react-native-daily-js-library" rel="noopener noreferrer"&gt;&lt;code&gt;react-native-daily-js&lt;/code&gt;&lt;/a&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio for the masses, the more platforms the merrier!
&lt;/h2&gt;

&lt;p&gt;We’ve put each of the clients in &lt;a href="https://github.com/daily-demos/party-line?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;one convenient repo&lt;/a&gt; for you. You’ll notice four folders, one for each of the clients. You can find the folder for our serverless functions inside &lt;code&gt;/react/server/functions&lt;/code&gt;. Each folder contains its own README with platform specific setup instructions. These should be enough to get everything up and running, but let us know if you’d find detailed, platform-specific posts helpful. Open an Issue, create a PR, or just &lt;a href="https://www.daily.co/contact?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;ping us&lt;/a&gt; any time we can help. &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%2Fv5ymq295v6y7ke8rth5m.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%2Fv5ymq295v6y7ke8rth5m.png" alt="Screenshot of Github repository folder structure" width="157" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, React and React Native are the most similar, and the most "idiomatic" in terms of how to build with Daily. Android and iOS are included to show what’s possible via "bridging" data to an invisible WebView. The fact that we’re only playing audio tracks makes this a bit more feasible. We’re actively working on native SDKs for mobile, so we welcome any feedback in this area.&lt;/p&gt;

&lt;p&gt;Follow along on the platform of your choice, or explore each of them simultaneously to see how to approach a cross platform application. &lt;/p&gt;

&lt;p&gt;For the rest of this overview, we’ll use the following legend.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/daily-demos/party-line/tree/main/react?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; (React web app)&lt;br&gt;
&lt;a href="https://github.com/daily-demos/party-line/tree/main/react-native?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; (React Native mobile app(s))&lt;br&gt;
&lt;a href="https://github.com/daily-demos/party-line/tree/main/ios?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; (iOS mobile app - Swift)&lt;br&gt;
&lt;a href="https://github.com/daily-demos/party-line/tree/main/android?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt; (Android mobile app - Kotlin &amp;amp; Java; we'll link to the Kotlin examples)&lt;br&gt;
&lt;a href="https://github.com/daily-demos/party-line/tree/main/react/server/functions?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🥅&lt;/a&gt; (Netlify function - Node)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Whenever you see one of these emoji, it will link to the relevant file or line in the repo. Even the ones above. Try it!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First off, follow the README instructions, and start your dev server. (&lt;a href="https://github.com/daily-demos/party-line/tree/main/react?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/tree/main/react-native?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/ios/README.md?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/tree/main/android?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;) &lt;/p&gt;

&lt;p&gt;If you’re one of those read-the-last-page-first types, you can see a working demo &lt;a href="https://partyline.daily.co/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;here&lt;/a&gt; and follow along that way. &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%2Ftcaht4k6wglv79inodku.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%2Ftcaht4k6wglv79inodku.png" alt="Party line app join page asks for first name last name join code and create button" width="800" height="950"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first page you are greeted with is a join/create a page.&lt;/p&gt;

&lt;p&gt;This is the user’s entry point into your application. Here we made a couple assumptions to keep the scope down. First, there’s no authentication or accounts per se. We take privacy &lt;a href="https://www.daily.co/security?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;seriously&lt;/a&gt; and you should too. So before you take our scrappy demo and deploy it as a production app, please consider how you’ll handle auth and security in general.&lt;/p&gt;

&lt;p&gt;Second, if you start a room, you’re the moderator. We accomplish this by creating a &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#meeting-tokens" rel="noopener noreferrer"&gt;meeting-token&lt;/a&gt; which is then used when you &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-join" rel="noopener noreferrer"&gt;join&lt;/a&gt; the call. Moderators have the ability to "promote" other user types, which is why we need a token to identify them, but more on that later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See more on how &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-createcallobject" rel="noopener noreferrer"&gt;create&lt;/a&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/assets/audio-single-file.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;) and &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-join" rel="noopener noreferrer"&gt;join&lt;/a&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/assets/audio-single-file.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;) works in the clients&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the server(less) side of things, we’ve created &lt;code&gt;/room&lt;/code&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/server/functions/room.js?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🥅&lt;/a&gt;) and &lt;code&gt;/token&lt;/code&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/server/functions/token.js?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🥅&lt;/a&gt;) endpoints which call the &lt;a href="https://docs.daily.co/reference#rooms" rel="noopener noreferrer"&gt;&lt;code&gt;/rooms&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.daily.co/reference#meeting-tokens" rel="noopener noreferrer"&gt;&lt;code&gt;/meeting-tokens&lt;/code&gt;&lt;/a&gt; endpoints respectively. You’ll see those endpoints used in each of the clients. We’re enforcing the 10 minute demo limit here by using the &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#room-configuration" rel="noopener noreferrer"&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/a&gt; property for rooms and tokens. Feel free to change this in your own application unless you prefer to keep your meetings short and sweet!&lt;/p&gt;

&lt;h2&gt;
  
  
  Life of the party
&lt;/h2&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%2F22nyjtt6yfgcnhtzr37c.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%2F22nyjtt6yfgcnhtzr37c.png" alt="View once you've joined and created a call" width="800" height="813"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you create a call, you are presented with the call view (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/components/InCall.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/components/InCall.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/ios/Party%20Line/Views/RoomView.swift?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/java/com/daily/partyline/RoomFragment.kt?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). Here, as a moderator, you have the ability to "promote" listeners to speakers, or moderators. We’re using the &lt;code&gt;owner&lt;/code&gt; property from the &lt;a href="https://docs.daily.co/reference#%EF%B8%8F-participants" rel="noopener noreferrer"&gt;participants&lt;/a&gt; object to identify moderators. This gets set when the meeting token you join with has &lt;code&gt;is_owner&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;. To simplify how user roles in general work for the purposes of this demo, we’re storing them by appending to the username (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/ios/Party%20Line/Views/ParticipantGridItemView.swift?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/assets/audio-single-file.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). In a production environment, you’ll want a more robust way to enforce the roles, so keep that in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look who's talking now
&lt;/h2&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%2F8mjfgf9itzigpjuvvq7s.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%2F8mjfgf9itzigpjuvvq7s.png" alt="Moderator controls to " width="167" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you use your moderator privileges to promote a speaker, under the hood this is accomplished by calling &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-sendappmessage" rel="noopener noreferrer"&gt;&lt;code&gt;sendAppMessage()&lt;/code&gt;&lt;/a&gt; to let the speaker know they have been promoted. For the promoted participant, who will be a speaker, we call &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-setusername" rel="noopener noreferrer"&gt;&lt;code&gt;setUserName()&lt;/code&gt;&lt;/a&gt;, so that other members will be able to pick up their new role via &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-participants" rel="noopener noreferrer"&gt;&lt;code&gt;participants()&lt;/code&gt;&lt;/a&gt; and update the UI accordingly in each of the clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't hesitate, moderate!
&lt;/h2&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%2Fuxwbadmelg1urbar24lx.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%2Fuxwbadmelg1urbar24lx.png" alt="Party line app interface remove from call option" width="750" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes conversations can get a little &lt;em&gt;spirited&lt;/em&gt; or maybe someone’s dog has decided they want to participate in the world’s latest social craze. When this happens it’s good as a moderator to be able to mute someone. We accomplish this by calling &lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-updateparticipant" rel="noopener noreferrer"&gt;&lt;code&gt;updateParticipant()&lt;/code&gt;&lt;/a&gt; with &lt;code&gt;setAudio:false&lt;/code&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/java/com/daily/partyline/WebAppClient.kt?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). For privacy reasons, moderators can only mute remote participants. They will have to unmute themselves when things quiet down. &lt;/p&gt;

&lt;p&gt;In rare circumstances, muting may not be enough, and you will need to remove someone from the room. We handle this by calling &lt;code&gt;sendAppMessage()&lt;/code&gt; and telling the client that needs to leave to exit the room by calling &lt;code&gt;leave()&lt;/code&gt; (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/java/com/daily/partyline/WebAppClient.kt?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas and One More Thing™️
&lt;/h2&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%2F96k8n77szcr6kwjo6th6.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%2F96k8n77szcr6kwjo6th6.png" alt="Moderator controls in Party line app" width="153" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because our trust mechanism to identify moderators is a token, when someone gets "promoted" to a moderator they need to rejoin (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/java/com/daily/partyline/WebAppClient.kt?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;) with their token so we can give them elevated control of the call. This pattern means they’ll drop out of the call for a second or two before rejoining as a moderator. In a production app you might prefer a smoother transition, which could be accomplished with a different moderator authorization method. &lt;/p&gt;

&lt;p&gt;Another thing you may have noticed is that we ask for device permissions when you join, even if you’re a listener. This allows us to immediately turn on your mic when the time comes, but if you prefer a less invasive approach, you can always rework things so permissions are requested only when you’ve been promoted. &lt;br&gt;
The not-so-secret sauce of the the iOS and Android clients is that they’re loading &lt;code&gt;daily-js&lt;/code&gt; in a "headless" WebView and then interacting with it via a "bridge" (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/java/com/daily/partyline/WebAppClient.kt?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). This is made possible by additions to platform specific WebView implementations which allow the audio tracks to be played off-screen. This works for this audio-only use case because there’s no video layout logic to deal with. We wanted to demonstrate the power of a lightweight integration like this, but rest assured that we’re actively working on fully featured mobile SDKs which we’ll release later this year™.&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%2Fc96donziev6iyiuqyrwg.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%2Fc96donziev6iyiuqyrwg.png" alt="Just one more thing meme" width="660" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So you’ve now got a flourishing multiplatform audio-only application. But you’re finding that your speakers can get a little carried away and sometimes you want to inject some audience participation. For this reason we’ve added the ability for listeners to raise their hands so they can be promoted to speakers. Since we’ve already "creatively" stored user roles in usernames, why not publicly show when someone raises their hand there as well? To do this, we call &lt;code&gt;setUserName()&lt;/code&gt; and prepend ✋ (&lt;a href="https://github.com/daily-demos/party-line/blob/main/react/src/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🕸&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react-native/contexts/CallProvider.jsx?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;⚛&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/react/public/ios-bridge.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🍏&lt;/a&gt; &lt;a href="https://github.com/daily-demos/party-line/blob/main/android/kotlin/app/src/main/assets/audio-single-file.html?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;🤖&lt;/a&gt;). A moderator can then decide to promote, in which case the ✋ will magically disappear. Or a listener can lower their hand if it was "more of a comment than a question". &lt;/p&gt;

&lt;p&gt;So there you have it, a suite of awesome demos that we built in a "weekend" (emphasis on week), but…&lt;/p&gt;

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

&lt;p&gt;Here are just a few ideas on what to do next with Party Line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add proper authentication and user roles&lt;/li&gt;
&lt;li&gt;Make rooms persistent and add room metadata&lt;/li&gt;
&lt;li&gt;Add the ability to schedule a "Party"&lt;/li&gt;
&lt;li&gt;Send notifications when someone joins (via webhook or push)&lt;/li&gt;
&lt;li&gt;Add user profiles (avatars, custom fields, etc)&lt;/li&gt;
&lt;li&gt;A Party list / overview page&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.daily.co/reference?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline#%EF%B8%8F-startlivestreaming" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; and scale up! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that you’ve got a billion dollar app, don’t forget to create a &lt;a href="https://pitch.com/?utm_source=dev&amp;amp;utm_medium=post&amp;amp;utm_campaign=partyline" rel="noopener noreferrer"&gt;deck&lt;/a&gt; and go after that hard-won VC money. 🤑&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In all seriousness, communities are only as good as their members. We want to take the guesswork out of the technical communications part of yours so you can focus on building.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please reach out if we can help you!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Deploy a Daily Node.js backend server instantly</title>
      <dc:creator>Phil Miller</dc:creator>
      <pubDate>Thu, 15 Oct 2020 18:49:04 +0000</pubDate>
      <link>https://dev.to/trydaily/deploy-a-daily-node-js-backend-server-instantly-9f4</link>
      <guid>https://dev.to/trydaily/deploy-a-daily-node-js-backend-server-instantly-9f4</guid>
      <description>&lt;p&gt;If you’ve been following our &lt;a href="https://dev.to/trydaily"&gt;Daily DEV tutorials&lt;/a&gt;, you might’ve noticed Paul’s note in his post about building a &lt;a href="https://dev.to/trydaily/build-a-video-chat-app-in-minutes-with-react-and-daily-js-481c"&gt;video chat app with React&lt;/a&gt;: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;“In real production code, you'll want to create rooms by calling the Daily REST API from your backend server, to avoid storing API keys in your client-side JavaScript.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the future, we’ll go into great detail about how to implement your server-side code, but for now we prefer to give you some building blocks to get you up-and-running as quickly as possible. &lt;/p&gt;

&lt;h2&gt;
  
  
  What we’ll build
&lt;/h2&gt;

&lt;p&gt;We’re going to set up an instant &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; server on &lt;a href="https://glitch.com/" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;. Glitch is a friendly, community-oriented developer tool that allows you to create projects from scratch or "remix" others for inspiration. Every project is backed by a real server, so you have everything you need to get started and to scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you’ll need to build it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily account and API key&lt;/strong&gt;: &lt;a href="https://dashboard.daily.co/signup" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; if you don’t have these yet.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glitch account&lt;/strong&gt;: If you plan on tweaking your server over time, we highly recommend &lt;a href="https://glitch.com/signin" rel="noopener noreferrer"&gt;signing up for Glitch&lt;/a&gt;. Though, you can still follow this tutorial without creating an account!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Click the &lt;a href="https://glitch.com/edit/?utm_content=project_dailyco-sample-server&amp;amp;utm_source=remix_this&amp;amp;utm_medium=button&amp;amp;utm_campaign=glitchButton#!/remix/dailyco-sample-server" rel="noopener noreferrer"&gt;Remix button&lt;/a&gt; below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://glitch.com/edit/?utm_content=project_dailyco-sample-server&amp;amp;utm_source=remix_this&amp;amp;utm_medium=button&amp;amp;utm_campaign=glitchButton#!/remix/dailyco-sample-server" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.glitch.com%2F2bdfb3f8-05ef-4035-a06e-2043962a3a13%252Fremix%25402x.png%3F1513093958726" alt="remix this" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now have an editable copy of the server, which includes public API endpoints that return data via the Daily API. You’ll also have a handy web-based development environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add your key
&lt;/h2&gt;

&lt;p&gt;All you need to do to get going is to add your Daily API Key, which you can get from the &lt;a href="https://dashboard.daily.co/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; in the Developers section.&lt;/p&gt;

&lt;p&gt;Copy it to your clipboard and open the .env file in the Glitch editor. Paste it there (replacing Variable Value):&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%2Fi%2Fbv6q9ep1v363toolewxb.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%2Fi%2Fbv6q9ep1v363toolewxb.jpg" alt="Screenshot of where to paste your Daily API key into the Glitch editor" width="800" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  At your service
&lt;/h2&gt;

&lt;p&gt;Now let’s have a look at the server code (in &lt;code&gt;server.js&lt;/code&gt;) and send a sample request.&lt;/p&gt;

&lt;p&gt;First, open up the log view (Tools &amp;gt; Logs, located in the bottom left) and you should see:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;💗🌴 Your app is listening on port 3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This means the &lt;code&gt;express&lt;/code&gt; server is running and listening for incoming requests [0].&lt;/p&gt;

&lt;p&gt;Looking at the code you will see three sections.&lt;/p&gt;

&lt;p&gt;In the first section we’re importing dependencies, clearing some useful constants, and setting up an &lt;code&gt;axios&lt;/code&gt; instance to reference the Daily API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// MAKE SURE YOU HAVE ADDED YOUR API KEY IN THE .env file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.daily.co/v1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_AUTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DAILY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// create an axios instance that includes the BASE_URL and your auth token&lt;/span&gt;
&lt;span class="c1"&gt;// this may be useful to put in an external file to it can be referenced&lt;/span&gt;
&lt;span class="c1"&gt;// elsewhere once your application grows&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_AUTH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up are all the endpoints we’re creating on our server. Each of them is essentially a loose wrapper that calls its equivalent in the Daily API. Let’s look at the first one, as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/rooms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rooms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/rooms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rooms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re saying when a request comes in at &lt;code&gt;/rooms&lt;/code&gt; we want to execute this &lt;code&gt;async&lt;/code&gt; callback that makes a request to the Daily API using the &lt;code&gt;apiHelper&lt;/code&gt; we defined below. If the request is successful then we send the response back to the requester as &lt;code&gt;json&lt;/code&gt;. If it fails, then we send back an &lt;code&gt;http 500&lt;/code&gt; error with an accompanying error message.&lt;/p&gt;

&lt;p&gt;Lastly, let’s look at the &lt;code&gt;apiHelper&lt;/code&gt; function:&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;apiHelper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Status: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Text: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// need to throw again so error is caught&lt;/span&gt;
    &lt;span class="c1"&gt;// a possible improvement here is to pass the status code back so it can be returned to the user&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal here is to have a reusable way to call the Daily API. It takes the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method: the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods" rel="noopener noreferrer"&gt;http request&lt;/a&gt; method&lt;/li&gt;
&lt;li&gt;endpoint: the Daily API endpoint &lt;/li&gt;
&lt;li&gt;body: the optional request body, required for POST, PUT, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re using the request method from the axios instance we defined above, so we don’t have to worry about specifying the BASE_URL and Authorization header with every request. We’ve included some basic error handling here, but feel free to modify this as needed [1].&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample request
&lt;/h2&gt;

&lt;p&gt;You can verify all is working as intended by opening the Glitch preview (Click Show -&amp;gt; Next to The Code). Next click 'Change URL' and add &lt;code&gt;[/rooms](https://docs.daily.co/reference#list-rooms)&lt;/code&gt;. You should see some &lt;code&gt;json&lt;/code&gt;, which is the list of rooms on your account.&lt;/p&gt;

&lt;p&gt;Your server should now be publicly accessible at the following url:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://YOUR-PROJECT-NAME.glitch.me&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;You now have a functional server to make calls to the Daily API which protects your API key. We’ve added a few endpoints as a reference but there are many others you can add as a next step (&lt;code&gt;/recordings&lt;/code&gt; for example).&lt;/p&gt;

&lt;p&gt;This server also implicitly “trusts” the client that is making these requests. A great next step would be adding some authentication to your client and checking for that on the server. You don’t want just anyone generating tokens with “is_owner” privileges, for example.&lt;/p&gt;

&lt;p&gt;Finally, while this is totally viable as a development server, you may want to consider becoming a Glitch member and “Boosting” this app. This gives you a bunch of &lt;a href="https://glitch.com/pricing" rel="noopener noreferrer"&gt;benefits&lt;/a&gt;, most important being that it will always be awake. You will also be supporting the team at Glitch and all the excellent work they do.&lt;/p&gt;

&lt;p&gt;[0] I’ve glossed over &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;express&lt;/a&gt; and &lt;a href="https://github.com/axios/axios" rel="noopener noreferrer"&gt;axios&lt;/a&gt;. If either of these are unfamiliar, please read their documentation first. At a high level, we’re using express to handle and respond to incoming requests, and we’re using axios to make requests to external Daily APIs.&lt;/p&gt;

&lt;p&gt;[1] We’re using async/await to simplify dealing with promises. If this is unfamiliar, do check out the docs on &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>video</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
