Embedding & API
Embed a feedback widget in your app or build a custom UI with the REST API.
Overview
Lupr exposes a set of public API endpoints for projects that have the badge enabled. These endpoints require no authentication — just enable the badge on your project and start making requests. All endpoints are CORS-enabled so you can call them directly from the browser.
Looking for the full integration guide? See the developer integration guide for step-by-step setup instructions, webhook configuration, and best practices.
Embed widget
Drop a lightweight feedback widget into any page. The widget loads asynchronously and renders a feedback form tied to your project. All you need is your project ID.
HTML / Script tag
Paste the following snippet before the closing </body> tag of your page.
<!-- Lupr feedback widget -->
<div id="lupr-widget" data-project="YOUR_PROJECT_ID"></div>
<script src="https://app.lupr.dev/widget.js" async></script>React / Next.js
For React or Next.js apps, use a useEffect hook to inject the widget script dynamically.
"use client";
import { useEffect } from "react";
export function LuprWidget({ projectId }: { projectId: string }) {
useEffect(() => {
const script = document.createElement("script");
script.src = "https://app.lupr.dev/widget.js";
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
return <div id="lupr-widget" data-project={projectId} />;
}data-project attribute: The data-project attribute connects the widget to your Lupr project. You can find your project ID on the project settings page.
REST API reference
All endpoints are publicly accessible for projects with the badge enabled. No API key or authentication header is required. The base URL is https://app.lupr.dev.
/api/pitches/{id}/widget
Returns the feedback feed for a project, including project metadata, aggregate stats, and a paginated list of feedback items.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| sort | string | votes | "votes" (most voted first) or "recent" (newest first) |
| limit | number | 10 | Number of feedback items to return. Range: 1–50. |
| status | string | all | "open", "under_consideration", "planned", "in_progress", "addressed", "not_now", "thank_you" |
curl "https://app.lupr.dev/api/pitches/clx123abc/widget?sort=votes&limit=5"{
"project": {
"id": "clx123abc",
"title": "My SaaS Product",
"badgeEnabled": true
},
"stats": {
"feedbackCount": 42,
"avgRating": 4.2,
"pmfScore": 73,
"topTags": ["ux", "pricing", "feature-request"]
},
"feedback": [
{
"id": "fb_001",
"text": "Love the onboarding flow, but pricing page needs work.",
"authorName": "Jane D.",
"rating": 4,
"wouldUse": true,
"votes": 12,
"status": "under_consideration",
"tags": ["pricing", "ux"],
"createdAt": "2026-02-15T10:30:00Z"
}
]
}/api/pitches/{id}/badge
Returns badge data for a project as JSON. Useful for building custom badge UIs or displaying validation status in your own components.
curl "https://app.lupr.dev/api/pitches/clx123abc/badge"{
"pitchTitle": "My SaaS Product",
"pmfScore": 73,
"feedbackCount": 42,
"avgRating": 4.2,
"validated": true
}/api/pitches/{id}/badge/svg
Returns an SVG badge image for embedding in READMEs, pitch decks, and landing pages. The badge color reflects the current validation score. The response content type is image/svg+xml.
curl "https://app.lupr.dev/api/pitches/clx123abc/badge/svg"
# Returns: SVG image (image/svg+xml)/api/pitches/{id}/feedback/public
Submit public feedback to a project. The project must have the badge enabled. Feedback submitted through this endpoint appears in the project's feedback list alongside invited reviewer feedback.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | Yes | The feedback text. Max 2000 characters. |
| authorName | string | No | Display name for the author. Defaults to "Anonymous". |
| wouldUse | boolean | No | "Would you use this?" Used for validation score calculation. |
curl -X POST "https://app.lupr.dev/api/pitches/clx123abc/feedback/public" \
-H "Content-Type: application/json" \
-d '{
"text": "Great product! The onboarding is smooth but I wish there was a dark mode option.",
"authorName": "Alex",
"wouldUse": true
}'{
"id": "fb_002",
"text": "Great product! The onboarding is smooth but I wish there was a dark mode option.",
"authorName": "Alex",
"wouldUse": true,
"status": "open",
"createdAt": "2026-03-01T14:22:00Z"
}Badge required: The badge must be enabled on the project for this endpoint to accept submissions. Enable it from your project settings page.
Status labels
Feedback items can be assigned one of seven status labels. These statuses are returned in API responses and displayed in the widget. Use the status query parameter on the widget endpoint to filter by status.
Badge embed
Display a validation badge on your landing page, README, or pitch deck. The badge automatically updates to reflect your current validation score and feedback count.
HTML embed
<a href="https://app.lupr.dev/pitch/clx123abc">
<img
src="https://app.lupr.dev/api/pitches/clx123abc/badge/svg"
alt="Lupr validation badge"
/>
</a>Markdown embed
[](https://app.lupr.dev/pitch/clx123abc)Badge variants
The badge color changes automatically based on your validation score:
Validated
Score > 70%Promising
Score 40–70%Pending
Not enough dataCustom domain
You can serve your public project page and badge from a custom domain instead of app.lupr.dev. This lets you keep embed URLs and badge images on your own brand domain.
Custom domains are configured in your project settings. You'll need to add a CNAME record pointing to Lupr and verify ownership. See the settings documentation for full setup instructions.
Rate limits
Public API endpoints are rate-limited to prevent abuse. Rate limits are applied per IP address.
| Endpoint | Limit |
|---|---|
| GET endpoints (widget, badge, SVG) | 60 requests / minute |
| POST /feedback/public | 10 requests / minute |
429 Too Many Requests: If you exceed the rate limit, the API returns a 429 status code. Retry after the number of seconds indicated in the Retry-After response header.