How to Add Voice Responses to FormAssembly Forms
FormAssembly lets you run JavaScript on the form page, and that is all Voice Capture needs. One block wires the microphone to your open end — plus the verification step that tells you whether the transcript actually lands in your data, which is the part most setups skip.
Why put voice on a FormAssembly open end
The open end is where a FormAssembly form earns its keep, and it is also where people give up first. Typing a considered paragraph into a phone keyboard is work, so most respondents write the shortest thing that lets them continue.
Across seven client studies we measured, typed answers averaged 10 words and spoken answers to the same questions averaged 23 — about twice as many, from an unchanged questionnaire (how we measured this). Nothing about the form design changes. The respondent gets a microphone button next to the text box, and whoever prefers to type still types.
Voice Capture handles the recording and the transcription. FormAssembly stays your form platform, your logic, your connectors and your data.
FormAssembly is not Formstack
The two names get mixed up constantly, including by people who own an account on one of them. FormAssembly serves forms from tfaforms.com or tfaforms.net and names its fields tfa_1, tfa_2 and so on. If your form URL and field names do not look like that, you are probably on Formstack, which has its own setup.
What you need
One thing: a place to run JavaScript on the page that shows the open end. In FormAssembly that is normally the form's custom code area, and on some plans an HTML element placed at the end of the form does the same job. Check which of the two your plan exposes before you start — everything below assumes the code actually runs.
The block
Replace proj_XXXXXXXX with your project key and set data-lang to the language your fieldwork is in.
<script>
window.__VC_PRELOADED = true;
try {
// FormAssembly names every field tfa_N. Prefer that; fall back to any
// textarea inside the form.
var ta = document.querySelector('textarea[id^="tfa_"]')
|| document.querySelector('.wFormContainer textarea')
|| document.querySelector('form textarea');
if (!ta || !ta.id) {
console.warn('[VoiceCapture] No open-ended field with an id on this page. Microphone not installed.');
} else if (!document.getElementById('gv-container')) {
var wrap = document.createElement('div');
wrap.id = 'gv-container';
wrap.setAttribute('data-project','proj_XXXXXXXX');
wrap.setAttribute('data-target','textarea[id="'+ta.id+'"]');
wrap.setAttribute('data-lang','en');
ta.parentNode.insertBefore(wrap, ta);
if (!document.querySelector(wrap.getAttribute('data-target'))) {
console.warn('[VoiceCapture] data-target does not resolve. The transcript will NOT reach your form.');
}
if (!document.getElementById('gv-script')) {
var s = document.createElement('script');
s.id = 'gv-script';
s.src = 'https://api.voicecapture.ai/voice.js';
s.onload = function(){ try { if (window.GeniusVoice && GeniusVoice.init) GeniusVoice.init(wrap); } catch(e){} };
document.body.appendChild(s);
}
}
} catch(e) {}
</script>
What that block is actually doing
The widget writes the transcript into your form's answer field, and it finds that field through the data-target attribute. The block above sets it for you: it locates the open-ended textarea, reads its id, and points data-target at it.
This is the part worth understanding, because skipping it fails silently. Without a data-target, the widget falls back to a selector that only exists on Alchemer. On a FormAssembly page that fallback matches nothing — and the failure looks like success: the microphone appears, the recording uploads, the transcript shows on screen and lands in your Voice Capture dashboard. The only thing that does not happen is the one that matters. The form field submits empty, and you find out when you export.
Verify it before you field anything
Do not take our word for it, and do not take the microphone appearing as proof. Two checks, in this order.
One. Record ten seconds on the live form, then open your browser console and run:
document.querySelector('textarea[id^="tfa_"]').value
If that returns your transcribed text, the write-back works. If it returns an empty string, the transcript stayed in Voice Capture and never reached the field.
Two. Submit that test response and open it inside FormAssembly. The verbatim has to be there, in its field, on the row. This is the check that actually settles it, and it takes a minute.
Two constraints to design around
One open end per page, visible when the page loads. The block attaches to the first textarea it finds. Two open ends on the same page is ambiguous, and an open end hidden behind conditional logic does not exist yet at the moment the code runs.
Iframes break it. The widget and the field have to live in the same document. If you embed your FormAssembly form in an iframe on another site, document.querySelector cannot cross that boundary and data-target will never resolve. Use the hosted form URL, or put the block inside the iframed document.
How transcripts join your data
Here FormAssembly is easier than most platforms, and it is worth saying why. On a survey platform that gives the widget nothing to identify the response, you have to wire a response id into a data-session attribute or you end up matching transcripts to interviews by timestamp — which is tolerable for a handful of tests and thoroughly unpleasant on a real sample.
On FormAssembly you do not need any of that, provided the write-back works. The transcript is written into a normal form field, so it travels in the same submission, on the same row, into the same export and the same connector you already use. There is nothing to join.
Which is exactly why the verification step above is not a formality. It is the difference between an integration that delivers data and one that quietly does not.
If the field is not found
The block writes a warning to the browser console rather than failing silently. Open the console on the form page and look for a line starting with [VoiceCapture]. If it says it found no field with an id, the selector needs adjusting to your form's markup — the generic embed guide covers how to pin down a stable selector, and you can set data-target by hand once you know it.
Ready to add voice to your surveys?
Start free — no credit card required. Setup takes 2 minutes.
Try Voice Capture Free