Scout AI Client SDK Reference

Last updated: 01/16/2026
About this sample

Scout AI is an Azure Function–based REST API that brings Anthropic Claude–powered research assistance into the UserLens Insights platform. This SDK integration guide was built from scratch to give developers a clear, structured path to integrating Scout AI into their own tooling — covering authentication, endpoint reference, request and response patterns, and error handling. No documentation existed before this work began, and the API was actively changing throughout. The guide was written to reduce integration friction and eliminate the need for developers to go directly to the engineering team for answers.

The main client class. All API interactions go through an instance of this class.

import { ScoutAIClient } from '@userlens/scout-ai';

Constructor

new ScoutAIClient(config: ScoutAIClientConfig)

Creates a new client instance.

ParameterTypeRequiredDescription
config.baseUrlstringYesBase URL of the Scout AI API. Trailing slashes are stripped automatically.
config.headersRecord<string, string>NoAdditional headers merged into every request. Use for auth tokens or routing headers.
config.fetchtypeof globalThis.fetchNoCustom fetch implementation. Defaults to the global fetch. Useful for Node.js < 18 polyfills or injecting mocks in tests.

Example:

const client = new ScoutAIClient({
  baseUrl: 'https://your-app.azurestaticapps.net/api/scout-ai',
  headers: {
    Authorization: 'Bearer eyJhbG...',
  },
});

health()

health(): Promise<HealthResponse>

Check the API status and whether the Anthropic API key is configured.

Parameters: None

Returns: HealthResponse

FieldTypeDescription
statusstringService status (e.g. "ok")
servicestringService name
anthropicConfiguredbooleanWhether the Anthropic API key is set

HTTP: GET /health

Example:

const status = await client.health();
console.log(status.anthropicConfigured); // true

complete()

complete(params: CompleteParams): Promise<string>

Send a one-shot completion request with a system and user prompt. This is the most flexible endpoint — use it for custom AI interactions that don't fit the specialized research methods.

Parameters: CompleteParams

FieldTypeRequiredDefaultDescription
systemPromptstringYesSystem-level instruction for the model
userPromptstringYesThe user message to send
maxTokensnumberNo4096Maximum tokens in the response
temperaturenumberNo0.7Sampling temperature (0–1)

Returns: string — The model's response text.

HTTP: POST /

Example:

const response = await client.complete({
  systemPrompt: 'You are a UX research expert.',
  userPrompt: 'What are the key principles of usability testing?',
  temperature: 0.5,
});

chat()

chat(params: ChatParams): Promise<string>

Send a multi-turn chat message with optional conversation history. Supports citation instructions for research-grounded responses.

Parameters: ChatParams

FieldTypeRequiredDefaultDescription
userPromptstringYesThe current user message
systemPromptstringNoSystem-level instruction
messagesChatMessage[]No[]Prior conversation messages for multi-turn context
maxTokensnumberNo4096Maximum tokens in the response
temperaturenumberNo0.7Sampling temperature (0–1)
includeCitationsbooleanNotrueInstruct the model to cite evidence using bracketed identifiers (e.g. [Session P1])

Returns: string — The model's response text.

HTTP: POST /stream (returns plain text, not JSON)

Example:

const reply = await client.chat({
  systemPrompt: 'You are Scout AI, a UX research assistant.',
  userPrompt: 'What patterns do you see across these sessions?',
  messages: [
    { role: 'user', content: 'Here are my session notes for 5 participants...' },
    { role: 'assistant', content: 'I can see several emerging themes...' },
  ],
});

rewrite()

rewrite(params: RewriteParams): Promise<string>

Rewrite text to improve clarity, conciseness, and impact. Optionally provide a specific focus or direction for the rewrite.

Parameters: RewriteParams

FieldTypeRequiredDefaultDescription
textstringYesThe text to rewrite
focusstringNoSpecific rewrite direction. When omitted, a general improvement is applied.

Returns: string — The improved text with no preamble or explanation.

HTTP: POST /rewrite

Example:

const improved = await client.rewrite({
  text: 'The user was not able to find the button easily and had trouble.',
  focus: 'Make this more concise and suitable for a stakeholder report',
});
// "The user struggled to locate the button."

analyzeHypotheses()

analyzeHypotheses(params: HypothesisAnalysisParams): Promise<string>

