Integrate Qualtrics with a Lovable app by creating Supabase Edge Functions that proxy Qualtrics API calls using an API token stored in Cloud → Secrets. Qualtrics uses datacenter-specific API URLs (your-datacenter-id.qualtrics.com) — configure the correct datacenter URL for your account before making API calls. Embed surveys via iframe and process response events via Qualtrics webhooks.
Integrating Qualtrics Experience Management with Your Lovable App
Qualtrics is the enterprise standard for experience management — the platform deployed by Fortune 500 companies, universities, and government agencies for measuring customer satisfaction, employee engagement, and brand perception. Unlike consumer survey tools, Qualtrics offers advanced survey logic, panel management, conjoint analysis, and a comprehensive reporting engine designed for research-grade data collection. For Lovable app builders working in enterprise contexts, integrating Qualtrics means connecting with existing XM programs that organizations have spent years building.
The critical technical detail that differentiates Qualtrics from other SaaS APIs is the datacenter-specific URL. Qualtrics does not have a single global API endpoint — every organization uses a URL based on their assigned datacenter, formatted as https://[datacenter-id].qualtrics.com/API/v3. Your datacenter ID is visible in your account settings under Qualtrics IDs and is typically a string like 'ca1', 'fra1', 'sjc1', or 'iad1' based on geographic region and data residency. All API calls that miss this detail will silently fail or receive authentication errors. This is the most common integration mistake, and it must be configured correctly in your Cloud → Secrets before any other API work.
Qualtrics API authentication uses a static API token generated in Account Settings → Qualtrics IDs → API. This token has full access to all surveys, responses, and directories in the account — it is a high-privilege credential that must be treated with maximum secrecy. Lovable's security infrastructure blocks approximately 1,200 hardcoded API keys daily and the platform holds SOC 2 Type II and ISO 27001:2022 certifications. The Qualtrics API token must live in Cloud → Secrets and must only be accessed via Deno.env.get() in Edge Functions — never in frontend React code.
Integration method
Qualtrics integrates with Lovable through Supabase Edge Functions that proxy all Qualtrics API calls using an API token stored in Cloud → Secrets. The critical configuration detail is the datacenter-specific API URL — every Qualtrics organization uses a subdomain like yourcompanyid.qualtrics.com, and all API requests must go to your specific datacenter URL. Edge Functions handle survey listing, response export, and embedded survey display while a webhook receiver Edge Function captures real-time response events.
Prerequisites
- A Lovable account with an existing project that has Supabase configured
- A Qualtrics account with API access — requires XM Platform license, not available on free trial accounts
- Your Qualtrics datacenter ID found in Account Settings → Account section → Qualtrics IDs (looks like 'ca1', 'fra1', 'sjc1', etc.)
- A Qualtrics API token from Account Settings → Account section → Qualtrics IDs → API → Generate Token
- At least one published Qualtrics survey with its Survey ID (starts with 'SV_') copied from the survey settings
Step-by-step guide
Find your Qualtrics datacenter ID and generate your API token
Find your Qualtrics datacenter ID and generate your API token
Qualtrics requires a datacenter-specific API URL for every request — this is the single most important configuration step and the most common source of integration failures. Log in to your Qualtrics account at yourdomain.qualtrics.com. Click your user icon in the top-right corner and select Account Settings. In the Account Settings page, click on the 'Account section' header to expand the account information, then find 'Qualtrics IDs' in the left sidebar and click it. On the Qualtrics IDs page, you will see several important identifiers. The Datacenter ID is labeled clearly — it is a short string like 'ca1' (Canada), 'fra1' (Frankfurt), 'iad1' (US East), 'sjc1' (US West), or 'syd1' (Sydney). This determines the base URL for all API calls: https://[datacenter-id].qualtrics.com/API/v3. Copy this datacenter ID carefully — a typo here means all API calls will fail with authentication errors. On the same page, find the API section and click 'Generate Token' to create your API token. If you already have a token, it will be shown here (partially obscured for security). Copy the full token value. Note that Qualtrics API tokens have full access to all resources in your organization's Qualtrics account — they are not scoped to specific surveys. Treat this token with the same security as a database root password. Also copy your Organization ID from this page — formatted as a string like 'yourcompany' — and the Survey IDs for the surveys you want to integrate (each Survey ID starts with 'SV_'). Now go to your Lovable project, open the Cloud tab, and add these secrets: QUALTRICS_API_TOKEN (your token), QUALTRICS_BASE_URL (formatted as https://[datacenter-id].qualtrics.com/API/v3), and QUALTRICS_ORG_ID (your organization ID). Add VITE_QUALTRICS_SURVEY_URL as the public survey URL for iframe embedding.
Pro tip: The Qualtrics API base URL format is https://[datacenter-id].qualtrics.com/API/v3 — note the '/API/v3' suffix is required for all v3 endpoints. Do not use the base domain without this path. Store the complete base URL including the path prefix in QUALTRICS_BASE_URL for easy use in Edge Functions.
Expected result: QUALTRICS_API_TOKEN, QUALTRICS_BASE_URL, and QUALTRICS_ORG_ID are stored in Lovable Cloud Secrets. The QUALTRICS_BASE_URL contains the full URL including your datacenter ID and the /API/v3 suffix. Testing the API token in a tool like curl returns survey data rather than an authentication error.
Create the Qualtrics API proxy Edge Function
Create the Qualtrics API proxy Edge Function
Create a Supabase Edge Function that proxies requests from your Lovable frontend to the Qualtrics API, handling authentication and the datacenter-specific URL abstraction. The function reads QUALTRICS_API_TOKEN and QUALTRICS_BASE_URL from Deno.env.get() to construct authenticated requests. Qualtrics API v3 uses the X-API-TOKEN header for authentication — unlike Bearer token approaches used by many other APIs, Qualtrics requires this specific header name. Every request must include 'X-API-TOKEN: [your-token]' in the headers. Forgetting this header or using 'Authorization: Bearer' instead results in a 401 response. The most useful Qualtrics API endpoints for a Lovable integration are: GET /surveys (list all surveys in the organization), GET /surveys/{surveyId} (get survey metadata including questions and structure), POST /surveys/{surveyId}/export-responses (initiate a response export), GET /surveys/{surveyId}/export-responses/{exportProgressId} (check export progress), and GET /surveys/{surveyId}/export-responses/{exportProgressId}/file (download the exported response file as a ZIP containing JSON or CSV). Qualtrics uses a multi-step export process for responses (not a single GET call). First, POST to initiate the export and receive a progress ID. Then poll the progress endpoint until the export status is 'complete'. Finally, download the ZIP file from the file endpoint. This asynchronous pattern is necessary for large response datasets but adds complexity for real-time dashboard use — for dashboards, use the webhook approach to store responses incrementally rather than bulk exporting on every page load. For the proxy function, support two modes: a 'surveys' mode that lists surveys (fast, single API call) and a 'responses' mode that uses the async export pattern for full response data (slower, multi-step). Cache exported responses in Supabase to avoid repeated exports.
Create a Supabase Edge Function called 'qualtrics-proxy' that handles GET requests. Accept a 'resource' query parameter ('surveys' or 'survey-detail') and an optional 'survey_id' parameter. Use X-API-TOKEN header authentication with QUALTRICS_API_TOKEN from Deno secrets. For 'surveys', fetch from QUALTRICS_BASE_URL + '/surveys'. For 'survey-detail', fetch survey metadata including questions. Return the Qualtrics API response as JSON. Handle 403 errors by returning a clear message about plan limitations.
Paste this in Lovable chat
1// supabase/functions/qualtrics-proxy/index.ts2import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';34const corsHeaders = {5 'Access-Control-Allow-Origin': '*',6 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',7};89serve(async (req) => {10 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });1112 try {13 const apiToken = Deno.env.get('QUALTRICS_API_TOKEN');14 const baseUrl = Deno.env.get('QUALTRICS_BASE_URL');1516 if (!apiToken || !baseUrl) {17 return new Response(18 JSON.stringify({ error: 'QUALTRICS_API_TOKEN or QUALTRICS_BASE_URL not configured' }),19 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }20 );21 }2223 const url = new URL(req.url);24 const resource = url.searchParams.get('resource') ?? 'surveys';25 const surveyId = url.searchParams.get('survey_id');2627 const qualtricsHeaders = {28 'X-API-TOKEN': apiToken,29 'Content-Type': 'application/json',30 };3132 let apiUrl = '';33 if (resource === 'surveys') {34 apiUrl = `${baseUrl}/surveys`;35 } else if (resource === 'survey-detail' && surveyId) {36 apiUrl = `${baseUrl}/surveys/${surveyId}`;37 } else {38 return new Response(JSON.stringify({ error: 'Invalid resource or missing survey_id' }), {39 status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },40 });41 }4243 const qResponse = await fetch(apiUrl, { headers: qualtricsHeaders });4445 if (qResponse.status === 401) {46 return new Response(JSON.stringify({ error: 'Invalid Qualtrics API token' }), {47 status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' },48 });49 }50 if (qResponse.status === 403) {51 return new Response(JSON.stringify({ error: 'Qualtrics plan does not support this API endpoint' }), {52 status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' },53 });54 }5556 const data = await qResponse.json();57 return new Response(JSON.stringify(data), {58 headers: { ...corsHeaders, 'Content-Type': 'application/json' },59 });60 } catch (error) {61 return new Response(JSON.stringify({ error: String(error) }), {62 status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },63 });64 }65});Pro tip: Qualtrics API responses are wrapped in a 'result' key — the actual data is at response.result, not at the top level of the response JSON. Always access response.result.elements for list endpoints and response.result for detail endpoints when parsing Qualtrics API responses.
Expected result: The qualtrics-proxy Edge Function is deployed. Calling it with ?resource=surveys returns a list of surveys from the Qualtrics organization. Calling it with ?resource=survey-detail&survey_id=SV_xxx returns the survey structure including all question details.
Embed a Qualtrics survey in your Lovable app
Embed a Qualtrics survey in your Lovable app
Qualtrics surveys can be embedded in web applications using two methods: iframe embedding with the survey's published URL, and the Qualtrics Web SDK for more integrated embedding with custom styling and event handling. For most Lovable app integrations, iframe embedding is simpler and more reliable. To get the survey's iframe URL, log in to Qualtrics, open your survey, click 'Distributions', then 'Anonymous Link'. The Anonymous Link URL is the public survey URL suitable for iframe embedding — it looks like https://[org].qualtrics.com/jfe/form/SV_xxxxxxxxx. Store this URL as VITE_QUALTRICS_SURVEY_URL in Lovable's environment configuration. For personalized data capture, pass user context through embedded data URL parameters. Append query parameters to the survey URL to pre-populate embedded data fields in Qualtrics: ?Q_EmbeddedData=userId~[user_id]|userPlan~[plan]. The respondent will not see these values, but they are stored with each response, enabling you to match survey responses back to Supabase user records. Qualtrics surveys fire a window.postMessage event when the survey is completed — the message data includes a 'QualtricsEmbeddedFeedback' type with the survey ID. Listen for this event in your Lovable React component to detect completion and close the modal or trigger post-survey actions. Note that the exact postMessage format varies slightly between Qualtrics versions — test with your specific survey to confirm the message format. For a better embedded experience, append &Q_SkinType=button to the survey URL on some Qualtrics configurations to hide the Qualtrics branding. Your Qualtrics license terms govern whether removing the branding is permitted.
Create a QualtricsModal React component that embeds a Qualtrics survey in a shadcn Dialog. The iframe src builds from VITE_QUALTRICS_SURVEY_URL with the user's ID appended as an embedded data parameter (?Q_EmbeddedData=userId~[userId]). Listen for window postMessage events from Qualtrics to detect survey completion and close the modal. After closing, update the user's Supabase profile to set qualtrics_survey_completed: true so the survey is not shown again.
Paste this in Lovable chat
1// src/components/QualtricsModal.tsx2import { useEffect, useCallback } from 'react';3import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';4import { supabase } from '@/integrations/supabase/client';56interface QualtricsModalProps {7 open: boolean;8 onClose: () => void;9 userId: string;10 userPlan?: string;11}1213const SURVEY_URL = import.meta.env.VITE_QUALTRICS_SURVEY_URL;1415export function QualtricsModal({ open, onClose, userId, userPlan = 'free' }: QualtricsModalProps) {16 const handleClose = useCallback(async () => {17 await supabase18 .from('profiles')19 .update({ qualtrics_survey_completed: true })20 .eq('id', userId);21 onClose();22 }, [userId, onClose]);2324 useEffect(() => {25 function handleMessage(event: MessageEvent) {26 // Handle Qualtrics completion postMessage27 if (28 event.data === 'QSIFinished' ||29 (typeof event.data === 'object' && event.data?.type === 'QualtricsEmbeddedFeedback')30 ) {31 handleClose();32 }33 }34 if (open) window.addEventListener('message', handleMessage);35 return () => window.removeEventListener('message', handleMessage);36 }, [open, handleClose]);3738 if (!SURVEY_URL) return null;3940 const embeddedParams = `userId~${encodeURIComponent(userId)}|userPlan~${encodeURIComponent(userPlan)}`;41 const iframeUrl = `${SURVEY_URL}?Q_EmbeddedData=${embeddedParams}`;4243 return (44 <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>45 <DialogContent className="max-w-3xl h-[85vh] p-0 overflow-hidden">46 <DialogHeader className="px-6 pt-4 pb-2">47 <DialogTitle>Share Your Feedback</DialogTitle>48 </DialogHeader>49 <iframe50 src={iframeUrl}51 className="w-full flex-1 border-none"52 style={{ height: 'calc(100% - 60px)' }}53 title="Qualtrics Survey"54 allow="camera; microphone"55 />56 </DialogContent>57 </Dialog>58 );59}Pro tip: Qualtrics embedded data field names are case-sensitive and must match exactly the field names defined in your survey's Survey Flow → Embedded Data element. If responses show blank embedded data values, check that the field names in the URL parameter match the field names in the Survey Flow configuration.
Expected result: The QualtricsModal component renders the Qualtrics survey in a responsive dialog. The survey loads and navigates through questions. Embedded data parameters (userId, userPlan) are passed to the survey. On completion, the modal closes and the user profile is updated.
Create a webhook receiver for real-time response processing
Create a webhook receiver for real-time response processing
Qualtrics's workflow triggers (formerly called event subscriptions) deliver response data to an external URL when survey responses are submitted. This real-time delivery is far more efficient than polling the API and enables immediate follow-up actions. Setting up webhook delivery requires configuring a workflow trigger in your Qualtrics survey. In your Qualtrics account, open the survey, click 'Workflows' in the top navigation. Click 'Create a workflow' and select 'Survey response' as the event trigger — this fires for every completed response. In the workflow's action step, select 'Web Service' as the action type. Set the method to POST and enter your Edge Function URL (https://[project-ref].supabase.co/functions/v1/qualtrics-webhook). In the request body, set the format to JSON and include the following fields mapped from Qualtrics embedded data and response values: ResponseId (from Response), status (from Response), values (from Response - Full Response), and any specific question values you need. The webhook payload structure in Qualtrics is customizable — you define exactly what fields are included in the JSON body through the workflow's 'Add field' interface. This is more flexible than SurveyMonkey but requires more configuration. At minimum, include the ResponseId so your Edge Function can fetch the full response via the API, or include all the relevant question values directly in the webhook body to avoid the additional API call. In the Edge Function, parse the incoming JSON body, extract the response data, and store it in your Supabase database. For NPS programs, also trigger the appropriate follow-up logic: create a support ticket for detractors, add promoters to a referral campaign audience, or send a summary email to the customer success team. For complex XM workflows or implementing Qualtrics's advanced features like panels or directory management, RapidDev's team can help design the integration architecture.
Create a Supabase Edge Function called 'qualtrics-webhook' that accepts POST requests from Qualtrics workflow triggers. Extract ResponseId, SurveyID, nps_score (from Q1), respondent_email (from embedded data), and verbatim_feedback (from Q2) from the request body. Store in a Supabase 'xm_responses' table with columns: response_id, survey_id, nps_score, respondent_email, verbatim_feedback, created_at. For nps_score < 7, also insert a row into 'follow_up_tasks' table with type 'detractor_followup'.
Paste this in Lovable chat
1// supabase/functions/qualtrics-webhook/index.ts2import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';3import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';45const corsHeaders = {6 'Access-Control-Allow-Origin': '*',7 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',8};910serve(async (req) => {11 if (req.method === 'OPTIONS') return new Response('ok', { headers: corsHeaders });12 if (req.method !== 'POST') return new Response('Method not allowed', { status: 405 });1314 try {15 const supabase = createClient(16 Deno.env.get('SUPABASE_URL') ?? '',17 Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''18 );1920 const body = await req.json();21 const responseId = body.ResponseId ?? body.response_id;22 const surveyId = body.SurveyID ?? body.survey_id;23 const npsScore = body.nps_score !== undefined ? Number(body.nps_score) : null;24 const respondentEmail = body.respondent_email ?? null;25 const verbatimFeedback = body.verbatim_feedback ?? null;2627 if (!responseId) {28 return new Response(JSON.stringify({ error: 'ResponseId missing from payload' }), {29 status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' },30 });31 }3233 // Store response34 const { error: insertError } = await supabase.from('xm_responses').upsert({35 response_id: responseId,36 survey_id: surveyId,37 nps_score: npsScore,38 respondent_email: respondentEmail,39 verbatim_feedback: verbatimFeedback,40 raw_payload: body,41 }, { onConflict: 'response_id' });4243 if (insertError) console.error('DB insert error:', insertError);4445 // Queue detractor follow-up46 if (npsScore !== null && npsScore < 7) {47 await supabase.from('follow_up_tasks').insert({48 type: 'detractor_followup',49 response_id: responseId,50 respondent_email: respondentEmail,51 nps_score: npsScore,52 status: 'pending',53 });54 }5556 return new Response(JSON.stringify({ success: true }), {57 headers: { ...corsHeaders, 'Content-Type': 'application/json' },58 });59 } catch (error) {60 console.error('Qualtrics webhook error:', error);61 return new Response(JSON.stringify({ error: String(error) }), {62 status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' },63 });64 }65});Pro tip: Qualtrics workflow triggers can also send a test request directly from the workflow editor — click 'Test' after configuring the web service action to send a sample payload to your Edge Function URL. Use this to verify your Edge Function processes the payload correctly before collecting real responses.
Expected result: The qualtrics-webhook Edge Function is deployed. The Qualtrics workflow trigger is configured to POST to the Edge Function URL. Submitting a test survey response creates a new row in the xm_responses table. Detractor responses (NPS below 7) also create rows in the follow_up_tasks table.
Common use cases
Display NPS trend data in an in-app customer success dashboard
Pull aggregated NPS response data from Qualtrics into your Lovable app's admin panel, showing score trends over time, promoter/detractor ratios, and verbatim response highlights. A Supabase Edge Function uses the Qualtrics response export API to fetch and cache response data in Supabase, enabling fast dashboard queries without hitting Qualtrics API rate limits on every page load.
Create an NPS Dashboard page that fetches Qualtrics survey responses from a Supabase Edge Function called 'qualtrics-proxy'. Display: current NPS score (calculated from the last 90 days of responses), trend chart showing monthly NPS over the past year, breakdown of promoters/passives/detractors as percentages, and a table of the 10 most recent verbatim comments. Use the survey ID from VITE_QUALTRICS_NPS_SURVEY_ID.
Copy this prompt to try it in Lovable
Embed a Qualtrics survey at the right moment in the user journey
Trigger a Qualtrics survey modal after a user completes a key action — finishing onboarding, completing a transaction, or reaching 30 days of usage. The Qualtrics survey embeds via iframe using a SecureClient URL that passes the user's ID and context data. After survey completion, a webhook stores the response in Supabase and marks the user as surveyed to prevent duplicate solicitations.
Create a QualtricsModal component that shows a Qualtrics survey in a Dialog after the user completes their first project. Build the embed URL from VITE_QUALTRICS_SURVEY_URL with the user's ID passed as an embedded data parameter. Close the modal on survey completion by listening for the postMessage event from the Qualtrics survey iframe. Update the user's Supabase profile to set nps_survey_sent: true after the modal is shown.
Copy this prompt to try it in Lovable
Process Qualtrics response webhooks for automated follow-up
Set up a Qualtrics workflow trigger that sends a POST event to your Edge Function when each survey response is submitted. The webhook Edge Function extracts the respondent's email, NPS score, and verbatim feedback, stores the structured data in Supabase, and triggers appropriate follow-up actions — creating a support ticket for detractors, sending a thank-you email to promoters, or flagging responses with specific keywords for manual review.
Create a Supabase Edge Function called 'qualtrics-webhook' that receives POST requests from Qualtrics workflow triggers. Parse the ResponseId from the body, fetch the full response from the Qualtrics API using QUALTRICS_API_TOKEN and QUALTRICS_BASE_URL. Extract the NPS score from QID1, the email from embedded data, and the verbatim comment from QID2. Store in Supabase 'xm_responses' table. For NPS scores below 7, create a row in 'follow_up_queue' with status 'pending'.
Copy this prompt to try it in Lovable
Troubleshooting
All Qualtrics API calls return '401 Unauthorized' or 'AUTH_ERROR'
Cause: The most common cause is using the wrong datacenter ID in the API URL. If the QUALTRICS_BASE_URL points to a different datacenter than your account resides in, authentication fails even with a valid API token. The second common cause is an expired or invalid API token.
Solution: Verify the datacenter ID by logging into Qualtrics, going to Account Settings → Qualtrics IDs, and comparing the Datacenter ID shown there against what is in QUALTRICS_BASE_URL. The URL must be exactly https://[datacenter-id].qualtrics.com/API/v3 — including the /API/v3 suffix and without a trailing slash. If the datacenter ID matches, regenerate the API token in Account Settings and update Cloud → Secrets.
Qualtrics survey iframe shows 'Survey is currently unavailable' or a blank white page
Cause: The survey is set to 'Inactive' in Qualtrics, the survey's collector (Anonymous Link) has been closed, or the survey URL is using the preview URL format instead of the live distribution URL.
Solution: In Qualtrics, open the survey and click 'Publish' if the survey is not published. Go to Distributions → Anonymous Link and verify the link status is 'Active'. The survey URL for embedding must come from Distributions → Anonymous Link, not from the survey preview URL (which contains /preview/ in the path and only shows to authorized Qualtrics users).
Qualtrics workflow trigger test succeeds but real responses do not trigger the webhook
Cause: The workflow trigger condition may be set to 'Partially recorded' instead of 'Completed', or the workflow is inactive. The Edge Function URL may also need to be accessible from Qualtrics's IP ranges.
Solution: Open the workflow in Qualtrics and verify: the trigger event is set to 'Survey response recorded', the completion filter is set to 'Completed responses only', and the workflow status toggle is set to 'Active'. Check Cloud Logs in your Lovable project to see if any requests are arriving at the Edge Function — if no requests appear, the issue is in Qualtrics's workflow configuration. Supabase Edge Functions are publicly accessible from any IP, so IP allowlisting is not needed.
Response export via the API takes too long and the Edge Function times out
Cause: Qualtrics response exports use an asynchronous multi-step process that can take 30-120 seconds for large surveys. A single Edge Function invocation cannot poll for completion without hitting the Edge Function timeout.
Solution: Split the export process into two separate Edge Function calls. The first call initiates the export and returns the export progress ID. Store the progress ID in your Supabase database. A second call (triggered manually or via a scheduled function) polls the progress endpoint and downloads the ZIP when ready. Alternatively, use the webhook approach for incremental response collection instead of batch exports.
Best practices
- Always store the complete QUALTRICS_BASE_URL including datacenter ID and /API/v3 path as a single secret — this makes the correct URL self-documenting and prevents datacenter mismatches that cause cryptic authentication errors.
- Use the X-API-TOKEN header for all Qualtrics API requests — not Authorization Bearer, not Basic auth. Qualtrics v3 API specifically requires this header name and format.
- Pass the Supabase user ID as a Qualtrics embedded data parameter when embedding surveys, using the Q_EmbeddedData URL parameter format — this enables matching survey responses back to your user records for personalized follow-up.
- Cache Qualtrics survey response data in your Supabase database and implement a scheduled refresh rather than calling the Qualtrics API on every dashboard page load — response exports are slow and rate-limited.
- Store raw webhook payloads as JSONB in your Supabase table alongside extracted structured fields — Qualtrics response data structure varies by survey, and raw payloads preserve all data for future extraction.
- Configure separate Qualtrics workflows for different response segments (detractors, promoters, passives) rather than doing the segmentation in the Edge Function — Qualtrics's conditional workflow logic is more reliable than attempting to parse complex survey logic in code.
- Generate a new API token with a descriptive name ('Lovable Integration - Created 2026-03-30') and document when it was created — Qualtrics tokens do not expire but can be administratively revoked, and knowing which token to regenerate saves troubleshooting time.
Alternatives
Choose SurveyMonkey when you need a simpler, less expensive survey solution with good analytics for standard business use cases — Qualtrics is better for enterprise XM programs with advanced logic, panel management, and research-grade data requirements.
Choose Typeform when you want a conversational, modern survey UI with high completion rates for product feedback — Qualtrics is better for formal research programs and enterprise IT environments where Qualtrics is an approved vendor.
Choose Amplitude for behavioral product analytics tracking what users do automatically — Qualtrics is best for capturing explicit user feedback and opinions through structured survey instruments.
Frequently asked questions
Does Qualtrics require a paid license for API access?
Yes. Qualtrics API access requires an XM Platform license — free trial accounts do not include API access. The level of API access (survey responses, webhooks, directory management) depends on your specific license tier. Contact your Qualtrics account representative to verify which API capabilities are included in your organization's license before building the integration.
What is the Qualtrics datacenter ID and why does it matter?
Qualtrics operates multiple data centers globally to comply with data residency requirements. Your organization's data lives in one specific datacenter, and all API requests must go to that datacenter's URL. Using the wrong datacenter URL — even with a valid API token — results in authentication failures. Your datacenter ID is visible in Account Settings → Qualtrics IDs and is a short string like 'ca1', 'fra1', or 'iad1' based on geographic region.
How do I pass user data to a Qualtrics survey without showing it to the respondent?
Use Qualtrics's embedded data feature. In your survey's Survey Flow, add an Embedded Data element and define field names (like userId, userPlan). Then append these values to the survey URL using the Q_EmbeddedData parameter format when embedding the iframe. The values are stored with each response invisibly — respondents do not see them, but they appear in response data exports and webhook payloads.
Can I show Qualtrics survey results inside my Lovable app without accessing the Qualtrics dashboard?
Yes. Use the Qualtrics response export API via an Edge Function to fetch and cache response data in your Supabase database. Query the cached data to calculate NPS scores, response rates, and verbatim feedback summaries. Display these metrics in React components using charts from libraries like Recharts or shadcn/ui's chart components. This approach also reduces dependency on Qualtrics's API availability for dashboard rendering.
How does Qualtrics compare to SurveyMonkey for a Lovable app integration?
Both require similar Edge Function patterns for API proxying and webhook processing. Qualtrics is more complex due to the datacenter-specific URL requirement and the multi-step response export process. SurveyMonkey has a simpler API with direct response access. Choose Qualtrics when your organization already uses it for XM programs and you need to integrate with existing surveys and workflows. Choose SurveyMonkey for greenfield survey integrations where you control the platform choice.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation