{"id":28538,"date":"2022-04-06T02:45:26","date_gmt":"2022-04-06T02:45:26","guid":{"rendered":"http:\/\/track-video-impressions-in-next.js-with-supabase"},"modified":"2022-04-06T02:45:26","modified_gmt":"2022-04-06T02:45:26","slug":"track-video-impressions-in-next-js-with-supabase","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/","title":{"rendered":"Track Video Impressions in Next.js with Supabase"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Tracking impressions is one of the most effective techniques for determining how well media content performs. An individual can determine which content and information users are most interested in depending on the number of impressions.<\/p>\n<p>A lot of applications now have either <a href=\"https:\/\/analytics.google.com\/\">Google <\/a>or <a href=\"https:\/\/usefathom.com\/ref\/45XEAJ\">Fathom <\/a>analytics integrated for tracking impressions, but the increasing presence of ad-blockers interferes with the generated reports \u2014 and more often than not, the statistics collected by these providers are inaccurate. However, these inaccurate reports can be solved by creating an impression tracker using a <a href=\"https:\/\/www.simform.com\/blog\/serverless-databases\/\">serverless database<\/a>.<\/p>\n<p>A serverless database is any database that embodies the core principles of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Serverless_computing\">the serverless computing paradigm<\/a>, such as little to no manual server management and instant access. The benefit of doing so is obtaining a more accurate count of impressions.<\/p>\n<p>This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.<\/p>\n<h3>CodeSandbox and GitHub<\/h3>\n<p>The completed project is on <a href=\"https:\/\/codesandbox.io\/s\/nifty-tdd-hdgcl9?file=\/pages\/index.js\">CodeSandbox<\/a>. Fork it to get started quickly.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/nifty-tdd-hdgcl9?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"Track video impressions in Next.js with Supabase\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><p>The source code is on <a href=\"https:\/\/github.com\/ugwutotheeshoes\/supabase-impression\">GitHub<\/a>.<\/p>\n<h3>Prerequisites<\/h3>\n<p>To get the most out of this article, the following requirements apply:<\/p>\n<ul>\n<li>A basic understanding of CSS, <a href=\"https:\/\/en.wikipedia.org\/wiki\/JavaScript\">JavaScript<\/a>, and <a href=\"https:\/\/reactjs.org\/\">React.js<\/a>.<\/li>\n<li>A Supabase account \u2014 Create one <a href=\"https:\/\/app.supabase.io\/\">here<\/a>.<\/li>\n<li>A Cloudinary account \u2014 Create one <a href=\"https:\/\/cloudinary.com\/homepage-2\">here<\/a>.<\/li>\n<\/ul>\n<h3>What is Supabase?<\/h3>\n<p><a href=\"https:\/\/app.supabase.io\/\">Supabase <\/a>is an open-source <a href=\"https:\/\/firebase.google.com\/\">Firebase <\/a>alternative. Supabase is a set of tools that helps developers build projects faster by handling the backend functions.<\/p>\n<p>Behind the scenes, Supabase uses the <a href=\"https:\/\/www.postgresql.org\/\">PostgreSQL <\/a>database. It is regarded widely as one of the best tools based on Postgres, a highly scalable relational database. The platform develops a REST API from the database\u2019s tables and columns. Its autogenerated APIs include built-in features like filtering and sorting.<\/p>\n<h3>Project setup and installation<\/h3>\n<p>Create a Next.js app in a new folder by running the following command in your terminal:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/78df2d12826e17be742260ad740db0bd099b415c-1349x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1349\" height=\"663\"\/><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">   npx create-next-app <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">project-name<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Navigate into the project directory and install Cloudinary React SDK and Supabase dependencies.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">    cd <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">project-name<\/span>&gt;<\/span>\n    npm install cloudinary-react @supabase\/supabase-js\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Running <code>npm run dev<\/code> starts the project on the local development server at <a href=\"https:\/\/localhost:3000\">https:\/\/localhost:3000<\/a> in our browser.<\/p>\n<h3>Setting up a video in Cloudinary<\/h3>\n<p>After successfully creating an account, Cloudinary will redirect us to our account\u2019s dashboard page, where we can upload the demo video.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/78df2d12826e17be742260ad740db0bd099b415c-1349x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1349\" height=\"663\"\/><\/p>\n<p>Set a name and password for the new project and click on the \u201cNew Project\u201d button to create the project, as shown below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/8d7e586a6d707118c695305068e04781217e2653-1366x759.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1366\" height=\"759\"\/><\/p>\n<p>As the project is being built, we\u2019ll create the database for the video impressions by clicking on the database icon shown on the sidebar. After that, click on the \u201cNew\u201d button at the top right of the screen to create a table for the database.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/41c85364dce73919432c4faab1a6968b8c9d5d94-1366x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1366\" height=\"663\"\/><\/p>\n<p>Navigate to the SQL editor and create a query tab to add a stored procedure to our database. A stored procedure allows us to add or extend functionality to the database.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/b2b197706474852379e244cbee7bd3057e93be42-1366x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1366\" height=\"663\"\/><\/p>\n<p>Add the code snippet below to the new query to create the stored procedure for our database.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">\n    create <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">increment<\/span> (<span class=\"hljs-params\">row_id int<\/span>)\n    <span class=\"hljs-title\">returns<\/span> <span class=\"hljs-title\">void<\/span> <span class=\"hljs-title\">as<\/span>\n    <span class=\"hljs-title\">$$<\/span>\n      <span class=\"hljs-title\">update<\/span> <span class=\"hljs-title\">pages<\/span>\n      <span class=\"hljs-title\">set<\/span> <span class=\"hljs-title\">views<\/span> = <span class=\"hljs-title\">views<\/span> + 1\n      <span class=\"hljs-title\">where<\/span> <span class=\"hljs-title\">id<\/span> = <span class=\"hljs-title\">row_id<\/span>;\n    <span class=\"hljs-title\">$$<\/span> \n    <span class=\"hljs-title\">language<\/span> <span class=\"hljs-title\">sql<\/span> <span class=\"hljs-title\">volatile<\/span>;\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s break down the query above.<\/p>\n<ul>\n<li>The query creates an increment function, with the row <code>id<\/code> as an argument.<\/li>\n<li>\n<code>set views = views + 1<\/code> updates\/increases the video impressions value called <code>views<\/code> in the database table by 1.<\/li>\n<\/ul>\n<p>Then, click the \u201cRUN\u201d button to create the function. Later we\u2019ll utilize the function to update the video impressions.<\/p>\n<h3>Accessing the API URL and API Key<\/h3>\n<p>To link the Supabase database to our demo application, we\u2019ll head to Supabase\u2019s homepage, where we can access our Supabase project\u2019s API URL and API Key as shown below:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/8e5312265f723fc74b59e9869294e927b5850738-1349x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1349\" height=\"663\"\/><\/p>\n<p>We need to create a <code>.env<\/code> file in the app\u2019s root directory to store the API URL and API Key.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    <span class=\"hljs-comment\">#.env<\/span>\n    NEXT_PUBLIC_SUPABASE_URL= OUR_PUBLIC_SUPABASE_URL\n    NEXT_PUBLIC_SUPABASE_KEY= OUR_PUBLIC_SUPABASE_KEY\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we\u2019ll create a file called <code>Supabase.js<\/code> in <code>pages\/components<\/code> and then add the following code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">\n    <span class=\"hljs-comment\">\/\/pages\/components\/Supabase.js<\/span>\n    <span class=\"hljs-keyword\">import<\/span> { createClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@supabase\/supabase-js\"<\/span>;\n    \n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> supabase = createClient(\n      process.env.NEXT_PUBLIC_SUPABASE_URL,\n      process.env.NEXT_PUBLIC_SUPABASE_KEY\n    );\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h3>Implementing the video player<\/h3>\n<p>To access the video for the demo application, import the required components from Cloudinary React SDK to <code>pages\/components\/index.js<\/code> as shown below.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> {Video, CloudinaryContext} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary-react'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, in the <code>CloudinaryContext<\/code> component, apply the Cloud name from our Cloudinary account details on the dashboard page and also include the name of the video in the Video component:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryContext<\/span> <span class=\"hljs-attr\">cloud_name<\/span>=<span class=\"hljs-string\">\"ugwutotheeshoes\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n         <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Video<\/span>\n           <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">\"production_ID_3959604_vnbhqn\"<\/span>\n           <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"850px\"<\/span>\n           <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"450px\"<\/span>\n           <span class=\"hljs-attr\">controls<\/span>\n           <span class=\"hljs-attr\">innerRef<\/span>=<span class=\"hljs-string\">{videoRef}<\/span>\n           <span class=\"hljs-attr\">onEnded<\/span>=<span class=\"hljs-string\">{endFunction}<\/span>\n         \/&gt;<\/span>\n       <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">CloudinaryContext<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019ll also apply some configuration parameters to the video, as shown above. Each of the parameters does the following:<\/p>\n<ul>\n<li>\n<code>publicId<\/code> &#8211; This holds the name of the demo video.<\/li>\n<li>\n<code>width<\/code> and <code>height<\/code> &#8211; Displays the video with a width of 850px and a height of 450px<\/li>\n<li>\n<code>controls<\/code> &#8211; Gives the video a set of controls such as play, pause, skip, fullscreen, etc.<\/li>\n<li>\n<code>innerRef<\/code> &#8211; This is just another attribute on the custom component in Cloudinary.<\/li>\n<li>\n<code>onEnded<\/code> &#8211; This triggers a function after the video finishes.<\/li>\n<\/ul>\n<p>After configuring the video player, our demo application will look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/b1664442e62e88807e652efcdba5a7079a719ca9-1366x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1366\" height=\"663\"\/><\/p>\n<h3>Updating the video impressions<\/h3>\n<p>Next, we\u2019ll import the <code>Supabase.js<\/code> file to access the API URL and API Key, then use the <code>onEnded<\/code> event to update the video impressions in Supabase using the code snippet below.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-comment\">\/\/pages\/components\/index.js<\/span>\n    <span class=\"hljs-keyword\">import<\/span> {supabase} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/supabase\"<\/span>;\n    \n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> endFunction = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> { data} = <span class=\"hljs-keyword\">await<\/span> supabase.rpc(<span class=\"hljs-string\">'increment'<\/span>, { <span class=\"hljs-attr\">row_id<\/span>: <span class=\"hljs-number\">1<\/span> })\n      };\n     <span class=\"hljs-comment\">\/\/ ....<\/span>\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>onEnded<\/code> event occurs when the video has reached the end. The event invokes a function or message when the video ends.<\/p>\n<p>In this instance, we\u2019ll call the <code>endFunction<\/code> function using a Supabase Remote Procedure Call (RPC) after the video ends. This function call updates the video impressions, as shown below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/f6a6a2ad49b3ca612be87d66c2835370aee31855-1349x663.png\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1349\" height=\"663\"\/><\/p>\n<p>After testing our demo application, it should look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams_sanity\/947eb9995915e75601136e3c5b49ee076c53e442-600x338.gif\" alt=\"image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"600\" height=\"338\"\/><\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28539,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[332,134,370,385,212,371],"class_list":["post-28538","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-api","tag-guest-post","tag-image","tag-netlify","tag-next-js","tag-under-review"],"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>Track Video Impressions in Next.js with Supabase<\/title>\n<meta name=\"description\" content=\"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.\" \/>\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\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Track Video Impressions in Next.js with Supabase\" \/>\n<meta property=\"og:description\" content=\"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-04-06T02:45:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"500\" \/>\n\t<meta property=\"og:image:height\" content=\"350\" \/>\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\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Track Video Impressions in Next.js with Supabase\",\"datePublished\":\"2022-04-06T02:45:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA\",\"keywords\":[\"API\",\"Guest Post\",\"Image\",\"Netlify\",\"Next.js\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\",\"name\":\"Track Video Impressions in Next.js with Supabase\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA\",\"datePublished\":\"2022-04-06T02:45:26+00:00\",\"description\":\"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA\",\"width\":500,\"height\":350},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Track Video Impressions in Next.js with Supabase\"}]},{\"@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":"Track Video Impressions in Next.js with Supabase","description":"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.","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\/guest_post\/track-video-impressions-in-next-js-with-supabase\/","og_locale":"en_US","og_type":"article","og_title":"Track Video Impressions in Next.js with Supabase","og_description":"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-04-06T02:45:26+00:00","og_image":[{"width":500,"height":350,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/"},"author":{"name":"","@id":""},"headline":"Track Video Impressions in Next.js with Supabase","datePublished":"2022-04-06T02:45:26+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","keywords":["API","Guest Post","Image","Netlify","Next.js","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/","name":"Track Video Impressions in Next.js with Supabase","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","datePublished":"2022-04-06T02:45:26+00:00","description":"This article demonstrates how to track video impressions using Next.js and Supabase \u2014 a serverless database.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","width":500,"height":350},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/track-video-impressions-in-next-js-with-supabase\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Track Video Impressions in Next.js with Supabase"}]},{"@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\/v1681924306\/Web_Assets\/blog\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb\/cb2be4de436744f8368445c3516854c3de7e3131-500x350-1_2853999deb.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28538","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=28538"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28538\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28539"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28538"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28538"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28538"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}