{"id":43299,"date":"2026-01-09T17:03:37","date_gmt":"2026-01-09T11:33:37","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=43299"},"modified":"2026-01-09T17:16:28","modified_gmt":"2026-01-09T11:46:28","slug":"automating-diagnostic-audio-playback-in-dynamics-365-using-javascript","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2026\/01\/automating-diagnostic-audio-playback-in-dynamics-365-using-javascript\/","title":{"rendered":"Automating Diagnostic Audio Playback in Dynamics 365 using JavaScript"},"content":{"rendered":"<p><img decoding=\"async\" class=\"alignnone size-full wp-image-43307\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-scaled.png\" alt=\"JavaScript\" width=\"2560\" height=\"1463\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-scaled.png 2560w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-300x171.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-1024x585.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-768x439.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-1536x878.png 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-2048x1170.png 2048w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/Automating-Diagnostic-Audio-Playback-in-Dynamics-365-using-JavaScript-660x377.png 660w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/p>\n<p>This technical guide explains how to play audio files stored in a Dataverse File column directly inside Dynamics 365 using JavaScript. It is intended for Dynamics 365 developers, system customizers, and solution architects who want to enhance model-driven apps with audio-based diagnostics, alerts, or voice context.<\/p>\n<p>Dynamics 365 is designed to organize your data. It effortlessly captures text, numbers, and dates. However, the real world is multimodal, it consists of sounds, voices, and noises that often get lost when we try to compress them into a standard text column.<\/p>\n<p>When a user reads a paragraph to understand a situation, they are performing an active, high-cognitive task. When they hear a sound, the understanding is passive and instant.<\/p>\n<p>In this blog, we unlock the audio dimension of CRM. By combining the standard Dataverse File data type with a JavaScript web resource, we can make Dynamics 365 records \u201cspeak\u201d to users, providing context that text alone cannot capture.<\/p>\n<h3><strong>Prerequisites<\/strong><\/h3>\n<p>Before you begin, ensure you have:<\/p>\n<ul>\n<li>Access to a Dataverse\/Dynamics 365<\/li>\n<li>System Customizer or System Administrator<\/li>\n<\/ul>\n<h3><strong>Step 1: Create the File Column<\/strong><\/h3>\n<p>We need a dedicated place to store the unique audio file for each record.<\/p>\n<ol>\n<li>Go to Power Apps and open your Solution.<\/li>\n<li>Navigate to the target<\/li>\n<li>Create a new column with File data type.<\/li>\n<li>Add this column to your Entity Main Form.<\/li>\n<\/ol>\n<h3><img decoding=\"async\" class=\"alignnone size-full wp-image-43302\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1.jpg\" alt=\"JavaScript\" width=\"1170\" height=\"626\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1.jpg 1170w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1-300x161.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1-1024x548.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1-768x411.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript1-660x353.jpg 660w\" sizes=\"(max-width: 1170px) 100vw, 1170px\" \/><\/h3>\n<h3><strong>Step 2: The JavaScript Logic <\/strong><\/h3>\n<ol>\n<li>Create a JavaScript Web Resource.<\/li>\n<\/ol>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-43303\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-scaled.jpg\" alt=\"JavaScript\" width=\"2560\" height=\"1463\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-scaled.jpg 2560w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-300x171.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-1024x585.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-768x439.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-1536x878.jpg 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-2048x1170.jpg 2048w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript2-660x377.jpg 660w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/><\/p>\n<ol start=\"2\">\n<li>Paste the following JavaScript code:<\/li>\n<\/ol>\n<pre class=\"lang:css gutter:true start:1\">var SoundApp = window.SoundApp || {};SoundApp.CurrentAudio = null; \/\/ Store the audio instance to control it later\u00a0SoundApp.Logic = (function () {\u00a0\u00a0\u00a0\u00a0 \/**\u00a0\u00a0\u00a0\u00a0 * Retrieves the file from the current record and plays it.\u00a0\u00a0\u00a0\u00a0 * Bind this to the OnChange event of your trigger field.\u00a0\u00a0\u00a0\u00a0 *\/\u00a0\u00a0\u00a0 function playAudioFromField(executionContext) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var formContext = executionContext.getFormContext();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 1. Ensure record is saved\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (formContext.ui.getFormType() === 1) { \/\/ 1 = Create\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 2. CONFIGURATION\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var fileColumnName = \"diagnosticaudio\"; \/\/ Your File Column Logical Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var entitySetName = \"incidents\";\u00a0 \/\/Your Entity name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ API Set Name \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 3. CHECK IF FILE EXISTS\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var fileAttribute = formContext.getAttribute(fileColumnName);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!fileAttribute || fileAttribute.getValue() == null) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 4. STOP PREVIOUS AUDIO \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (SoundApp.CurrentAudio) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SoundApp.CurrentAudio.pause();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SoundApp.CurrentAudio.currentTime = 0;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 5. CONSTRUCT API URL\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var recordId = formContext.data.entity.getId().replace(\/[{}]\/g, \"\");\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var clientUrl = Xrm.Utility.getGlobalContext().getClientUrl();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var audioUrl = clientUrl + \"\/api\/data\/v9.2\/\" + entitySetName + \"(\" + recordId + \")\/\" + fileColumnName + \"\/$value\";\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ 6. PLAY AUDIO\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SoundApp.CurrentAudio = new Audio(audioUrl);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var playPromise = SoundApp.CurrentAudio.play();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (playPromise !== undefined) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 playPromise.then(function () {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ Audio started successfully\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }).catch(function (error) {\/\/Error\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0}\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } catch (e) {\/\/Error\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\u00a0\u00a0\u00a0 }\u00a0\u00a0\u00a0\u00a0 return {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 playAudioFromField: playAudioFromField\u00a0\u00a0\u00a0 };})();<\/pre>\n<h3><strong>Step 3: Configure the Trigger<\/strong><\/h3>\n<p>Now, add the script to the form so it reacts to user input.<\/p>\n<ol>\n<li>Open your Entity Form<\/li>\n<li>Select the field that should trigger the sound (e.g., Status Reason or a custom &#8220;Audio&#8221; Checkbox).<\/li>\n<li>In the Events tab, add an On-Change event handler and call your JavaScript function.<\/li>\n<li>Save and Publish.<\/li>\n<\/ol>\n<h3><img decoding=\"async\" class=\"alignnone size-full wp-image-43304\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3.jpg\" alt=\"JavaScript\" width=\"1563\" height=\"645\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3.jpg 1563w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3-300x124.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3-1024x423.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3-768x317.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3-1536x634.jpg 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript3-660x272.jpg 660w\" sizes=\"(max-width: 1563px) 100vw, 1563px\" \/><\/h3>\n<h3><strong>Step 4: Test the Functionality<\/strong><\/h3>\n<ol>\n<li>Open modified form in Dynamics 365.<\/li>\n<li>Upload a standard .mp3 or .wav file into your new Diagnostic Audio<\/li>\n<li>Change the value of your trigger field (e.g., flip the &#8220;Audio&#8221; checkbox).<\/li>\n<li>Listen: The browser should immediately stream and play the audio file.<\/li>\n<\/ol>\n<h3><img decoding=\"async\" class=\"alignnone size-full wp-image-43305\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4.jpg\" alt=\"JavaScript\" width=\"1093\" height=\"477\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4.jpg 1093w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4-300x131.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4-1024x447.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4-768x335.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/01\/JavaScript4-660x288.jpg 660w\" sizes=\"(max-width: 1093px) 100vw, 1093px\" \/><\/h3>\n<h3><strong>Real-World Examples<\/strong><\/h3>\n<p>Here is how this functionality solves actual business problems:<\/p>\n<ul>\n<li>Remote Diagnostics (Field Service): Technicians record machine noises and attach them to Work Orders. Experts at HQ listen instantly to identify mechanical faults without traveling on-site.<\/li>\n<li>Sentiment Analysis (Customer Service): Agents listen to angry voicemails <em>before<\/em> calling a customer back. This allows them to gauge emotion and prepare the right empathetic tone.<\/li>\n<li>Verbal Contracts (Sales): Sales reps attach verbal approvals to Opportunities. Legal teams can audit the deal by simply clicking play, rather than searching through call logs.<\/li>\n<\/ul>\n<h3><strong>Bonus Tip: Playing a Static Notification Sound<\/strong><\/h3>\n<p>Sometimes you don&#8217;t need a unique file per record; you just want a standard &#8220;Ping&#8221; or \u201cBuzz\u201d sound when a field changes (like a high-priority alert).<\/p>\n<p>Since Dynamics Web Resources don&#8217;t natively support MP3 upload, you can use this workaround:<\/p>\n<ol>\n<li>Rename your sound file from .mp3 to .png extension.<\/li>\n<li>Upload it as a Web Resource.<\/li>\n<li>Use the following code to play it:<\/li>\n<\/ol>\n<p>JavaScript<\/p>\n<pre class=\"lang:css gutter:true start:1\">function playStaticSound() {\u00a0\u00a0\u00a0 \/\/ Get the base URL\u00a0\u00a0\u00a0 var clientUrl = Xrm.Utility.getGlobalContext().getClientUrl();\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\/\/ Construct path to Web Resource\u00a0\u00a0\u00a0 var soundUrl = clientUrl + \"\/WebResources\/your_Webresource\";\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0var audio = new Audio(soundUrl);\u00a0\u00a0\u00a0 audio.play().catch(function(e) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0});}<\/pre>\n<h3><strong>FAQs<\/strong><\/h3>\n<h3><strong>Can Dynamics 365 play audio files stored in Dataverse?<\/strong><\/h3>\n<p>Yes. Audio files stored in a Dataverse File column can be played in Dynamics 365 using JavaScript and the Dataverse Web API.<\/p>\n<h3><strong>What audio formats are supported?<\/strong><\/h3>\n<p>Browser-supported formats such as .mp3 and .wav work best for Dynamics 365 audio playback.<\/p>\n<h3><strong>Does this solution require plugins or server-side code?<\/strong><\/h3>\n<p>No. This is a fully client-side solution using JavaScript web resources.<\/p>\n<h3><strong>Is this supported in model-driven apps?<\/strong><\/h3>\n<p>Yes. This approach works in Dynamics 365 model-driven apps where File columns and JavaScript are supported.<\/p>\n<h3><strong>\u00a0<\/strong><strong>Conclusion<\/strong><\/h3>\n<p>By implementing this approach, you transform static Dynamics 365 records into interactive, context-rich tools. Instead of relying solely on text, you capture real-world signals like noise, tone, and voice and deliver them directly within the CRM interface.<\/p>\n<p>This solution is especially valuable for Dynamics 365 developers looking to enhance model-driven apps using standard Dataverse capabilities and lightweight client-side JavaScript, without plugins or complex infrastructure.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This technical guide explains how to play audio files stored in a Dataverse File column directly inside Dynamics 365 using JavaScript. It is intended for Dynamics 365 developers, system customizers, and solution architects who want to enhance model-driven apps with audio-based diagnostics, alerts, or voice context. Dynamics 365 is designed to organize your data. It\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2026\/01\/automating-diagnostic-audio-playback-in-dynamics-365-using-javascript\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[2354,33,2361],"tags":[],"class_list":["post-43299","post","type-post","status-publish","format-standard","hentry","category-dataverse","category-javascript","category-technical"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/43299","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=43299"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/43299\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=43299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=43299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=43299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}