Collecting Feedback
Collect and manage user feedback with the CobblPublicClient
The CobblPublicClient allows you to collect user feedback for prompt runs. This feedback is used to improve your prompts over time.
Feedback collection uses CobblPublicClient. It doesn't require authentication and is safe for browser environments.
Overview
The public client is designed for end-user feedback submission and does not require authentication. This makes it safe to use in client-side applications.
import { CobblPublicClient } from '@cobbl-ai/sdk'
const publicClient = new CobblPublicClient()Creating Feedback
Use createFeedback to submit new feedback for a prompt run:
await publicClient.createFeedback({
runId: 'run_abc123',
helpful: 'helpful',
userFeedback: 'This response was exactly what I needed!',
})Parameters
| Field | Type | Required | Description |
|---|---|---|---|
runId | string | Yes | The run ID from runPrompt() |
helpful | 'helpful' | 'not_helpful' | No* | Whether the output was helpful |
userFeedback | string | No* | Detailed feedback message |
At least one of helpful or userFeedback is required.
The runId comes from the response when running a prompt with
CobblAdminClient. Make sure to
persist this ID so users can provide feedback later.
Response
interface CreateFeedbackResponse {
id: string // Unique ID for the feedback item
message: string // Success message
}Examples
Rating Only
const { id } = await publicClient.createFeedback({
runId: result.runId,
helpful: 'helpful',
})Feedback Text Only
const { id } = await publicClient.createFeedback({
runId: result.runId,
userFeedback: 'The response was too formal for my use case.',
})Both Rating and Text
const { id } = await publicClient.createFeedback({
runId: result.runId,
helpful: 'not_helpful',
userFeedback: 'The tone was too casual for a professional email.',
})Updating Feedback
Use updateFeedback to add or modify feedback after initial submission:
await publicClient.updateFeedback('feedback_xyz789', {
userFeedback: 'Actually, after reading again, this could be shorter.',
})Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The feedback ID from create |
helpful | 'helpful' | 'not_helpful' | No | Update the helpfulness rating |
userFeedback | string | No | Update the feedback text |
Example: Progressive Feedback
First collect a rating, then add detailed feedback:
// Step 1: Quick rating
const { id } = await publicClient.createFeedback({
runId: result.runId,
helpful: 'not_helpful',
})
// Step 2: User provides more details
await publicClient.updateFeedback(id, {
userFeedback: 'The response was too verbose and missed key points.',
})React Integration
Feedback Form Component
'use client'
import { useState } from 'react'
import { CobblPublicClient } from '@cobbl-ai/sdk'
const publicClient = new CobblPublicClient()
interface FeedbackFormProps {
runId: string
onSubmit?: () => void
}
export const FeedbackForm = ({ runId, onSubmit }: FeedbackFormProps) => {
const [feedback, setFeedback] = useState('')
const [helpful, setHelpful] = useState<'helpful' | 'not_helpful' | null>(null)
const [isSubmitting, setIsSubmitting] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!helpful && !feedback) return
setIsSubmitting(true)
try {
await publicClient.createFeedback({
runId,
helpful: helpful || undefined,
userFeedback: feedback || undefined,
})
onSubmit?.()
} catch (error) {
console.error('Failed to submit feedback:', error)
} finally {
setIsSubmitting(false)
}
}
return (
<form onSubmit={handleSubmit}>
<div>
<button
type="button"
onClick={() => setHelpful('helpful')}
className={helpful === 'helpful' ? 'selected' : ''}
>
👍 Helpful
</button>
<button
type="button"
onClick={() => setHelpful('not_helpful')}
className={helpful === 'not_helpful' ? 'selected' : ''}
>
👎 Not Helpful
</button>
</div>
<textarea
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
placeholder="Tell us what could be improved..."
/>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Submitting...' : 'Submit Feedback'}
</button>
</form>
)
}Using via API Route
For better separation, you can proxy feedback through your own API:
import { CobblPublicClient } from '@cobbl-ai/sdk'
import { NextResponse } from 'next/server'
const publicClient = new CobblPublicClient()
export const POST = async (request: Request) => {
const body = await request.json()
try {
const result = await publicClient.createFeedback({
runId: body.runId,
helpful: body.helpful,
userFeedback: body.userFeedback,
})
return NextResponse.json(result)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to submit feedback' },
{ status: 500 }
)
}
}// Then call your API route instead
const handleSubmit = async () => {
await fetch('/api/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ runId, helpful, userFeedback: feedback }),
})
}Feedback Widget
For an even simpler integration, consider using the Cobbl Feedback Widget — a drop-in embeddable widget for collecting user feedback:
import { FeedbackWidget } from '@cobbl-ai/feedback-widget/react'
const App = () => <FeedbackWidget runId={result.runId} variant="thumbs" />The widget supports:
- Script tag — Drop into any HTML page
- JavaScript — Stripe Elements-style API
- React — First-class React component
Best Practices
1. Store Run IDs for Later
The runId is returned when running prompts with
CobblAdminClient. Always persist
this ID.
const result = await adminClient.runPrompt('chatbot', { query })
// Store for feedback
await db.conversations.create({
message: result.output,
runId: result.runId,
})2. Make Feedback Optional
Don't require users to provide feedback — make it easy and unobtrusive:
<button onClick={() => setShowFeedback(true)}>Was this helpful?</button>3. Use Progressive Feedback
Collect quick ratings first, then ask for details. This helps you get feedback if the user doesn't complete the form.
// Quick thumbs up/down
const { id } = await publicClient.createFeedback({
runId,
helpful: 'not_helpful',
})
// If negative, prompt for more details
if (helpful === 'not_helpful') {
// Show text input
await publicClient.updateFeedback(id, {
userFeedback: detailedFeedback,
})
}