Which case is for you?
Case A – simple, for everyone: every demo request lands in a Google Sheet you use as a CRM, and you get an e-mail.
Case B – for teams using a CRM: every demo request becomes a lead in HubSpot, ready for your sales team.
A visitor fills in your demo request form, and seconds later the lead is in your CRM. A small business gets a new row in its leads sheet and an e-mail it can reply to; a sales team gets a new contact in HubSpot. Either way, you're talking to the lead while they're still on your website.
This is the e-mail you get for every new demo request in Case A:
And this is the new contact in HubSpot in Case B:
How this works. Survio sends each completed response to a webhook URL. An automation tool (we use n8n in this guide) receives it and writes the lead where you work. Survio does the sending, n8n does the rest.
New to webhooks in Survio? Start with Webhooks: send responses to your other tools in real time, then come back here.
What you'll build
Both cases start the same way: a short demo request form on your website, sent to n8n by a webhook.
At a glance | Case A: a sheet as your CRM | Case B: HubSpot |
Result | Each request is a row in Google Sheets with a Status column, and you get an e-mail | Each request is a new contact in HubSpot CRM, ready for your sales team |
Tools | Survio, n8n, Google Sheets, Gmail | Survio, n8n, HubSpot |
Best for | A small business that follows up on leads by itself | A sales team that already works in HubSpot |
Before you start
A Survio survey on a paid plan. Webhooks aren't available on the Free plan, and each plan allows a set number of webhooks per survey (see the webhooks article).
An n8n account, n8n Cloud or self-hosted.
Case A: a Google account for Google Sheets and Gmail. Case B: a HubSpot account.
In this guide we use a short demo request form: name, work e-mail (an e-mail question), company, team size (a choice question) and an optional "What would you like to see in the demo?". Your form can look different; you map your own questions in Case A or Case B.
Step 1 — Put the form on your website
Open your survey, go to Get responses and choose On the web.
Pick Pop-up window and set when it appears. For a short form, switch on Hide the welcome page so visitors start with the first question.
Click Embed on website and paste the code into your website.
More options, such as a button or a side-bar widget, are in Embed a survey on your website.
Step 2 — Case A only: prepare the leads sheet
Create a new Google Sheet and rename its first tab to
leads.In row 1, type the column headers:
Response ID,Received,Name,E-mail,Company,Team size,What they want to see,StatusandLanguage.Select the cells of the Status column below the header, choose Insert → Dropdown, add the options New, Contacted and Done (use Add another item), and click Done.
Your sheet is now a simple CRM. New leads arrive as New. When you've called or written to someone, switch them to Contacted, and to Done when the deal is closed or lost. Filter the Status column to see who still needs an answer.
Step 3 — Create the webhook in n8n
In n8n, create a new workflow and add a Webhook node as the trigger.
Set HTTP Method to POST.
Switch to the Production URL tab and copy the address.
Click Publish. The production URL only accepts deliveries once the workflow is published.
Use the Production URL, not the Test URL. The Test URL only listens while the editor is waiting for a test event, so Survio's deliveries fail as soon as you close it. Survio retries a failed delivery for about a day, and after 5 days of failures it switches the webhook off.
Step 4 — Connect the survey in Survio
Open your survey and go to Get responses.
In the left sidebar under Automations & Integrations, select Webhooks and click + Add a webhook.
Paste the n8n Production URL into Webhook URL and click Save webhook. The webhook is switched on straight away.
Step 5 — Send a test request and find your question ids
Fill in your form through its normal link and submit it. Survio sends only completed responses, so click through to the end.
In n8n, open the Executions tab. The delivery arrives within a few seconds.
Open the execution and click the Webhook node. Expand
body, thendata, thenanswers. Each answer shows itsquestion.id, the questionlabeland theanswer.Write down the id of each question. You can also click Pin to keep building against this response without submitting the form again.
Always pick answers by question id. Answers arrive as a list. If you later add a question to the form, positions in the list shift. Question ids never change.
The lead's e-mail is in the answers. Don't use data.email: it stays empty when the e-mail comes from an e-mail question. Read it from the answer to your e-mail question.
Case A — A sheet as your CRM, plus an e-mail
The workflow has three steps after the webhook: Prepare lead picks the answers out of the response, Save lead to sheet adds the row, and E-mail the new lead tells you about it.
Prepare lead
Add an Edit Fields (Set) node after the Webhook node and rename it to
Prepare lead.Under Fields to Set, add one field for each column of your sheet and keep its type String. The field name must match the column header exactly; the value is the expression below.
Replace the question ids (90403243 and so on) with the ids you wrote down in Step 5, and Europe/Prague with your time zone.
Field name | Value |
Response ID |
|
Received |
|
Name |
|
| |
Company |
|
Team size |
|
What they want to see |
|
Status |
|
Language |
|
Save lead to sheet
Add a Google Sheets node after Prepare lead, rename it to
Save lead to sheetand choose the operation Append or Update Row.Connect your Google account, then pick your spreadsheet under Document and the
leadstab under Sheet.Set Mapping Column Mode to Map Automatically and Column to match on to Response ID.
Under Options, add Cell Format and choose Let n8n format. Otherwise Google Sheets turns answers like 2-10 into dates.
Why a separate Prepare lead step? When you pick a different spreadsheet or tab in the Google Sheets node, n8n clears the column mapping inside that node. With the expressions in Prepare lead, nothing is lost.
E-mail the new lead
Add a Gmail node after Save lead to sheet, rename it to
E-mail the new lead, and choose Message and Send.Connect your Gmail account and put your own address in To.
Set Subject to
New demo request: {{ $('Prepare lead').item.json.Name }} ({{ $('Prepare lead').item.json.Company }}).Set Email Type to HTML and write the Message with the lead's details, for example
{{ $('Prepare lead').item.json['E-mail'] }}for the e-mail address.Under Options, add Send Replies To with
{{ $('Prepare lead').item.json['E-mail'] }}, so that Reply goes straight to the lead, and turn off Append n8n Attribution.
Click Publish again. Changes you make after publishing go live only when you publish again.
Submit another request. A new row with the status New appears in your sheet, and the e-mail from the top of this article arrives a moment later.
Case B — Send every demo request to HubSpot
Here the lead goes straight into HubSpot CRM as a contact with the lifecycle stage Lead, so your sales team picks it up where they already work. The workflow has two steps after the webhook: Prepare lead and Create or update contact.
Prepare lead
Add an Edit Fields (Set) node after the Webhook node, rename it to Prepare lead, and add these String fields. Replace the question ids with your own.
Field name | Value |
| |
First name |
|
Last name |
|
Company |
|
Message |
|
The First name and Last name fields split the name from a single "Your name" question. If your form asks for first and last name separately, pick each answer by its own question id instead.
Create or update contact
Add a HubSpot node after Prepare lead, rename it to
Create or update contact, and choose the resource Contact and the operation Create or Update.Connect your HubSpot account.
Set Email to
{{ $json['E-mail'] }}. HubSpot uses the e-mail to find an existing contact, so a returning lead is updated instead of duplicated.Under Contact Properties, click Add Property and add First Name, Last Name, Company Name and Message with the matching fields from Prepare lead, and set Lifecycle Stage Name or ID to Lead.
Click Publish again.
The contact may be linked to a company automatically. If HubSpot finds a company with the same e-mail domain, it associates the new contact with it, and the contact can take over that company's owner. That's usually what you want; check it once with a test request.
Get the ready-made workflow
Instead of building Step 3 and your case by hand, start from our workflow. Download the file for your case from the attachments at the end of this article: survio-demo-requests-to-sheet-and-gmail.json for Case A, or survio-demo-requests-to-hubspot.json for Case B. Then:
In n8n, create an empty workflow. Open the menu (three dots) next to the workflow name and choose Import, then From file. Pick the file you downloaded.
Open Prepare lead and replace the question ids with your own, and in Case A also Europe/Prague with your time zone.
Case A: open Save lead to sheet. It shows a red warning sign until it's set up. Connect your Google account and pick your spreadsheet and its
leadstab. n8n then switches Mapping Column Mode to Map Each Column Manually: set it back to Map Automatically and set Column to match on to Response ID. Then open E-mail the new lead, connect your Gmail account and put your own address in To.Case B: open Create or update contact and connect your HubSpot account.
Open Survio Webhook, copy the Production URL into Survio (Step 4) and click Publish.
Test it end to end
Open your website, fill in the pop-up form and submit it.
Case A: check that a row with the status New appears on the
leadstab and that the e-mail arrives. Reply to it and check that the reply is addressed to the lead.Case B: open HubSpot and check that the contact is there with the lifecycle stage Lead and your demo request in its Message.
Look at the Executions tab in n8n. Every delivery and its data are listed there.
Troubleshooting
Symptom | Cause | Fix |
Nothing arrives in n8n | The Test URL is in Survio, or the workflow isn't published | Copy the Production URL into Survio and click Publish |
Survio won't save the webhook URL from a self-hosted n8n | n8n shows an internal address instead of its public one | Set n8n's |
"Listen for test event" shows nothing although the form was submitted | Survio sends to the Production URL; listening watches the Test URL | Check the Executions tab instead |
Your latest change has no effect | The workflow is published, but the change isn't (the Publish button shows a dot) | Click Publish again |
A column stays empty and a new column appears at the end of the sheet | A field name in Prepare lead doesn't match the column header exactly | Rename the field in Prepare lead to match the header, then delete the extra column |
The same lead appears twice | Operation set to Append Row, or no column to match on | Use Append or Update Row and match on Response ID |
Reply goes to you instead of the lead | Send Replies To isn't set in the Gmail node | Add Send Replies To under Options with the lead's e-mail |
Team size shows as a date | Google Sheets reads 2-10 as a date | In Save lead to sheet, set Cell Format to Let n8n format |
The e-mail address is missing | Read from | Read it from the answer to your e-mail question |
Create or update contact fails | The e-mail is empty or invalid, or the HubSpot connection has expired | Make the e-mail question required, and reconnect HubSpot in the node |
Survio switched the webhook off | The webhook URL failed for 5 days in a row | Fix the cause, then switch the webhook back on in Survio |
Good to know
Survio sends only completed responses, one message per response, within seconds. A form a visitor closes halfway isn't sent.
Nothing is sent retroactively: not responses from before the webhook existed, and not responses from while it was paused.
A failed delivery is retried up to 8 times over roughly 27 hours, and each attempt waits up to 30 seconds for a reply. Matching on Response ID keeps retries from adding duplicate rows.
If deliveries fail for 5 days in a row, Survio switches the webhook off and you need to switch it back on.
Pausing a webhook keeps its slot; deleting it is permanent.
Survio doesn't keep a delivery history in the app. The Executions tab in n8n is your log.
Sending responses to webhooks doesn't use up any extra responses from your plan.
Rather have us set it up? On the Webhooks page in Survio, click Get expert setup, tell us what you'd like to happen, and our team will build it, test it and hand you a working webhook.
