SfSkills Domains Docs GitHub

Home / admin / salesforce-surveys

salesforce-surveys

Use when designing, configuring, distributing, or troubleshooting Salesforce Surveys and Feedback Management. Triggers: 'create a survey', 'NPS score', 'survey invitation', 'survey response report', 'customer feedback form', 'guest user survey access', 'SurveyInvitation', 'SurveySubject', 'SurveySettings', 'sendSurveyInvitation', 'survey not linked to case', 'deploy a survey between orgs'. NOT for choosing between CSAT, NPS, and CES as your CX metric — use architect/customer-effort-scoring. NOT for third-party survey tools like SurveyMonkey or Qualtrics.

Open the skill folder on GitHub


You are a Salesforce Admin expert in Salesforce Surveys and Feedback Management. Your goal is to help practitioners design surveys that capture meaningful feedback, configure distribution channels correctly, and avoid the common permission and licensing pitfalls that silently break external survey collection.


Before Starting

Gather this context before working on anything in this domain:


Questions to Ask Before Configuring

Ask these before opening Survey Builder; the answers decide the design, and an LLM that skips them produces a survey that collects data nobody can act on.

AskWhy it mattersWhat a good answer adds
"Which record must every response be traceable to — Case, Account, Order, or nothing?"Decides whether the design needs SurveySubject rows, which cannot be backfilled onto responses already collectedThe join shape: ParentId = invitation or response, SubjectId = that record
"Do respondents have Salesforce logins, or are they anonymous members of the public?"Guest access, CommunityId, and the Experience Cloud dependency all hang off this one answerThe distribution channel and whether a guest profile is in scope at all
"Does anyone need the responses to be anonymous?"Anonymity is not free — it disables Paused, so anyone who closes the tab starts overAn explicit trade of attributability and resume against candour
"How does the survey branch, and how many decisions live on one page?"Routing is decided per page, and a BASIC-type survey cannot branch at allThe page map, and an early catch if the survey type is wrong
"How many invitations go out in one batch, and from which address?"ConnectApi.Surveys.sendSurveyInvitationEmail caps at 300 recipients per call and requires a from-addressChunking, an org-wide email address, and a Lightning (not Classic) template
"Which org does this survey have to exist in, and who promotes it?"The survey is a Flow, so it inherits the active-flow deployment gate and per-org record IDsA deploy plan, and reports that do not hardcode a SurveyId
"Who owns the response data, and can survey owners edit it?"enableSurveyOwnerCanManageResponse widens who can touch submitted feedbackA deliberate setting rather than an inherited default

What a proper configuration adds over just building a survey: every response arrives joined to the record that caused it, the guest path is proven from an unauthenticated session before customers see it, the anonymity and resume behaviours are chosen rather than discovered, and the whole thing promotes between orgs as a Flow instead of being retyped.


Core Concepts

Survey Data Model

Salesforce Surveys use a specific object hierarchy. The Survey object is the parent container. Each survey has one or more SurveyVersion records representing draft and active versions. When a survey is sent, a SurveyInvitation record is created to track the distribution channel and link. Responses are stored in SurveyResponse (one per respondent session) with individual answers in SurveyQuestionResponse. Aggregates land in SurveyQuestionScore. Understanding this hierarchy is critical for reporting -- you cannot build a useful survey dashboard without joining across these objects.

The split that matters most is which of these you can write:

ObjectCreateable?Supported calls (Object Reference)
Survey, SurveyVersion, SurveyPage, SurveyQuestionNoquery / retrieve / describe / getDeleted / getUpdated (+ search() on Survey, SurveyVersion)
SurveyResponse, SurveyQuestionResponseNoquery / retrieve / describe (+ undelete() on SurveyResponse)
SurveyQuestionScoreNoquery / retrieve / describe / delete / undelete
SurveyInvitation, SurveySubject, SurveyEngagementContext, SurveyEmailBrandingYesfull CRUD + upsert

Authoring happens in Survey Builder; automation happens on the createable half. There is no supported way to insert a survey definition as records.

The Survey Is a Flow

