BETA
Skip to content

AI features

Krafter Surveys ships four AI-powered surfaces, each backed by the platform's LLM engine. Use them for the parts where humans don't add value — drafting questions, reviewing for clarity, picking the next adaptive question, summarising results.

FeatureUsed bySurface
Generate questionsYou — when authoring a surveyPOST /surveys/:id/generate
Review questionsYou — before launchingPOST /surveys/:id/review
Adaptive conversationRespondents — mode: "ai" surveysPOST /surveys/:slug/next
SummariesYou — after collecting responsesPOST /surveys/:id/summary, GET /summary

All four require the platform's LLM engine to be configured. If it isn't, the endpoints return 503 Service Unavailable. Transient upstream model failures return 502 Bad Gateway — retry with the same arguments.


Manual mode vs AI mode

Every survey is either manual or ai. The choice affects how respondents experience the survey:

manualai
Who picks the next question?You — by question position and branching rulesThe AI engine, per respondent, based on prior answers
Are branching rules respected?YesNo — the conductor ignores them
Are questions rendered to the respondent?Yes — in position orderNo — the AI generates each question on the fly
What's saved?answers keyed by question_idai_conversation array of {role, question, answer} turns + ai_cost_cents
Where does the next question come from?The survey's question listPOST /surveys/:slug/next

You can switch a survey between modes via PATCH /surveys/:id. Switching from manual to ai does not delete your authored questions — they remain on the survey and can be inspected via GET /surveys/:id, but the conductor won't use them.


Generating draft questions

Use POST /surveys/:id/generate to draft a question list for a goal. The endpoint returns candidate questions — it does not save them. Review the output, then create each question via POST /surveys/:id/questions.

bash
curl -X POST https://app.krafter.dev/api/v1/surveys/SURVEY_ID/generate \
  -H "Authorization: Bearer kr_live_abc123def456" \
  -H "Content-Type: application/json" \
  -d '{
    "goal": "Understand why new signups churn before week 2",
    "context": {
      "audience": "self-serve SaaS users",
      "tone": "casual",
      "language": "en",
      "max_questions": 6
    }
  }'

context fields

FieldDescription
topicSurvey topic (e.g. "onboarding", "pricing")
audienceWho the respondents are
tone"formal", "casual", etc.
languageLanguage code ("en", "es", "de", ...)
max_questionsSoft cap on the returned list length

All fields are optional. The engine uses sensible defaults from the survey's name and ai_config if you omit them.

The returned shape matches what POST /surveys/:id/questions accepts. Loop through the array, add a position, and persist:

bash
position=1
for question in "${questions[@]}"; do
  curl -X POST .../surveys/$SURVEY_ID/questions \
    -d "$(jq -n --argjson q "$question" --arg p "$position" '$q + {position: ($p|tonumber)}')"
  ((position++))
done

Reviewing existing questions

Once you've authored questions (manually or by saving the AI's drafts), use POST /surveys/:id/review to run them through a quality check. The reviewer flags:

  • Leading or biased phrasings
  • Double-barrelled questions (two asks in one)
  • Redundancy across questions
  • Confusing answer options
  • Ordering / flow issues

The endpoint does not edit anything — it returns suggestions for you to apply manually via PATCH /questions/:id.

json
{
  "data": [
    {
      "question_id": "q1c2d3e4-...",
      "issue": "leading",
      "severity": "warning",
      "message": "\"How great was our onboarding?\" presupposes the answer is positive.",
      "suggested_title": "How would you describe your onboarding experience?"
    }
  ]
}

The exact suggestion shape is owned by the AI engine and may evolve. Render unknown keys as plain text.


Adaptive AI surveys

Setting mode: "ai" on a survey makes the experience conversational — the AI engine asks one question at a time, branching based on the respondent's prior answers. The engine decides when there are no more useful questions to ask.

Authoring an AI survey

You don't author questions for AI surveys. Instead, you set the engine's brief in ai_config:

bash
curl -X PATCH https://app.krafter.dev/api/v1/surveys/SURVEY_ID \
  -H "Authorization: Bearer kr_live_abc123def456" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "ai",
    "ai_config": {
      "goal": "Understand why this user signed up",
      "target_questions": 5,
      "tone": "casual",
      "language": "en"
    }
  }'
ai_config fieldDescription
goalWhat the survey should learn. Required for AI mode
target_questionsSoft cap on conversation length
tone"formal", "casual", etc.
languageLanguage code
audienceTarget persona description

You can additionally seed the conversation with a "warmup" question authored manually — the AI will pick it up from questions[0] if present.

Respondent flow (AI mode)

The embed widget and standalone survey page handle this automatically. If you're rendering the survey yourself, the loop is:

  1. Start a responsePOST /api/v1/surveys/:slug/responses (same as manual mode)
  2. Ask the AI for the next questionPOST /api/v1/surveys/:slug/next with the running conversation array:
    json
    {
      "conversation": [
        {"role": "ai", "question": "What did you build with Krafter?"},
        {"role": "user", "answer": "A signup form"}
      ]
    }
  3. Render the question, capture the answer, append to conversation, repeat step 2.
  4. Save progress via PATCH /api/v1/surveys/:slug/responses/:response_id — pass the full ai_conversation array. The response's ai_cost_cents is updated server-side
  5. When done: true comes back from /next, call POST /complete

The data shape from /next:

json
// More questions to come
{
  "data": {
    "question": "How long did the form take to set up?",
    "type": "text",
    "done": false
  }
}

// Conversation is complete
{
  "data": {
    "summary": "User successfully built a signup form in under 10 minutes.",
    "done": true
  }
}

Cost

AI conversations call an LLM on every /next, so total cost scales with conversation length and answer verbosity. Each response's ai_cost_cents field accrues the running token cost — surface it on the dashboard if you want per-response cost visibility.


Response summaries

Once you have enough completed responses, summarise them:

  1. Enqueue a jobPOST /surveys/:id/summary. Returns 202 Accepted immediately
  2. Wait for completion — either subscribe to the summary.generated webhook or poll GET /surveys/:id/summary
  3. Read the summary — text overview, bullet insights, response tags, confidence

Summaries run a single LLM call against the completed responses for the survey. Cost scales with response count and answer length. The dashboard rate-limits regenerations; if you generate programmatically, throttle.

The latest summary is what GET /surveys/:id/summary returns. Older summaries are retained in the database (for the audit trail) but not exposed via the API today.

See Analytics → Summary for the full schema.


When the engine isn't configured

If the LLM backend isn't wired up — no API key, model unreachable — the four AI endpoints return 503 Service Unavailable with {"error": "AI engine not configured"}. The platform operator (typically the team running the Krafter installation) is responsible for provisioning the LLM provider. On the hosted app.krafter.dev deployment, this is always configured.

For self-hosting, see the self-hosting guides — the AI engine is opt-in, and surveys gracefully degrade to manual mode without it (the manual-mode flow does not depend on the engine at all).


Privacy considerations

AI features send respondent answers (and, for review, your question text) to the configured LLM provider. If you handle answers covered by data-handling agreements (PII, medical, financial), confirm with your provider that:

  • Your account is on a no-training tier
  • Inputs are not retained beyond the request lifetime
  • The data residency of the provider matches your jurisdiction

The Krafter platform does not redact PII before sending — it forwards answers as-is. If you need to redact, do it on your side before saving via save_progress, or stick to manual surveys.

Built by Krafter Studio