Evaluate research hypotheses against collected research data. Returns a structured Markdown analysis including supporting/contradicting evidence, confidence levels, and recommended status changes for each hypothesis.

Parameters: HypothesisAnalysisParams

FieldTypeRequiredDefaultDescription
projectNamestringNo"Research Project"Name of the research project
hypothesesHypothesisInput[]YesHypotheses to evaluate
researchDataResearchDataItem[]YesResearch data to analyze against

Returns: string — Markdown-formatted analysis containing:

  • Per-hypothesis evaluation with recommended status and confidence level
  • Supporting and contradicting evidence with citations
  • Summary counts (validated, invalidated, partial, insufficient)
  • Key insights and prioritized recommendations

HTTP: POST /hypotheses

Limits: First 5 research items used; each truncated to 2 000 characters.

Example:

const analysis = await client.analyzeHypotheses({
  projectName: 'Mobile App Redesign',
  hypotheses: [
    { statement: 'Users prefer bottom navigation over hamburger menus', status: 'untested' },
    { statement: 'Onboarding reduces churn for new users', status: 'testing' },
  ],
  researchData: [
    { title: 'Session P1', content: 'Participant immediately looked to the bottom...' },
    { title: 'Session P2', content: 'User skipped the onboarding tutorial...' },
  ],
});

generateReport()

generateReport(params: ReportParams): Promise<string>

Generate a findings report from synthesis notes and hypotheses.

Parameters: ReportParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
synthesisNotesSynthesisNote[]No[]Notes to base the report on
hypothesesHypothesisInput[]No[]Hypotheses to include
reportTypeReportTypeNo"detailed"Report format

Report types:

TypeDescription
"executive"Concise 1–2 page summary focused on business impact
"detailed"Comprehensive analysis with full findings and recommendations
"presentation"Formatted for slides with headers and bullet points

Returns: string — Markdown-formatted report.

HTTP: POST /report

Limits: First 20 synthesis notes used; each truncated to 500 characters.

Example:

const report = await client.generateReport({
  projectName: 'Checkout Redesign',
  reportType: 'executive',
  synthesisNotes: [
    { content: '3 of 5 users abandoned at the payment step', theme: 'drop-off' },
    { content: 'Users praised the progress indicator', theme: 'positive' },
  ],
  hypotheses: [
    { statement: 'Simplifying the form reduces abandonment', status: 'validated' },
  ],
});

summarizeSessions()

summarizeSessions(params: SummaryParams): Promise<string>

Summarize multiple user research session notes into a structured analysis.

Parameters: SummaryParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
sessionNotesSessionNote[]YesSession notes to summarize
summaryTypeSummaryTypeNo"overview"Summary format

Summary types:

TypeDescription
"overview"Executive summary with top 5–7 findings and recommendations
"findings-report"Full UX research report with severity ratings, evidence tables, and prioritized recommendations
"detailed"Participant-by-participant breakdown with task completion analysis
"themes"Thematic analysis identifying 3–7 major themes with prevalence and relationships
"quotes"Top 10–15 impactful quotes grouped by theme with sentiment analysis

Returns: string — Markdown-formatted summary.

HTTP: POST /session-summary

Limits: "findings-report": max 8 sessions, 2 500 chars each. Others: max 10 sessions, 2 000 chars each.

Example:

const summary = await client.summarizeSessions({
  projectName: 'Dashboard UX Study',
  summaryType: 'themes',
  sessionNotes: [
    { title: 'P1 - Sarah (Product Manager)', content: 'Found the dashboard overwhelming...' },
    { title: 'P2 - James (Developer)', content: 'Wanted more customization options...' },
    { title: 'P3 - Maria (Designer)', content: 'Appreciated the visual hierarchy...' },
  ],
});

generatePersonas()

generatePersonas(params: PersonaParams): Promise<string>

Generate user personas from research data. Each persona includes demographics, goals, pain points, behaviors, and a representative quote.

Parameters: PersonaParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
researchData(string | ResearchDataItem)[]No[]Source research data
countnumberNo3Number of personas to generate

Returns: string — Markdown-formatted personas.

HTTP: POST /personas

Limits: First 10 research items used; each truncated to 1 000 characters.

Example:

