Adding sound effects to your ERPNext/Frappe interface can greatly improve user interaction, feedback, and even bring a little fun into routine workflows. In this article, we’ll walk through three professional ways to play audio on button click within a Frappe form.
We’ll cover:
- Method 1: Using
frappe.utils.play_sound()
withhooks.py
- Method 2: Manually embedding and playing audio
- Method 3: Using the browser’s Text-to-Speech API to speak messages
Method 1: Using frappe.utils.play_sound()
with hooks.py
This is the cleanest and Frappe-native approach. It allows you to register sound assets in your
hooks.py
file and play them with just a single line of JavaScript.
custom_module/
└── public/
└── sounds/
└── sound.mp3
hooks.py
sounds = [
{
"name": "test",
"src": "/assets/custom_module/sounds/sound.mp3",
"volume": 0.1
}
]
JavaScript
frappe.ui.form.on('Doctype', {
refresh(frm) {
frm.add_custom_button(__('Play Sound'), function() {
frappe.utils.play_sound('test');
});
}
});
It’s efficient, integrates into Frappe’s asset system, and is easy to reuse across your app.
Method 2: Dynamic Audio Element with Cache Busting
Want more control? This method creates an
<audio>
tag on the fly and plays it. We also add a unique timestamp to prevent caching issues.
custom_module/
└── public/
└── sounds/
└── sound.mp3
JavaScript
frappe.ui.form.on('Doctype', {
refresh(frm) {
frm.add_custom_button(__('Play Sound'), function() {
var audio = document.createElement('audio');
var uniqueTimestamp = new Date().getTime();
audio.src = '/assets/custom_module/sounds/sound.mp3?timestamp=' + uniqueTimestamp;
audio.play().catch(function(error) {
console.error("Playback failed:", error);
});
});
}
});
Ideal when you’re not registering the sound in hooks.py
, or when you want to dynamically control the file source.
Method 3: Speak with a Siri-like Voice
This method uses the browser’s SpeechSynthesis API to read out a response like “I am fine” when a button is clicked — great for making your UI more interactive or accessible.

frappe.ui.form.on('Doctype', {
refresh: function(frm) {
frm.add_custom_button(__('How are you?'), function() {
function speakWithSiriVoice() {
const msg = new SpeechSynthesisUtterance("I am fine");
const voices = speechSynthesis.getVoices();
const siriLikeVoice = voices.find(voice =>
voice.name.toLowerCase().includes("samantha") ||
voice.name.toLowerCase().includes("karen") ||
voice.name.toLowerCase().includes("moira")
);
msg.voice = siriLikeVoice || voices[0];
msg.pitch = 1;
msg.rate = 1;
window.speechSynthesis.speak(msg);
}
if (speechSynthesis.getVoices().length === 0) {
speechSynthesis.onvoiceschanged = () => {
speakWithSiriVoice();
};
} else {
speakWithSiriVoice();
}
});
}
});
It doesn’t require any audio files — pure voice generation from text. Great for greetings, confirmations, or fun user feedback.
Thank You!