Flow.processType includes Survey — "A flow for Salesforce Surveys. From the UI, this type of flow is created in Survey Builder", API 42.0 and later — and SurveyEnrich for the Survey Data Mapper. The REST translation resources agree: translated survey fields "are stored in Flow fields". Practically this means the survey retrieves and deploys as the Flow metadata type, and every Flow rule applies to it: the production active-flow deployment gate, the managed-package restriction, and the paused-interview rule that blocks deleting a version. SurveyResponse.InterviewId points at the FlowInterview for that response, which is why a paused response is literally a paused flow interview.

Question Types and Branching

SurveyQuestion.QuestionType is a restricted picklist with 19 values: Boolean (v49.0+), CSAT, Currency, Date, DateTime, FreeText, Image, Matrix (v55.0+), MultipleChoice, MultiSelectPicklist, NPS, Number, Picklist, RadioButton, StackRank, Rating, ShortText (v49.0+), Slider, Toggle. The Metadata API's parallel SurveyQuestionType enum spells multiple-choice as MultiChoice and omits RadioButton, so a value copied from one context fails in the other.

Branching in Salesforce Surveys is page-level, not question-level. You route respondents to different pages based on answers on the current page. Plan the page layout accordingly — a question that drives branching must be on its own page or grouped only with questions that share the same routing destination. Whether the survey can branch at all is fixed by Survey.SurveyType: SURVEY has everything, BASIC ships without display logic or page branching, and ASSESSMENT (API 58.0+) targets sales enablement.

Guest User Access for External Surveys

External survey collection is the single most common source of failures. When an unauthenticated person clicks a survey link, they operate under the site's Guest User Profile. That profile must have Read and Create permissions on Survey, SurveyInvitation, SurveyResponse, and SurveyQuestionResponse objects. Without these, the respondent silently fails to submit or sees a generic access error. The guest user also needs field-level security on all fields used in the survey invitation flow. Cross-reference admin/experience-cloud-guest-access for the site-level hardening that surrounds this profile.


Common Patterns

Pattern: Post-Case Survey via Email Invitation

When to use: You want to collect CSAT or NPS feedback after a support case is closed.

How it works:

  1. Create the survey with an NPS or Rating question on page 1 and an optional free-text follow-up on page 2.
  2. Prefer the platform action: Flow's actionType sendSurveyInvitation exists precisely for this — "Sends email survey invitations to leads, contacts, and users in your org based on an action, such as when a customer support case closes" (API 47.0+).
  3. If you need control the action does not give you, build the records by hand: create a SurveyInvitation with SurveyId, ParticipantId, CommunityId and OptionsAllowGuestUserResponse, then a SurveySubject with ParentId = the invitation and SubjectId = the Case.
  4. Send the invitation URL by reading SurveyInvitation.InvitationLink back after insert — it is generated, never supplied.

Why not the alternative: Sending a raw survey link without a SurveyInvitation loses the ability to tie responses back to the originating Case record, making the data useless for reporting.

Pattern: Internal Employee Pulse Survey

When to use: Collecting periodic feedback from authenticated Salesforce users (employees or partners with login access).

How it works:

  1. Create the survey with the desired question types.
  2. Distribute via a direct link or embed the survey in a Lightning page using the Survey component.
  3. Internal users authenticate normally; no guest user configuration is needed.
  4. Responses carry SurveyResponse.SubmitterId, a lookup to Contact, Lead or User.

Pattern: Bulk Send From Apex

When to use: A campaign-scale send to a list of contacts, where a record-triggered Flow has nothing to trigger on.

How it works: Call ConnectApi.Surveys.sendSurveyInvitationEmail(surveyId, input) in chunks of 300. Required input properties are recipients, fromEmailAddress, isPersonalInvitation, allowGuestUserResponse, allowParticipantsAccessTheirResponse and collectAnonymousResponse. Set isPersonalInvitation = true to keep responses attributable. The full shape is in references/metadata-examples.md § 8.


Decision Guidance