const personas = await client.generatePersonas({
  projectName: 'E-commerce Platform',
  count: 4,
  researchData: [
    { title: 'Interview - Power User', content: 'Shops daily, price-sensitive...' },
    { title: 'Interview - Casual Browser', content: 'Visits weekly, discovery-driven...' },
  ],
});

createJourneyMap()

createJourneyMap(params: JourneyMapParams): Promise<string>

Create a customer journey map from research data. Maps the user experience across phases including actions, emotions, pain points, and opportunities.

Parameters: JourneyMapParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
researchData(string | ResearchDataItem)[]No[]Source research data

Returns: string — Markdown-formatted journey map.

HTTP: POST /journey-map

Limits: First 8 research items used; each truncated to 1 500 characters.

Example:

const journeyMap = await client.createJourneyMap({
  projectName: 'Support Ticket Flow',
  researchData: [
    { title: 'Session 1', content: 'User started by searching the FAQ, then...' },
    { title: 'Session 2', content: 'User went directly to live chat...' },
  ],
});

extractThemes()

extractThemes(params: ThemeParams): Promise<string>

Extract themes from research data using thematic analysis. Identifies 3–7 major themes with supporting evidence, relationships, and recommendations.

Parameters: ThemeParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
researchData(string | ResearchDataItem)[]No[]Source research data

Returns: string — Markdown-formatted theme analysis.

HTTP: POST /themes

Limits: First 10 research items used; each truncated to 1 500 characters.

Example:

const themes = await client.extractThemes({
  projectName: 'Dashboard Redesign',
  researchData: [
    { title: 'Interview 1', content: 'Participant mentioned information overload...' },
    { title: 'Interview 2', content: 'Wanted to customize which widgets appear...' },
  ],
});

generateInterviewGuide()

generateInterviewGuide(params: InterviewGuideParams): Promise<string>

Generate a structured interview guide for user research sessions. Produces an introduction script, warm-up questions, objective-based main questions with follow-up probes, and interviewer tips.

Parameters: InterviewGuideParams

FieldTypeRequiredDefaultDescription
projectNamestringYesProject name
objectivesstring[]No[]Research objectives the guide should address
durationnumberNo60Target interview duration in minutes

Returns: string — Markdown-formatted interview guide.

HTTP: POST /interview-guide

Limits: First 10 objectives used.

Example:

const guide = await client.generateInterviewGuide({
  projectName: 'Navigation Redesign',
  objectives: [
    'Understand how users discover features',
    'Identify navigation pain points',
    'Evaluate mental models for information architecture',
  ],
  duration: 45,
});

Types

Configuration

ScoutAIClientConfig

interface ScoutAIClientConfig {
  baseUrl: string;
  headers?: Record<string, string>;
  fetch?: typeof globalThis.fetch;
}

HealthResponse

interface HealthResponse {
  status: string;
  service: string;
  anthropicConfigured: boolean;
}

Request Types

CompleteParams

interface CompleteParams {
  systemPrompt: string;
  userPrompt: string;
  maxTokens?: number;    // default: 4096
  temperature?: number;  // default: 0.7
}

ChatParams

interface ChatParams {
  userPrompt: string;
  systemPrompt?: string;
  messages?: ChatMessage[];
  maxTokens?: number;       // default: 4096
  temperature?: number;     // default: 0.7
  includeCitations?: boolean; // default: true
}

RewriteParams

interface RewriteParams {
  text: string;
  focus?: string;
}

HypothesisAnalysisParams

interface HypothesisAnalysisParams {
  projectName?: string;          // default: "Research Project"
  hypotheses: HypothesisInput[];
  researchData: ResearchDataItem[];
}

ReportParams

interface ReportParams {
  projectName: string;
  synthesisNotes?: SynthesisNote[];
  hypotheses?: HypothesisInput[];
  reportType?: ReportType;  // default: "detailed"
}

SummaryParams

interface SummaryParams {
  projectName: string;
  sessionNotes: SessionNote[];
  summaryType?: SummaryType;  // default: "overview"
}

PersonaParams

interface PersonaParams {
  projectName: string;
  researchData?: (string | ResearchDataItem)[];
  count?: number;  // default: 3
}

JourneyMapParams

