Cobbl
CobblPublicClient

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.

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

FieldTypeRequiredDescription
runIdstringYesThe run ID from runPrompt()
helpful'helpful' | 'not_helpful'No*Whether the output was helpful
userFeedbackstringNo*Detailed feedback message

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

FieldTypeRequiredDescription
idstringYesThe feedback ID from create
helpful'helpful' | 'not_helpful'NoUpdate the helpfulness rating
userFeedbackstringNoUpdate 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

components/FeedbackForm.tsx
'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:

app/api/feedback/route.ts
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 }
    )
  }
}
components/FeedbackForm.tsx
// 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

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,
  })
}

Next Steps

On this page