{"id":22374,"date":"2021-06-07T13:53:50","date_gmt":"2021-06-07T13:53:50","guid":{"rendered":"http:\/\/building_a_roommate_matching_app_with_cloudinary_and_jamstack"},"modified":"2024-05-29T16:15:09","modified_gmt":"2024-05-29T23:15:09","slug":"building_a_roommate_matching_app_with_cloudinary_and_jamstack","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack","title":{"rendered":"Building a Roommate-Matching App With Cloudinary and Jamstack"},"content":{"rendered":"\n<style>\n.btn.exp-btn {\n    text-transform: none;\n    padding: 10px 30px;\n    font-size: 1.1em;\n    border-radius: 40px;\n    margin-top: 20px;\n    margin-bottom: 40px;\n    display: inline-block;\n    position: relative;\n    max-width: 400px;\n}\n#exp-btn-carrot {margin-bottom: 1px; margin-left: 1px;}\n.btn.exp-btn::after {\n    content: \"\";\n    display: inline-block;\n    background-image: url(https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1657723837\/exp-btn.png);\n    position: absolute;\n    background-size: contain;\n    background-repeat: no-repeat;\n    width: 33px;\n    height: 70px;\n    top: 0px;\n    right: -22px;\n}\n@media (max-width: 992px) {\n    .btn.exp-btn {margin-left: 0;}\n}\n\n@media (max-width: 500px) {\n     .btn.exp-btn {\n         max-width: initial;\n         margin-left: auto!important;\n         margin-right: auto;\n         font-size: 15px;\n         width: 300px;\n         display: block;\n         padding: 10px;\n     }\n.btn.exp-btn:after {display: none;}\n}\n<\/style>\n<div style=\"display: flex; justify-content: center;\"><a href=\"#creating_a_next_js_app\" class=\"exp-btn btn btn-sm btn-primary c-subscription-cta__link\">Shortcut to Cloudinary\u2019s solution\n<svg id=\"exp-btn-carrot\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10.759\" height=\"11.117\" viewBox=\"0 0 10.759 11.117\">\n  <path id=\"Polygon_1\" data-name=\"Polygon 1\" d=\"M4.248,0,8.5,7.518H0Z\" transform=\"translate(6.511) rotate(60)\" fill=\"#fff\"><\/path>\n<\/svg>\n<\/a><\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><p>Roommate matching can be a pain\u2014especially during the COVID pandemic when people don\u2019t want to meet in person. Matching apps like Flatmates, Roomster, and roommates.com are helpful, and if you\u2019re in the roommate-matching space, you know that great video is essential for those seeking roommates. Fortunately, Cloudinary can help.<\/p>\n<p>Cloudinary is a cloud-based SaaS with which you as developers can upload and manage videos in the cloud, editing, transforming, and optimizing them for any screen. You can then insert those videos into a website through a video-player app. This article shows you how to build a sample app for matching roommates by leveraging video capabilities.<\/p>\n<h2>Explaining the Roommate-Matching App<\/h2>\n<p>This sample <a href=\"https:\/\/github.com\/marcelooliveira\/cloudinary-roommates\/tree\/main\/app\">Roommate-Matching App<\/a> is based on a simplified use case of a typical apartment-and-room rental app: owners input details about their properties and room seekers might then signal interest. Before closing the deal, both parties exchange profiles, make an appointment, and meet at the location.<\/p>\n<p>To avoid meeting in person during the pandemic, owners would upload a 10-minute video that showcases the room and the rest of the property. The video also talks about their hobbies, likes, and dislikes. To protect privacy, the video is restricted for access. To watch it, the room seeker must secure the owner\u2019s approval.<\/p>\n<p>The following diagram illustrates the sequence of events within the app:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/action-sequence.png\" alt=\"Action sequence\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"450\" height=\"457\"\/><\/p>\n<h2>Understanding the Tech Stack<\/h2>\n<p>This app boasts a tech stack that\u2019s ready for the modern web and rapid development:<\/p>\n<ul>\n<li>\n<p><strong><a href=\"https:\/\/nextjs.org\/\">Next.js<\/a> for the user interface (UI)<\/strong>: Next.js is a React-based framework that enables such functions as server-side rendering and <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\">static generation<\/a>.<\/p>\n<\/li>\n<li>\n<p><strong><a href=\"https:\/\/www.netlify.com\/\">Netlify<\/a> with Jamstack for hosting:<\/strong> Unlike traditional web apps, Netlify\u2019s simple architecture works on prebuilt files served over a content delivery network (CDN). Such an approach results in higher performance, security, and scalability along with lower costs and an enhanced developer experience.<\/p>\n<\/li>\n<li>\n<p><strong><a href=\"https:\/\/www.sanity.io\/\">Sanity<\/a> as a storage back end:<\/strong> Given the app\u2019s serverless scenario, Sanity Data Store provides data access and stores room details as a collection of documents. You\u2019ll use Sanity\u2019s <a href=\"https:\/\/www.sanity.io\/docs\/client-libraries\">JavaScript client library<\/a> to conveniently encapsulate low-level operations.<\/p>\n<\/li>\n<li>\n<p><strong><a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> for media management:<\/strong> For an optimal user experience, this app delivers optimized images and video streaming on Cloudinary, whose dashboard and tools offer an end-to-end solution for easily managing media assets.<\/p>\n<\/li>\n<\/ul>\n<h2>Creating a Next.js App<\/h2>\n<p>This section steps you through the procedure for creating the sample Roommate-Matching App with the tech stack described earlier. For brevity, the description also contains code samples from the key parts of the app, emphasizing those sections that use the Cloudinary API. <a href=\"https:\/\/cloudinary.com\/users\/register\/free\/?utm_content=cta-free-sign-up-sb-app-clo-jam\">Click here<\/a> to claim your free forever Cloudinary account.<\/p>\n<ol>\n<li>\n<p>Create a GitHub repository and then install Node.js and the Next.js command-line tool.<\/p>\n<\/li>\n<li>\n<p>Create a standard Next.js project:<\/p>\n<p><code>create-next-app<\/code><\/p>\n<\/li>\n<li>\n<p>Open the project in a code editor and create a <code>Next.config.js<\/code> file that contains this snippet:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>module.exports = {\n  distDir: &quot;dist&quot;,\n  target: &quot;serverless&quot;\n}\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Build and test on <code>localhost<\/code> with the commands npm <code>install<\/code>, <code>npm run build<\/code>, and npm run dev; and then go to <code>http:\/\/localhost:3000<\/code>. Commit the local changes and push them to GitHub:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>git commit\ngit push\n<\/code><\/pre>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/nextjs-app.png\" alt=\"Next.js app\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"460\" height=\"443\"\/><\/p>\n<h2>Deploying the App to Netlify<\/h2>\n<p>Now deploy your app to the Netlify cloud for hosting:<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/app.netlify.com\/signup\">Sign up for a free Netlify account<\/a> and then create a Netlify site from your GitHub repository by clicking <strong>New Site from Git<\/strong>. Choose the repository you want to link to your site on Netlify. When you push to Git, Netlify will run your build tool of choice on its servers and deploy the result. Change the build settings on your dashboard to read like this:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>Build command: `next build`\nPublish directory: `dist\/`\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Click the <strong>Plugins<\/strong> tab and add <strong>Next<\/strong> to the Netlify plugin. That plugin will then build and deploy your Next.js app with no other configurations required.<\/p>\n<\/li>\n<li>\n<p>From the <strong>Deploy<\/strong> tab for your site, force a new deployment, and test the deployed website: <code>https:\/\/YOUR-SITE-NAME.netlify.app\/<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/v1622604157\/Web_Assets\/blog\/deploy-netlify.png\" alt=\"Deploy Netlify\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"494\" height=\"512\"\/><\/p>\n<p>Your Netlify project is now ready for continuous integration: every time you push a commit, Netlify will connect to your app repository and automatically publish your website.<\/p>\n<\/li>\n<li>\n<p>Open your Netlify dashboard, view the <strong>Functions<\/strong> tab, and note that Netlify has automatically exported the Hello API endpoint as a serverless function at <code>https:\/\/YOUR-SITE-NAME.netlify.app\/.netlify\/functions\/next_api_hello<\/code>, which gives you the same result as the <code>http:\/\/localhost:3000\/api\/hello<\/code> endpoint:<\/p>\n<p><code>{&quot;name&quot;:&quot;John Doe&quot;}<\/code><\/p>\n<\/li>\n<\/ol>\n<p>Every time your app calls the <code>\/api\/hello<\/code> endpoint, Netlify will redirect it internally to the <code>\/functions\/next_api_hello<\/code> path of your deployed website.<\/p>\n<p>Recall that you created the Next.config.js file with this code before:<\/p>\n<p>module.exports = {\ndistDir: \u201cdist\u201d,\ntarget: \u201cserverless\u201d\n}<\/p>\n<p>When Netlify builds your app with the next build command, the settings above cause Next.js to prepare a serverless deployment, which splits your app into small parts, called lambdas. Here\u2019s how Next.js builds and deploys pages and APIs to the distribution (<code>dist<\/code>) folder:<\/p>\n<ul>\n<li>\n<code>\/pages\/index.js =&gt; \/dist\/serverless\/pages\/index.js<\/code>\n<\/li>\n<li>\n<code>\/pages\/api\/rooms\/[id].js =&gt; \/dist\/serverless\/pages\/api\/rooms\/[id].js<\/code>\n<\/li>\n<\/ul>\n<p>Despite having the same name, the target files in the <code>dist<\/code> folder are different from their source files because each lambda file contains a complete bundle that can run without dependencies. When you deploy your app as a serverless website in Netlify, those lambdas greatly improve the app\u2019s reliability and scalability.<\/p>\n<h2>Implementing Netlify Identity<\/h2>\n<p><a href=\"https:\/\/docs.netlify.com\/visitor-access\/identity\/\">Netlify Identity\u2019s<\/a> convenient authentication service is easy to integrate into your app. Follow these steps:<\/p>\n<ol>\n<li>\n<p>Open the <strong>Identity<\/strong> tab of your Netlify project and click <a href=\"https:\/\/docs.netlify.com\/visitor-access\/identity\/\"><strong>Enable Identity<\/strong><\/a>.<\/p>\n<\/li>\n<li>\n<p>Install on the command line the <a href=\"https:\/\/www.npmjs.com\/package\/netlify-identity-widget\">Netlify Identity Widget<\/a>, Bootstrap, React Bootstrap, and FontAwesome with <code>npm<\/code>:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>npm install netlify-identity-widget\nnpm install bootstrap\nnpm install react-bootstrap\nnpm install fontawesome\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Add the <code>Layout<\/code> and <code>Header<\/code> components to the <code>\/components<\/code> folder of your project:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>\/components\/\n  \/Layout.js\n  \/Header.js\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Add the <code>netlify-identity-widget<\/code> script below to the Layout component:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>  return (\n    &lt;&gt;\n      &lt;Head&gt;\n        &lt;title&gt;Your Roommate Matching App&lt;\/title&gt;\n        &lt;script type=&quot;text\/javascript&quot; src=&quot;https:\/\/identity.netlify.com\/v1\/netlify-identity-widget.js&quot;&gt;&lt;\/script&gt;\n      &lt;\/Head&gt;\n  .\n.\n.\n      &lt;Header \/&gt;\n      &lt;main&gt;\n        &lt;link rel=&quot;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;..\/app.css&quot; \/&gt;\n        &lt;div className=&quot;container&quot;&gt;{children}&lt;\/div&gt;\n      &lt;\/main&gt;\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Add the <code>data-netlify-identity-menu<\/code> component below to the <code>Header<\/code> component:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>&lt;div data-netlify-identity-menu&gt;&lt;\/div&gt;\n<\/code><\/pre>\n<\/li>\n<li>\n<p>In the Index page, wrap the UI with the <code>Layout<\/code> component:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>return (\n  &lt;Layout&gt;\n    [...]    \n  &lt;\/Layout&gt;\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Run the app again, click the <strong>Sign Up<\/strong> link in the Netlify Identity menu, and register for a new account.<\/p>\n<\/li>\n<li>\n<p>Open your email to confirm the registration and then log in to the new account:<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/netlify-identity.png\" alt=\"netlify-identity\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"512\" height=\"414\"\/>\n<img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/netlify-identity-login.png\" alt=\"netlify-identity login\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"705\" height=\"570\"\/><\/p>\n<h2>Accessing Data With Sanity<\/h2>\n<p>For data access, outsource your data store to Sanity. Integrate Sanity into the app, as follows:<\/p>\n<ol>\n<li>\n<p>Create two folders, name them <code>\/public\/img<\/code> and <code>\/data<\/code>, and then add some pictures of a room for rent under <code>\/public\/img<\/code>. In the <code>data<\/code> folder, add a dummy JSON file called <code>data.js<\/code> with information on the room.<\/p>\n<\/li>\n<li>\n<p>Edit the index page to display the room-catalog data from a static JSON file.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.sanity.io\/create\">Sign up for a free Sanity account<\/a>. Create a Sanity project and then add a collection named <code>rooms<\/code>.<\/p>\n<\/li>\n<li>\n<p>Install the <code>@sanity\/client npm<\/code> package.<\/p>\n<\/li>\n<li>\n<p>Create a <code>.env<\/code> file and add the credentials of your Sanity project to it:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>SANITY_PROJECT_ID=XXXXXXXXXX\nSANITY_API_TOKEN=xxxxxxxxxxxxxxxx\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Edit the <code>Next.config.js<\/code> file to export your Sanity credentials:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>const sanityProjectId = process.env.SANITY_PROJECT_ID;\nconst sanityApiToken = process.env.SANITY_API_TOKEN;\nmodule.exports = {\n  distDir: 'dist',\n  target: 'serverless',\n  publicRuntimeConfig: {\n    sanityProjectId: sanityProjectId,\n    sanityApiToken: sanityApiToken\n  }\n}\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Go to the <strong>Environment Variables<\/strong> section of your Netlify project settings and add the same Sanity credentials from the <code>Next.config.js<\/code> file.<\/p>\n<\/li>\n<li>\n<p>Create the <code>Pages\/API\/rooms\/[id].js<\/code> endpoint with the <code>GET<\/code> and <code>POST<\/code> methods to connect to your Sanity data store with your credentials and perform data operations on the <code>rooms<\/code> collection. Within your API methods, use the <a href=\"https:\/\/www.sanity.io\/docs\/js-client\">Sanity API JavaScript client<\/a> and call the getDocument, fetch, and createOrUpdate methods of the Sanity client to get a single room document, to retrieve all the room documents, and to update a room document, respectively.<\/p>\n<\/li>\n<li>\n<p>Build, run, and test the new API endpoint on <code>localhost<\/code>.<\/p>\n<\/li>\n<li>\n<p>Install the <a href=\"https:\/\/www.npmjs.com\/package\/swr\">SWR React Hooks library package<\/a> for fetching and caching remote data:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>&gt;npm i swr\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Edit the index page to fetch room data from the new API endpoint instead of the static JSON file.<\/p>\n<\/li>\n<li>\n<p>Run the app again. The room information along with images are now displayed on the homepage, for example:<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_700,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/available-rooms.png\" alt=\"Available rooms\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"778\"\/><\/p>\n<h2>Integrating Image and Video Services With Cloudinary<\/h2>\n<p>Media access is the last piece in the puzzle. Follow the steps below to integrate your app with Cloudinary\u2019s services and components.<\/p>\n<p><strong>1.<\/strong> <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">Sign up for a free Cloudinary account<\/a> and create a Cloudinary project. Click <strong>Settings<\/strong> &gt; <strong>Upload<\/strong> and, under <strong>Upload presets<\/strong>, look for the preset with the <strong>Mode = Unsigned<\/strong> setting.<\/p>\n<p><strong>2.<\/strong> Click  <strong>Settings<\/strong> &gt; <strong>Security<\/strong> and, under <strong>Restricted media types<\/strong>, deselect the <strong>Resource list<\/strong> option.<\/p>\n<p><strong>3.<\/strong> Add your Cloudinary project\u2019s credentials to the <code>.env<\/code> file:<\/p>\n<pre><code>```\nCLOUDINARY_CLOUD_NAME=XXXXXX\nCLOUDINARY_UPLOAD_PRESET=XXXXXX\nSANITY_PROJECT_ID=XXXXXXXXXX\nSANITY_API_TOKEN=xxxxxxxxxxxxxxxx\n```\n<\/code><\/pre>\n<p><strong>4.<\/strong> Edit the <code>Next.config.js<\/code> file to export your Cloudinary credentials.<\/p>\n<p><strong>5.<\/strong> Add the following section under <code>module.exports<\/code> in the <code>Next.config.js<\/code> file:<\/p>\n<pre><code>```  \nconst cloudinaryCloudName = process.env.CLOUDINARY_CLOUD_NAME;\nconst cloudinaryUploadPreset = process.env.CLOUDINARY_UPLOAD_PRESET;\nconst sanityProjectId = process.env.SANITY_PROJECT_ID;\nconst sanityApiToken = process.env.SANITY_API_TOKEN;\nmodule.exports = {\n  distDir: 'dist',\n  target: 'serverless',\n  publicRuntimeConfig: {\n    cloudinaryCloudName: cloudinaryCloudName,\n    cloudinaryUploadPreset: cloudinaryUploadPreset,\n    sanityProjectId: sanityProjectId,\n    sanityApiToken: sanityApiToken\n  },\n  images: {\n    domains: ['res.cloudinary.com']\n  }\n}\n```\n<\/code><\/pre>\n<p><strong>6.<\/strong> Add the Cloudinary script below to the Layout.js file:<\/p>\n<pre><code>```\n[\u2026]\n  return (\n    &lt;&gt;\n      &lt;Head&gt;\n        &lt;style&gt;{dom.css()}&lt;\/style&gt;\n        &lt;title&gt;Your Roommate-Matching App&lt;\/title&gt;\n        &lt;script src=&quot;https:\/\/widget.cloudinary.com\/v2.0\/global\/all.js&quot; type=&quot;text\/javascript&quot;&gt;&lt;\/script&gt;\n[\u2026]\n```\n<\/code><\/pre>\n<p><strong>7.<\/strong> Add to the Netlify settings your Cloudinary credentials as environment variables  with the same names and values as those declared in the <code>Next.config.js<\/code> file.<\/p>\n<p><strong>8.<\/strong> Replace the <code>&lt;img&gt;<\/code> tag with the <code>&lt;Image&gt;<\/code> component from <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/image\"><code>next\/image<\/code><\/a> to eliminate the <a href=\"https:\/\/developers.google.com\/publisher-tag\/guides\/minimize-layout-shift\">layout-shift<\/a> effect on pages that contain images.<\/p>\n<p><strong>9.<\/strong> Create button components to enable users to upload, play, request access to, and approve requests for videos.<\/p>\n<p><strong>10.<\/strong> Modify the upload-button component (the UploadButton.js file) to open the <a href=\"https:\/\/cloudinary.com\/documentation\/upload_widget\">Cloudinary upload widget<\/a> and call the API endpoint to update the room\u2019s image and video URLs:<\/p>\n<pre><code>```\n    var myWidget = cloudinary.createUploadWidget({\n      cloudName: publicRuntimeConfig.cloudinaryCloudName,\n      upload_preset: publicRuntimeConfig.cloudinaryUploadPreset,\n      showAdvancedOptions: true\n    }, (error, result) =&gt; {\n\n      if (result.event == &quot;success&quot;) {\n\n        console.log(result.info);\n\n        if (result.info.resource_type == &quot;image&quot;) {\n          fetch('\/api\/rooms\/' + room._id, {\n            method: 'POST',\n            body: JSON.stringify({ pic: result.info.secure_url }),\n            headers: {\n              'Content-Type': 'application\/json'\n            },\n          })\n          .then(res =&gt; mutate('\/api\/rooms\/' + room._id));\n        }\n\n        if (result.info.resource_type == &quot;video&quot;) {\n          fetch('\/api\/rooms\/' + room._id, {\n            method: 'POST',\n            body: JSON.stringify({ videoId: result.info.public_id }),\n            headers: {\n              'Content-Type': 'application\/json'\n            },\n          })\n          .then(res =&gt; mutate('\/api\/rooms\/' + room._id));\n        }\n      }\n      else {\n        console.log(error);\n      }\n    })\n\n    myWidget.update({tags: ['room-' + room._id]});\n    myWidget.open();\n  }\n```\n<\/code><\/pre>\n<div class='c-callout  c-callout--inline-title c-callout--note'><strong class='c-callout__title'>Note:<\/strong> <p>On Cloudinary\u2019s free plan, the maximum image-file size you can upload is 100 MB. For all the upload limits, see the right-hand side of your <a href=\"https:\/\/cloudinary.com\/users\/login?RelayState=%2Fconsole%2Fsettings%2Faccount\">account settings page<\/a>.<\/p><\/div>\n<p><strong>11.<\/strong> Create a new Details page under the <code>pages\/details\/[id].js<\/code> file and add to the page a component named <code>VideoPlayer<\/code> so that users can watch video and review video requests.<\/p>\n<p><strong>12.<\/strong> Add Cloudinary\u2019s embedded video player to the <code>VideoPlayer.js<\/code> file:<\/p>\n<pre><code>```\nimport getConfig from 'next\/config';\n\nconst { publicRuntimeConfig } = getConfig();\n\nconst VideoPlayer = (props) =&gt; {\n\n  const videoUrl = 'https:\/\/player.cloudinary.com\/embed\/'\n  + '?cloud_name=' + publicRuntimeConfig.cloudinaryCloudName\n  + '&amp;public_id=' + props.room.videoId\n  + '&amp;fluid=true&amp;controls=true&amp;source_types%5B0%5D=mp4';\n\n  return &lt;iframe\n    src={videoUrl}\n    height=&quot;400&quot;\n    allow=&quot;autoplay; fullscreen; encrypted-media; picture-in-picture&quot;\n    allowFullScreen\n    frameBorder=&quot;0&quot;&gt;&lt;\/iframe&gt;\n}\n\nexport default VideoPlayer\n```\n<\/code><\/pre>\n<h2>Walking Through the Roommate Matching App<\/h2>\n<p>Below is how the app works.<\/p>\n<ol>\n<li>\n<p>The owner opens the homepage and, if rooms available for rent are displayed, logs in with the user name and password previously registered with Netlify Identity:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/login-to-roommate-app.png\" alt=\"login to app\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"512\" height=\"268\"\/><\/p>\n<\/li>\n<li>\n<p>When users log in, they can upload videos for the rooms they own by clicking <strong>Upload Media<\/strong>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/available-rooms-2.png\" alt=\"Available rooms\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1000\" height=\"590\"\/><\/p>\n<\/li>\n<li>\n<p>Cloudinary\u2019s upload widget uploads the media (images or videos) for a specific room:\n<img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/roommate-upload-widget.png\" alt=\"Upload widget\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1000\" height=\"829\"\/><\/p>\n<\/li>\n<li>\n<p>The app automatically assigns the media to the room in question.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/upload-queue.png\" alt=\"Upload Queue\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1000\" height=\"829\"\/><\/p>\n<\/li>\n<li>\n<p>The API\u2019s <code>POST<\/code> method in the app accesses the <code>rooms<\/code> collection of the Sanity data store and updates the image and video URLs in the current room\u2019s document.<\/p>\n<\/li>\n<\/ol>\n<p>At this point, the owner can click the play button to verify that the video is in good shape (see the screenshot below). This details page is powered by Cloudinary\u2019s <a href=\"https:\/\/cloudinary.com\/documentation\/video_player_how_to_embed\">cloud-hosted player<\/a>, which you can conveniently embed in an <code>&lt;iframe&gt;<\/code> element.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/video-tour.png\" alt=\"house tour\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1000\" height=\"752\"\/><\/p>\n<p>Now that the video has been uploaded, the room seeker can log in to the app with his or her Netlify Identity credentials:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/roommate-app-login.png\" alt=\"roommate app login\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"380\" height=\"335\"\/><\/p>\n<p>Afterwards, the <strong>Request Video<\/strong> button appears for the room with video uploaded by its owner. The room seeker can then click the button to request permission to watch.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto,dpr_2.0\/Web_Assets\/blog\/request-video.png\" alt=\"Request video\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1000\" height=\"607\"\/><\/p>\n<p>The app then displays the <strong>Request Pending<\/strong> button:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/request-pending.png\" alt=\"Request pending\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"319\" height=\"451\"\/><\/p>\n<p>Since the match event is an agreement between two parties, the room seeker must wait till the room owner opens the room-details page again, takes note of the request, and approves it by clicking <strong>Approve<\/strong>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/f_auto,q_auto\/Web_Assets\/blog\/approved-listing.png\" alt=\"Approved listing\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"512\" height=\"221\"\/><\/p>\n<p>Afterwards, the app displays the <strong>Watch Video<\/strong> button on the room seeker\u2019s page:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto\/Web_Assets\/blog\/watch-video.png\" alt=\"Watch video\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"500\" height=\"308\"\/><\/p>\n<p>By clicking <strong>Watch Video<\/strong>, the room seeker is redirected to the room-details page to watch the video:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/image\/upload\/w_500,c_fill,f_auto,q_auto\/Web_Assets\/blog\/click-watch-video.png\" alt=\"Click watch video\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"500\" height=\"409\"\/><\/p>\n<h2>Moving on to the Next Steps<\/h2>\n<p>The Roommate-Matching App described above demonstrates how to easily configure and integrate frameworks, libraries, and platforms, such as Next.js, Netifly, Sanity, and Cloudinary, to build robust, cloud-based solutions. In particular, by integrating Cloudinary\u2019s first-class APIs and components with your app, you can enable room owners to quickly upload, retrieve, and manage media assets as helpful details for room seekers in quest of the ideal match.<\/p>\n<p>Feel free to use the code and API methods you learned above to integrate video into other apps. To leverage the Cloudinary platform to effectively manage media assets for your apps, first sign up for a <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">free account<\/a>.<\/p>\n<p>Here are more resources offered by Cloudinary:<\/p>\n<ul>\n<li>The <a href=\"https:\/\/cloudinary.com\/documentation\/digital_asset_management_tutorials\">Dashboard Console<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/commanding_cloudinary_through_the_cli\">The command line<\/a>\n<\/li>\n<li>APIs, widgets, and SDKs for <a href=\"https:\/\/cloudinary.com\/products\/programmable_media\">creating personalized media experiences<\/a>\n<\/li>\n<li>The <a href=\"https:\/\/cloudinary.com\/documentation\/advanced_search_tutorial\">media-search feature<\/a>\n<\/li>\n<\/ul>\n<p>Also, check out the <a href=\"https:\/\/nextjs.org\/blog\/next-8#serverless-nextjs\">serverless architecture<\/a> of Next.js.<\/p>\n<p>To obtain the source code of the sample app, download or fork the <a href=\"https:\/\/github.com\/marcelooliveira\/cloudinary-roommates\">GitHub repository<\/a>.<\/p>\n<h2>About the Author<\/h2>\n<p>Marcelo Ricardo de Oliveira is a senior freelance software developer who lives with his lovely wife, Luciana, and his little buddy and stepson, Kau\u00ea, in Guarulhos, Brazil. He is the cofounder of the Brazilian TV Guide and currently works for Alura Cursos Online.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Shortcut to Cloudinary\u2019s solution<\/p>\n","protected":false},"author":41,"featured_media":22375,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[25,119,212,303,305,311],"class_list":["post-22374","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-asset-management","tag-file-upload","tag-next-js","tag-video","tag-video-api","tag-video-transcoding"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Building a Roommate-Matching App With Cloudinary and Jamstack<\/title>\n<meta name=\"description\" content=\"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a Roommate-Matching App With Cloudinary and Jamstack\" \/>\n<meta property=\"og:description\" content=\"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-06-07T13:53:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-05-29T23:15:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1540\" \/>\n\t<meta property=\"og:image:height\" content=\"847\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Building a Roommate-Matching App With Cloudinary and Jamstack\",\"datePublished\":\"2021-06-07T13:53:50+00:00\",\"dateModified\":\"2024-05-29T23:15:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\"},\"wordCount\":13,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA\",\"keywords\":[\"Asset Management\",\"File-upload\",\"Next.js\",\"Video\",\"Video API\",\"Video Transcoding\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2021\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\",\"url\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\",\"name\":\"Building a Roommate-Matching App With Cloudinary and Jamstack\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA\",\"datePublished\":\"2021-06-07T13:53:50+00:00\",\"dateModified\":\"2024-05-29T23:15:09+00:00\",\"description\":\"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA\",\"width\":1540,\"height\":847},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a Roommate-Matching App With Cloudinary and Jamstack\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building a Roommate-Matching App With Cloudinary and Jamstack","description":"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack","og_locale":"en_US","og_type":"article","og_title":"Building a Roommate-Matching App With Cloudinary and Jamstack","og_description":"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.","og_url":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack","og_site_name":"Cloudinary Blog","article_published_time":"2021-06-07T13:53:50+00:00","article_modified_time":"2024-05-29T23:15:09+00:00","og_image":[{"width":1540,"height":847,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack"},"author":{"name":"","@id":""},"headline":"Building a Roommate-Matching App With Cloudinary and Jamstack","datePublished":"2021-06-07T13:53:50+00:00","dateModified":"2024-05-29T23:15:09+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack"},"wordCount":13,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA","keywords":["Asset Management","File-upload","Next.js","Video","Video API","Video Transcoding"],"inLanguage":"en-US","copyrightYear":"2021","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack","url":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack","name":"Building a Roommate-Matching App With Cloudinary and Jamstack","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA","datePublished":"2021-06-07T13:53:50+00:00","dateModified":"2024-05-29T23:15:09+00:00","description":"Build a cloud-based app for matching roommates with Next.js for the UI, Netlify for hosting, Sanity for data storage, and Cloudinary for media management.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA","width":1540,"height":847},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/building_a_roommate_matching_app_with_cloudinary_and_jamstack#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building a Roommate-Matching App With Cloudinary and Jamstack"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718523\/Web_Assets\/blog\/Roommate-matching-app_22375dd352\/Roommate-matching-app_22375dd352.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/22374","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=22374"}],"version-history":[{"count":6,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/22374\/revisions"}],"predecessor-version":[{"id":34113,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/22374\/revisions\/34113"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/22375"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=22374"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=22374"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=22374"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}