Back to Docs

Feedback Collection

Collect customer feedback from your app using widgets, forms, or direct API calls.

import { useState } from 'react';

interface FeedbackWidgetProps {
  apiKey: string;
  userEmail?: string;
  userName?: string;
}

export function FeedbackWidget({ apiKey, userEmail, userName }: FeedbackWidgetProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [content, setContent] = useState('');
  const [status, setStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setStatus('sending');

    try {
      const res = await fetch('https://simpleproduct.dev/api/v1/feedback', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          title: 'Feedback',
          content,
          email: userEmail,
          name: userName,
          source: 'react-widget',
          metadata: { page: window.location.pathname },
        }),
      });

      if (res.ok) {
        setStatus('sent');
        setTimeout(() => {
          setIsOpen(false);
          setStatus('idle');
          setContent('');
        }, 2000);
      } else {
        setStatus('error');
      }
    } catch {
      setStatus('error');
    }
  };

  if (!isOpen) {
    return (
      <button
        onClick={() => setIsOpen(true)}
        style={{
          position: 'fixed',
          bottom: '20px',
          right: '20px',
          padding: '12px 24px',
          borderRadius: '8px',
          border: 'none',
          background: '#000',
          color: '#fff',
          cursor: 'pointer',
        }}
      >
        Feedback
      </button>
    );
  }

  return (
    <div style={{
      position: 'fixed',
      bottom: '20px',
      right: '20px',
      width: '320px',
      padding: '20px',
      borderRadius: '12px',
      background: '#fff',
      boxShadow: '0 4px 20px rgba(0,0,0,0.15)',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '16px' }}>
        <h3 style={{ margin: 0 }}>Send Feedback</h3>
        <button onClick={() => setIsOpen(false)} style={{ background: 'none', border: 'none', cursor: 'pointer' }}>✕</button>
      </div>

      {status === 'sent' ? (
        <p>Thanks for your feedback!</p>
      ) : (
        <form onSubmit={handleSubmit}>
          <textarea
            value={content}
            onChange={(e) => setContent(e.target.value)}
            placeholder="What's on your mind?"
            required
            style={{ width: '100%', minHeight: '100px', marginBottom: '12px', padding: '8px', borderRadius: '6px', border: '1px solid #ddd' }}
          />
          <button
            type="submit"
            disabled={status === 'sending'}
            style={{ width: '100%', padding: '10px', borderRadius: '6px', border: 'none', background: '#000', color: '#fff', cursor: 'pointer' }}
          >
            {status === 'sending' ? 'Sending...' : 'Send'}
          </button>
          {status === 'error' && <p style={{ color: 'red', marginTop: '8px' }}>Something went wrong. Please try again.</p>}
        </form>
      )}
    </div>
  );
}

// Usage in your app
function App() {
  return (
    <>
      {/* Your app content */}
      <FeedbackWidget
        apiKey="YOUR_API_KEY"
        userEmail={currentUser?.email}
        userName={currentUser?.name}
      />
    </>
  );
}

API Reference

POST /api/v1/feedback

Headers

  • Authorization: Bearer YOUR_API_KEY (required)
  • Content-Type: application/json

Request Body

FieldTypeRequiredDescription
titlestringYesFeedback title/subject
contentstringYesThe feedback message
emailstringNoCustomer email (creates/links customer record)
namestringNoCustomer name
externalIdstringNoYour user ID for identity matching
sourcestringNoWhere feedback came from (e.g., "widget", "nps")
metadataobjectNoAny custom JSON data

Response

{ "data": { "id": "abc123", "title": "Feedback", "content": "...", "person": { "id": "...", "name": "John", "email": "john@example.com" }, "createdAt": 1234567890 } }

Tips

  • Link feedback to customers: Include email to automatically create/link customer records
  • Track sources: Use the source field to see where feedback comes from
  • Add context: Use metadata to include page URL, user agent, feature flags, etc.