interface JourneyMapParams {
  projectName: string;
  researchData?: (string | ResearchDataItem)[];
}

ThemeParams

interface ThemeParams {
  projectName: string;
  researchData?: (string | ResearchDataItem)[];
}

InterviewGuideParams

interface InterviewGuideParams {
  projectName: string;
  objectives?: string[];
  duration?: number;  // default: 60
}

Domain Types

ChatMessage

interface ChatMessage {
  role: 'user' | 'assistant';
  content: string;
}

HypothesisInput

interface HypothesisInput {
  statement: string;
  status: 'validated' | 'invalidated' | 'partial' | 'untested'
        | 'testing' | 'supported' | 'partially_supported';
}

ResearchDataItem

interface ResearchDataItem {
  title?: string;
  content: string;
}

SynthesisNote

interface SynthesisNote {
  content: string;
  theme?: string;
}

SessionNote

interface SessionNote {
  title: string;
  content: string;
}

Enums

ReportType

type ReportType = 'executive' | 'detailed' | 'presentation';

SummaryType

type SummaryType = 'overview' | 'findings-report' | 'detailed' | 'themes' | 'quotes';

Errors

All errors extend ScoutAIError, which extends the built-in Error. This lets you catch all SDK errors with a single catch or handle specific failure modes individually.

import {
  ScoutAIError,
  ScoutAIValidationError,
  ScoutAIContentTooLargeError,
  ScoutAIRateLimitError,
  ScoutAIServerError,
} from '@userlens/scout-ai';

Error hierarchy

Error
 └── ScoutAIError
      ├── ScoutAIValidationError      (400)
      ├── ScoutAIContentTooLargeError  (413)
      ├── ScoutAIRateLimitError        (429)
      └── ScoutAIServerError           (5xx)

Common properties

Every error class has these properties:

PropertyTypeDescription
messagestringHuman-readable error description
statusnumberHTTP status code from the API
codestringMachine-readable error code
namestringError class name

ScoutAIError

Base class for all SDK errors.

class ScoutAIError extends Error {
  readonly status: number;
  readonly code: string;
}

Static method:

ScoutAIError.fromResponse(status: number, body: { error?: string }): ScoutAIError

Factory that creates the appropriate error subclass based on the HTTP status code. Used internally by the client. If the response body has no error field, a default message is generated.


ScoutAIValidationError

Thrown when the API rejects the request due to invalid or missing parameters.

PropertyValue
status400
code"validation_error"
name"ScoutAIValidationError"

Common causes:

  • Missing required fields (e.g. userPrompt, sessionNotes)
  • Empty hypothesis or research data arrays
  • Using an unsupported HTTP method

ScoutAIContentTooLargeError

Thrown when the request payload exceeds the API's content size limit (~100 000 characters / ~25 000 tokens).

PropertyValue
status413
code"content_too_large"
name"ScoutAIContentTooLargeError"

How to resolve:

  • Reduce the number of session notes or research data items
  • Shorten individual content strings
  • Use fewer messages in conversation history

ScoutAIRateLimitError

Thrown when the underlying AI provider rate-limits the request.

PropertyValue
status429
code"rate_limit"
name"ScoutAIRateLimitError"

How to resolve:

  • Implement exponential back-off before retrying
  • Reduce request frequency

ScoutAIServerError

Thrown for unexpected server-side failures.

PropertyValue
status500 (or other 5xx)
code"server_error"
name"ScoutAIServerError"

How to resolve:

  • Retry after a brief delay
  • If persistent, check the API health endpoint

Error handling example

try {
  const summary = await client.summarizeSessions({
    projectName: 'My Study',
    sessionNotes: notes,
  });
} catch (err) {
  if (err instanceof ScoutAIContentTooLargeError) {
    // Reduce content and retry
    const fewerNotes = notes.slice(0, 5);
    const summary = await client.summarizeSessions({
      projectName: 'My Study',
      sessionNotes: fewerNotes,
    });
  } else if (err instanceof ScoutAIRateLimitError) {
    // Wait and retry
    await new Promise(r => setTimeout(r, 5000));
    // retry...
  } else if (err instanceof ScoutAIError) {
    // Any other API error
    console.error(`Scout AI error (${err.code}): ${err.message}`);
  } else {
    // Network error, etc.
    throw err;
  }
}