Send email from Contentsquare when a new survey response needs attention—without exposing an email API key or pretending there is a native Contentsquare app. The reliable architecture is Contentsquare Voice of Customer webhook → your server-side relay → Volanea’s REST email API.
Contentsquare does support outbound webhooks for Voice of Customer Growth customers. The concrete trigger is a new survey response being created: Contentsquare sends an HTTPS POST to the webhook URL configured on a Survey. That makes it a useful foundation for operational emails such as a low-score alert to the CX team, a daily-review queue notification, or an escalation when feedback includes selected terms. (support.contentsquare.com)
There is an important limitation to establish first: Volanea does not have a native Contentsquare marketplace app or plugin. More importantly, Contentsquare’s webhook sends its own event payload to an endpoint you configure; it is not a generic email-composer that can securely store a Volanea key and transform survey answers into a Volanea send request. Use a small middleware endpoint you operate instead.
What this integration does
This integration turns a Contentsquare survey-response event into an email sent by Volanea. It is intentionally designed for internal notification rather than automatically emailing the survey respondent.
That distinction matters. A Contentsquare survey response is feedback data, not automatically a permissioned marketing or support-contact record. The documented response model includes a response ID and answer objects, while an email address should not be assumed to exist in every response. Route the alert to a controlled internal address such as cx-alerts@example.com, then have your team decide whether and how to follow up through the appropriate customer channel. (support.contentsquare.com)
A practical flow looks like this:
- A visitor submits a Contentsquare Voice of Customer survey.
- Contentsquare creates the survey response and posts a JSON webhook event to your relay.
- Your relay validates the event type, extracts the response ID and answer values, and checks whether it processed that response already.
- The relay calls Volanea’s
POST /v1/sendendpoint with an internal recipient, a formatted subject, and an HTML/text summary. - Volanea queues the email through its transactional sending pipeline.
- The relay returns a fast
2xxresponse to Contentsquare.
Contentsquare documents that webhooks are sent as UTF-8 JSON with Content-Type: application/json. The outer envelope includes event, version, and data; the relevant event for this guide is survey_response. Contentsquare says events are normally sent within seconds, but delivery order is not guaranteed, so do not use arrival time as the business timestamp or as an ordering mechanism. (support.contentsquare.com)
The real Contentsquare trigger: a new survey response
The trigger is not a CRM record creation, stage change, or form builder submission. In Contentsquare’s Voice of Customer webhook model, the email workflow begins when a new survey response is created.
For a Survey webhook, Contentsquare sends an event with event: "survey_response". Its webhook documentation also describes replay and test_message event values. A robust receiver must therefore route on the event type and return a successful response for event types it does not use rather than crashing on an unfamiliar event. (support.contentsquare.com)
Why survey-response alerts are the right first use case
A response alert is high-signal when it helps a human act quickly. Good examples include:
- A feedback survey response contains a complaint, bug report, or cancellation reason.
- An NPS-style survey answer falls below the threshold your CX team has set.
- A checkout or signup survey reveals that a visitor could not complete a critical task.
- A product-research response mentions a feature request that needs triage.
- A response includes a free-text answer that a research team wants to review while the associated session context is still fresh.
Avoid an email for every possible answer if your survey volume is large. Sending every neutral response to a shared inbox creates alert fatigue, raises the chance that urgent feedback is missed, and makes it harder to establish a clear service-level expectation. Start with one survey and one meaningful rule, then expand after you know the volume and quality of the alerts.
Plan and product availability
Contentsquare’s webhook article specifically states that this feature applies to customers on the Voice of Customer Growth plan. The ability to see or configure survey webhooks therefore depends on the Voice of Customer product and your plan entitlement, not simply on installing the Contentsquare tracking tag. (support.contentsquare.com)
That is why the first implementation check should be operational rather than technical: confirm that the target Survey has a place to enter a webhook URL. If it does not, do not try to manufacture an outbound integration through browser-side tracking code. Ask your Contentsquare administrator or account team whether Voice of Customer webhooks are enabled for the account.
Why you need a server-side relay
A direct Contentsquare-to-Volanea connection is not the right design. Contentsquare posts its webhook payload to a URL. Volanea expects an authenticated email-send request with an email-specific JSON body. Those are different request contracts.
Your relay is the adapter between them. It receives the Contentsquare event, applies your routing rules, escapes untrusted survey text before putting it into HTML, creates an idempotency key, and makes the authenticated request to Volanea.
The relay solves four separate problems
Payload transformation. Contentsquare sends a survey event envelope; Volanea expects a message payload with fields such as recipient, sender, subject, and body. The relay maps one to the other.
Credential isolation. The Volanea secret key stays in an environment variable or secret manager attached to the relay runtime. It never becomes part of the tracking-tag configuration, browser JavaScript, page source, or survey content.
Deduplication. Contentsquare explicitly says webhook consumers should handle accidental duplicate messages. The relay can store the survey response ID before sending, and it can pass a stable Idempotency-Key to Volanea for safe send retries. (support.contentsquare.com)
Fast acknowledgement. Contentsquare requires the receiving server to respond within 10 seconds and expects a 2xx response. A focused endpoint that validates, records, queues, and responds is much safer than doing slow follow-up work before returning. (support.contentsquare.com)
Where the Volanea API key lives
The Volanea key does not live on the Contentsquare side. On the Contentsquare side, you configure only your relay’s HTTPS webhook URL on the Survey. The secret Volanea key belongs in server-side configuration for the relay, for example:
- a deployment platform’s encrypted environment variable;
- a cloud secret manager injected into the runtime;
- an edge-function secret store; or
- a container-orchestrator secret mounted only for the service account running the relay.
For the code below, the key is read from process.env.VOLANEA_API_KEY. Store the internal alert recipient and verified From address there too, rather than hard-coding production addresses in the repository.
Do not put a secret email API key in client-visible configuration. Contentsquare’s web tracking tag runs on your site, where a browser can inspect JavaScript and network activity. A credential exposed there can be copied and used to send arbitrary mail from your account. Contentsquare’s own API guidance similarly stresses that machine-to-machine credentials must stay secret and must not be embedded in an application or publicly accessible location. (support.contentsquare.com)
Contentsquare payload shape and field mapping
The webhook contract has a stable outer envelope:
event: the event name, includingsurvey_response,replay, ortest_message.version: currently documented as integer1.data: the event-specific object.
For survey responses, use the response fields you actually need. Contentsquare documents an individual survey response with an id and an answers list. Each answer has a question_id, an answer, and an optional comment. Do not depend on undeclared fields just because they appeared in one test payload. (support.contentsquare.com)
The following example maps the documented response ID and answers into an internal alert. It uses a Node.js server handler style that works with Express after JSON parsing. Replace the in-memory processedResponses set with a database table, Redis key, queue, or durable workflow store before production use.
import crypto from "node:crypto";
import express from "express";
const app = express();
app.use(express.json({ limit: "256kb" }));
const processedResponses = new Set<string>(); // Replace with durable storage.
const {
VOLANEA_API_KEY,
VOLANEA_FROM,
CONTENTSQUARE_ALERT_TO,
CONTENTSQUARE_WEBHOOK_TOKEN,
} = process.env;
if (!VOLANEA_API_KEY || !VOLANEA_FROM || !CONTENTSQUARE_ALERT_TO || !CONTENTSQUARE_WEBHOOK_TOKEN) {
throw new Error("Missing required server-side environment variables");
}
type ContentsquareAnswer = {
question_id: string;
answer: string;
comment?: string;
};
type ContentsquareSurveyWebhook = {
event: "survey_response" | "replay" | "test_message" | string;
version: number;
data: {
id?: string;
answers?: ContentsquareAnswer[];
};
};
function escapeHtml(value: string): string {
return value
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
app.post("/webhooks/contentsquare/:token", async (req, res) => {
// Keep the route token server-side. It is not a replacement for durable deduplication.
if (req.params.token !== CONTENTSQUARE_WEBHOOK_TOKEN) {
return res.sendStatus(404);
}
const payload = req.body as ContentsquareSurveyWebhook;
// Contentsquare can send test_message, replay, or future event types.
if (payload.event !== "survey_response") {
return res.status(204).end();
}
const responseId = payload.data?.id;
const answers = Array.isArray(payload.data?.answers) ? payload.data.answers : [];
// Reject malformed survey events without attempting an email send.
if (!responseId) {
return res.status(400).json({ error: "survey response id is required" });
}
// First layer of duplicate protection. Use INSERT ... ON CONFLICT in production.
if (processedResponses.has(responseId)) {
return res.status(204).end();
}
processedResponses.add(responseId);
const answerLines = answers.map(({ question_id, answer, comment }) => {
const commentText = comment ? `\nComment: ${comment}` : "";
return `Question ${question_id}: ${answer || "(no answer)"}${commentText}`;
});
const text = [
"A new Contentsquare survey response was received.",
`Response ID: ${responseId}`,
"",
...answerLines,
].join("\n");
const htmlAnswers = answers.map(({ question_id, answer, comment }) => `
<li>
<strong>Question ${escapeHtml(question_id)}</strong>: ${escapeHtml(answer || "(no answer)")}
${comment ? `<br><em>Comment:</em> ${escapeHtml(comment)}` : ""}
</li>
`).join("");
// The same logical Contentsquare response always receives the same send key.
const idempotencyKey = `contentsquare-survey-response:${responseId}`;
const emailResponse = await fetch("https://api.volanea.com/v1/send", {
method: "POST",
headers: {
"Authorization": `Bearer ${VOLANEA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({
from: VOLANEA_FROM,
to: CONTENTSQUARE_ALERT_TO,
subject: `New Contentsquare survey response: ${responseId}`,
text,
html: `
<h1>New Contentsquare survey response</h1>
<p><strong>Response ID:</strong> ${escapeHtml(responseId)}</p>
<ul>${htmlAnswers || "<li>No answer values were supplied.</li>"}</ul>
`,
}),
});
if (!emailResponse.ok) {
// In production, remove the response ID from an in-progress record only when
// retry policy permits, or use an outbox/queue so a 5xx can be retried safely.
processedResponses.delete(responseId);
const detail = await emailResponse.text();
console.error("Volanea send failed", emailResponse.status, detail);
return res.status(502).json({ error: "email provider rejected the send" });
}
return res.status(202).json({ responseId, status: "email accepted" });
});
app.listen(3000);
Volanea’s single-message endpoint is POST /v1/send on https://api.volanea.com, and it supports the Idempotency-Key header for safe retries. Review the Volanea REST API reference and setup guides when adapting the send payload to stored templates, multiple internal recipients, attachments, scheduling, or event webhooks. (volanea.com)
Set up the Contentsquare webhook endpoint
Before editing the Survey, deploy the relay to a public HTTPS URL. Contentsquare requires HTTPS/TLS and a response within 10 seconds. A local http://localhost endpoint is useful only when tunneled through a secure temporary URL for development; it is not a production endpoint. (support.contentsquare.com)
Recommended configuration sequence
- Create a dedicated server-side endpoint, such as
https://integrations.example.com/webhooks/contentsquare/<random-token>. - Generate a long, random route token and save it as
CONTENTSQUARE_WEBHOOK_TOKENin the relay environment. - Create a Volanea secret key and save it as
VOLANEA_API_KEYin the same server-side secret store. - Set
VOLANEA_FROMto an address on a domain verified in Volanea. - Set
CONTENTSQUARE_ALERT_TOto a monitored internal mailbox or ticket-ingestion address. - In the relevant Contentsquare Survey, enter the relay URL as the webhook URL.
- Use Contentsquare’s webhook test capability if available in your Survey configuration, or submit a clearly marked test response.
- Confirm the relay receives
event: "survey_response", then confirm the Volanea send request succeeds and the internal alert arrives.
The webhook documentation says you can enter the webhook URL on a Survey or replay Segment. For this email-alert use case, configure it on the Survey because the event you want is a new survey response. (support.contentsquare.com)
Keep the acknowledgement path short
Do not call unrelated APIs, generate a PDF, load a customer profile, or wait for a human-review service before responding to Contentsquare. Its receiver deadline is 10 seconds. A better production design is:
- Validate the incoming request and event type.
- Write the event to durable storage with a unique constraint on the response ID.
- Enqueue a job or invoke a reliable worker.
- Return
204or202immediately. - Let the worker call Volanea, retry retryable failures, and record the send outcome.
This pattern reduces webhook timeouts and prevents a temporary Volanea or network issue from making Contentsquare repeatedly deliver the same event while your handler is still doing work.
Build useful routing rules before sending
An alert that repeats all response data is a good test, but not always a good production message. Decide what makes a response actionable.
Low-score escalation
If your survey contains a rating or NPS-style question, compare the answer for its known question_id with your threshold. For example, send an immediate alert only for ratings from 0 through 6, send a digest for 7 and 8, and suppress routine email for 9 and 10.
Do not infer the semantic meaning of a question merely from its answer text. Store the IDs of the questions your automation uses. A score of 5 could mean five stars, five out of ten, a priority level, or a selected option depending on survey design.
Keyword escalation
For free-text feedback, normalize the answer and optional comment to lower case and search for a limited, maintained set of business-relevant terms. Examples might include charged twice, cannot log in, accessibility, or cancel subscription.
Keyword matching should trigger review, not make a final decision about urgency. It can miss spelling variations and context, and it can overmatch harmless statements such as “I did not have a problem logging in.”
Team ownership routing
You can route email based on the survey or question context:
- Checkout-friction surveys go to ecommerce operations.
- Product-feedback surveys go to product research.
- Accessibility feedback goes to the accessibility owner.
- Billing complaints go to support or finance operations.
- Security reports go to a tightly controlled incident mailbox.
Start with explicit configuration instead of hard-coding a growing list of conditions. A small mapping file or database table can associate survey/question IDs with recipients, priority, and template IDs.
Use Volanea templates for a maintainable alert format
Inline html and text are useful while proving the integration. Once the notification layout is stable, a Volanea template is often easier to maintain because the relay sends structured variables instead of a full HTML document on every response.
A template-oriented payload might contain a templateId plus variables such as responseId, answersText, priority, and surveyName. Keep the exact variable names aligned with the template, and test rendering with representative answers that include punctuation, markup-like characters, long comments, and missing optional comments.
Templates also separate content changes from application deployment. Your CX operations team can improve the internal alert copy, add review instructions, or change an escalation banner without requiring a code release—provided your access controls and change process support that workflow.
Use inline HTML when each message is heavily assembled by code or when the alert is still experimental. Use templates when the structure is consistent and you want a clearer boundary between integration logic and email presentation.
Privacy, consent, and data minimization
Survey feedback may contain personal data even when your form does not explicitly ask for it. A respondent can include an order number, phone number, account detail, health information, or other sensitive context in free text.
Contentsquare documents personal-data redaction controls for its web collection, including automatic redaction for common patterns and configuration options for masking. That does not eliminate the need to minimize what your email alert contains. An internal email mailbox may have different retention, forwarding, and access rules than your feedback tooling. (docs.contentsquare.com)
Use these safeguards:
- Send only the response fields the receiving team needs.
- Prefer an internal reference ID and secure review link over copying every answer into email when the feedback is sensitive.
- Escape all answer text before inserting it into HTML.
- Do not place raw survey text in email subject lines, where it can appear in notification previews and logs.
- Limit alert inbox access to people who need it.
- Define retention rules for both webhook logs and email content.
- Document who is allowed to contact a respondent and which consent record governs that follow-up.
For many teams, the best alert email is deliberately brief: response ID, survey name or routing category, priority, and a link or instruction to review the full response in the authorized system.
When this breaks
Every webhook-to-email path has two separate reliability boundaries: Contentsquare delivering the event to your relay, and your relay delivering an email request to Volanea. Treat them separately when debugging.
Contentsquare retries create duplicate send attempts
Contentsquare says webhook consumers should handle accidental duplicates even though it attempts to send each message only once. If your endpoint accepts an event, sends an email, then loses the HTTP response before Contentsquare receives it, Contentsquare may deliver the same response again. (support.contentsquare.com)
Use two layers of protection:
- Persist the Contentsquare response ID with a uniqueness constraint before or alongside processing.
- Send Volanea a stable
Idempotency-Key, such ascontentsquare-survey-response:<response-id>, for the same logical email.
The database constraint protects your own workflow. The Volanea idempotency key protects the outbound send if your worker retries after a network timeout or uncertain provider response. Do not generate a new random idempotency key on every retry; doing so converts a retry into a new send.
Webhook timeouts cause retries or dropped operational visibility
Contentsquare requires a response within 10 seconds. If the relay waits on a slow email call, an overloaded database, or a downstream enrichment request, the webhook can time out. (support.contentsquare.com)
Fix this by acknowledging quickly after durable acceptance. Put the Volanea request on a queue-backed worker if alert delivery does not need to occur inside the webhook request itself. Monitor the time from inbound event receipt to final email acceptance, not only the HTTP latency of the endpoint.
Payload fields are missing or answers are blank
The webhook envelope is consistent, but the event data is event-specific. In a survey response, an optional comment may be absent, a visitor may skip non-required questions, and a partially completed survey can show blank answers. Contentsquare notes that survey results can include blank responses when a user skips a non-required question or abandons a popover/full-screen survey after answering only some questions. (support.contentsquare.com)
Design for missing values:
- Treat
commentas optional. - Default blank
answervalues to a visible marker such as(no answer). - Do not index
answers[0]and assume it is the score question. - Match answers by
question_id. - Validate the response ID before using it as an idempotency key.
- Gracefully acknowledge unknown event types such as
test_messagerather than treating them as malformed survey responses.
There is also a plan-level issue: Contentsquare’s webhook feature applies to Voice of Customer Growth customers. If a webhook setting or expected feature is unavailable in a different plan or account configuration, do not compensate with client-side secrets or browser-to-email API calls. Confirm the entitlement and use a supported server-side integration path. (support.contentsquare.com)
Volanea accepts the request but the team does not see an email
A successful API response means the provider accepted the send request; it is not the same as proof that every recipient saw the message. Check the Volanea send record and delivery events, verify the From domain, inspect suppression or unsubscribe handling where relevant, and confirm that the internal recipient mailbox did not quarantine the message.
For internal operational alerts, use a verified domain and an address your mail administrators recognize. If alerts go to a shared mailbox, verify mailbox rules, ticketing ingestion filters, and spam/quarantine policies before assuming the problem is in Contentsquare.
The relay returns an error after creating a durable record
This is a common edge case. Suppose the relay stores the response ID, enqueues work, but then returns a 500 because of a logging failure. Contentsquare may retry. On the retry, your uniqueness check sees that the job already exists and should return a success response, not another error.
Model your database status explicitly: received, queued, sending, sent, and failed. This makes it possible to distinguish a genuine duplicate from a previous attempt that needs recovery.
Test the integration safely
Use a dedicated test Survey and a non-production internal mailbox first. Mark the survey questions and the email subject clearly as test content so a real support queue does not mistake it for a customer escalation.
A disciplined test plan includes:
- Submit a normal response with every question answered.
- Submit a response with optional questions left blank.
- Submit a response containing
<script>, quotation marks, ampersands, and long free text to verify HTML escaping. - Replay the same webhook payload twice and confirm one logical email is sent.
- Simulate a Volanea timeout and verify the same idempotency key is reused for the retry.
- Send
test_messageandreplayevent shapes to confirm the endpoint safely acknowledges unsupported types. - Temporarily slow the worker, not the HTTP acknowledgement path, to confirm the endpoint stays inside Contentsquare’s 10-second requirement.
Keep sanitized copies of representative payloads in automated tests. This protects the integration when someone changes a Survey question, removes a question, changes its optionality, or routes a different Survey to the same webhook endpoint.
Conclusion
The dependable way to send email from Contentsquare with Volanea is a server-side webhook relay. The actual Contentsquare trigger is a new survey response created event from Voice of Customer. Contentsquare posts the JSON event to your HTTPS endpoint; your endpoint maps documented response fields into a Volanea POST /v1/send request; Volanea sends the internal transactional alert.
Do not expose a Volanea secret in client-visible configuration, and do not treat a webhook as exactly-once delivery. Store response IDs durably, acknowledge Contentsquare quickly, use a stable Volanea idempotency key, and code defensively for blank or missing answer fields. That yields an integration that remains useful when response volume grows and resilient when a network hop fails.
FAQ
Does Contentsquare have a native Volanea integration?
No. This setup does not use a Contentsquare marketplace app or native Volanea plugin. It uses Contentsquare’s Voice of Customer webhook capability and a server-side relay that calls Volanea’s REST API.
What starts the email send in Contentsquare?
A new survey response is created. Contentsquare posts a survey_response webhook event to the webhook URL configured on the Survey. (support.contentsquare.com)
Can I send an email directly to the survey respondent?
Only if you have a valid, permissioned email address through an approved data source and a clear transactional or consent basis for the message. Do not assume every Contentsquare survey-response payload contains an email address. This guide intentionally sends alerts to an internal team mailbox.
How do I stop duplicate emails?
Use the Contentsquare survey response ID as your durable deduplication key and as the basis for Volanea’s Idempotency-Key, for example contentsquare-survey-response:<response-id>. Reuse that key only for retries of the same logical email.
What if I cannot configure a webhook on my Survey?
First confirm that your account has Contentsquare Voice of Customer Growth webhook access. If the capability is not enabled for the account, use a supported export or API workflow through a server-side scheduler or middleware rather than exposing email credentials in browser code. (support.contentsquare.com)