SituationRecommended ApproachReason
External customers, no Salesforce loginGuest User Profile + SurveyInvitation with CommunityId and OptionsAllowGuestUserResponseOnly way to capture external responses without requiring authentication
Internal employees with Salesforce accessDirect link or embedded Lightning componentSimpler setup, automatic user association via SubmitterId
Need to tie response to a Case or AccountSurveySubject with ParentId = invitation/response, SubjectId = the recordThe only supported join; a lookup on the Case does not exist
Case-closed trigger, no custom logic neededFlow sendSurveyInvitation actionDocumented platform action; fewer records to hand-manage
More than 300 recipients in one sendChunk ConnectApi.Surveys.sendSurveyInvitationEmailHard per-call cap of 300 participants
Complex conditional logic between questionsPage-level branching, one decision question per page, SurveyType = SURVEYRouting is per page; a BASIC survey has no branching at all
Respondents must be able to resumeKeep OptionsCollectAnonymousResponse and OptionsAllowParticipantAccessTheirResponse falseEither flag set to true removes the Paused status
Survey must exist in several orgsRetrieve and deploy the Flow (processType Survey)It is Flow metadata, not org-only configuration
Embedding the survey on your own websiteIframeWhiteListUrlSettings with <context>Surveys</context>Otherwise the frame is blocked with no visible error

  1. Establish what exists. Query the org before designing: SELECT DeveloperName, SurveyType, ActiveVersionID, IsPartialSaveEnabled FROM Survey and SELECT VersionNumber, SurveyStatus FROM SurveyVersion WHERE SurveyId = '…'. Confirm SurveySettings.enableSurvey is true. Note that the status field is SurveyStatus, not Status — references/gotchas.md Gotcha 4.
  2. Answer the seven questions above, and record the answer to "which record must every response trace to" as the design's first line. It decides whether SurveySubject is in scope.
  3. Draft the survey design as surveys/<Name>.survey.json using templates/salesforce-surveys-template.md: pages, question types from the 19-value picklist, one branching question per page, and the anonymity/resume flags. Run the checker — it lints branch targets, type spellings, and the anonymity-versus-partial-save contradiction.
  4. Write the deployable metadata from references/metadata-examples.md: settings/Survey.settings-meta.xml, the guest Profile object permissions, IframeWhiteListUrlSettings if the survey is embedded off-platform, and the package.xml. Every XML block there is well-formed and grounded in the guide's own samples.
  5. Build the distribution, preferring the sendSurveyInvitation Flow action; fall back to the SurveyInvitation + SurveySubject Apex in § 6 of the metadata examples. Draft any bulk load as surveys/<Name>.invitations.csv so the checker can verify the columns are createable and the expiry is in the future.
  6. Run the checker and fix every ERROR before deploying:
    python3 skills/admin/salesforce-surveys/scripts/check_salesforce_surveys.py \
      --manifest-dir force-app/main/default
  7. Prove the guest path and the join. Open the invitation link in a private window with no Salesforce session and submit. Then run the verification SOQL in references/metadata-examples.md — response rate by survey version, and SurveySubject rows with SubjectEntityType = 'Case'. Zero subjects against non-zero invitations means the association never landed, and it cannot be added afterwards.

Review Checklist

Run through these before marking work in this area complete:


Salesforce-Specific Gotchas

The full set, with What happens / When it occurs / How to avoid and line-level citations, is in references/gotchas.md. The three that break the most deployments:

  1. SurveyVersion.Status does not exist — the field is SurveyStatus, so the guard query everyone writes silently returns nothing.
  2. Only ParticipantId is writable on an invitation — ContactId, LeadId and UserId are derived, and a Flow that sets them fails.
  3. SurveySubject is the only join — and its ParentId is the invitation or the response, never the Case.

Output Artifacts

ArtifactDescription
Survey design documentsurveys/<Name>.survey.json — question types, page layout, branching map, anonymity flags
settings/Survey.settings-meta.xmlThe org-level Surveys switch, deployable
Guest user permission checklistObject and field permissions required on the Guest User Profile
Survey distribution flow or ApexAutomation that creates SurveyInvitation + SurveySubject records and sends links
surveys/<Name>.invitations.csvData Loader payload for a bulk invitation load, createable columns only
Verification SOQLResponse rate by survey version, and the SurveySubject association check

Reference Files

FileRead it when
references/metadata-examples.mdWriting the deployable XML, the invitation CSV, the SurveySubject Apex, package.xml, or the verification SOQL
references/gotchas.mdA survey "works in the builder" and fails in production, or a field/status name does not behave as expected
references/well-architected.mdWeighing native Surveys against third-party tools, or the anonymous-versus-tracked and tier decisions
references/llm-anti-patterns.mdReviewing AI-generated survey guidance before acting on it
templates/salesforce-surveys-template.mdStarting a new survey engagement and capturing the seven questions above

Package files