@feedclip/sdk
v0.1.34
Published
Video feedback SDK for React, Vue, and Angular
Downloads
896
Maintainers
Readme
FeedClip SDK
Video feedback for React, Vue, and Angular.
Website · GitHub · Live examples · Changelog
FeedClip records a selected tab, window, or screen in the browser, with an optional microphone or explicit camera mode. Users can review the clip, capture the current frame, annotate it, and send video, screenshots, written feedback, and product context to a destination you control.
- React 19, Vue 3, and Angular 19–21
- TypeScript, ESM, CommonJS, and CSS builds
- Local preview before anything is submitted
- Custom HTTP, IndexedDB, Supabase, and S3 transports
- Optional FeedClip Pro and FeedClip Cloud
Installation
React:
npm install @feedclip/sdk react react-domVue:
npm install @feedclip/sdk vue react react-domAngular:
npm install @feedclip/sdk @angular/core react react-domThe Vue and Angular entrypoints are lifecycle adapters over the same React capture engine, so they also require React 19 and React DOM 19.
React quick start
import FeedClip, {
createIndexedDbFeedbackStore,
} from "@feedclip/sdk";
import "@feedclip/sdk/style.css";
const saveFeedback = createIndexedDbFeedbackStore({
databaseName: "my-product-feedback",
});
export function Feedback() {
return (
<FeedClip
config={{
locale: "en-US",
maxDurationMilliSeconds: 60_000,
maxFileSize: 25 * 1024 * 1024,
defaultVideoFileExtension: "webm",
defaultVideoFileNameStyle: "ISO 8601",
onSubmit: saveFeedback,
// Replace these sample values with your own non-sensitive metadata.
getContext: () => ({
accountId: "account-123",
appVersion: "1.0.0",
}),
diagnostics: {
enabled: true,
},
}}
/>
);
}IndexedDB keeps submissions in the browser and is useful for local development and the Free examples. For production, provide an authenticated backend or use FeedClip Cloud.
Floating launcher
Use FeedClipLauncher when feedback should open from a chat-style button above
your product instead of occupying space in the page layout:
import { FeedClipLauncher } from "@feedclip/sdk";
import "@feedclip/sdk/style.css";
export function AppFeedback() {
return (
<FeedClipLauncher
label="Report a problem"
position="bottom-right"
config={{
locale: "en-US",
maxDurationMilliSeconds: 60_000,
maxFileSize: 25 * 1024 * 1024,
defaultVideoFileExtension: "webm",
defaultVideoFileNameStyle: "ISO 8601",
onSubmit: submitFeedback,
}}
/>
);
}The launcher is portaled into document.body, uses a fixed high stacking
layer, respects mobile safe areas, and defaults to the bottom-right corner.
Opening it never starts a recording or asks for media permission; the customer
still explicitly chooses Record screen or Use camera. Escape and the
close controls dismiss it and restore focus to the launcher.
Available positions are bottom-right, bottom-left, top-right, and
top-left. Use controlled open and onOpenChange props when your own Help
menu, support chat, or application state should control the panel. The default
English and Russian launcher labels follow config.locale; override label
and closeLabel for product-specific wording.
Vue exports FeedClipLauncherVue from @feedclip/sdk/vue. Angular exports
FeedClipAngularLauncherComponent from @feedclip/sdk/angular with the
<feedclip-launcher> selector.
Vue
<script setup lang="ts">
import FeedClipVue from "@feedclip/sdk/vue";
import { createIndexedDbFeedbackStore } from "@feedclip/sdk";
import "@feedclip/sdk/style.css";
const config = {
locale: "en-US" as const,
maxDurationMilliSeconds: 60_000,
maxFileSize: 25 * 1024 * 1024,
defaultVideoFileExtension: "webm" as const,
defaultVideoFileNameStyle: "ISO 8601" as const,
onSubmit: createIndexedDbFeedbackStore({ databaseName: "feedback" }),
};
</script>
<template>
<FeedClipVue :config="config" />
</template>Angular
import { Component } from "@angular/core";
import { FeedClipAngularComponent } from "@feedclip/sdk/angular";
import { createIndexedDbFeedbackStore } from "@feedclip/sdk";
import "@feedclip/sdk/style.css";
@Component({
selector: "app-feedback",
standalone: true,
imports: [FeedClipAngularComponent],
template: `<feedclip-widget [config]="config" />`,
})
export class FeedbackComponent {
readonly config = {
locale: "en-US" as const,
maxDurationMilliSeconds: 60_000,
maxFileSize: 25 * 1024 * 1024,
defaultVideoFileExtension: "webm" as const,
defaultVideoFileNameStyle: "ISO 8601" as const,
onSubmit: createIndexedDbFeedbackStore({ databaseName: "feedback" }),
};
}Submit to your backend
createFeedbackEndpointTransport sends multipart/form-data containing a
JSON payload, the recorded video, an optional screenshot, optional
screenshot visualNotes, and an optional Pro-generated thumbnail image file.
import { createFeedbackEndpointTransport } from "@feedclip/sdk";
const onSubmit = createFeedbackEndpointTransport({
endpoint: "/api/feedback",
credentials: "include",
});The endpoint returns a receipt:
interface FeedbackReceipt {
feedbackId: string;
status: "received" | "processing" | "completed" | "failed";
analysis?: FeedbackAnalysis;
attachments?: Array<{
kind: "video" | "screenshot" | "thumbnail";
fileName: string;
mediaType: string;
size: number;
url: string;
}>;
issue?: GeneratedIssue;
error?: "processing_failed";
}Cloud analysis can include analysis.issueMarkdown: a preformatted Markdown
issue body with summary, priority, reproduction steps, context, transcript, and
safe opt-in diagnostics. When users click the attached screenshot, FeedClip
adds lightweight visual notes with marker coordinates and optional labels, so
the generated issue can point engineers to the exact part of the UI. Every
additional click creates another marker (up to five), and markers are included
automatically when the user uploads the feedback; there is no separate save
step. Use it to
create GitHub, Linear, Jira, or internal tracker tickets without asking
engineers to rewrite the report by hand.
It can also include analysis.environment: a compact QA snapshot with the page,
browser, operating system, viewport, language, and timezone. FeedClip derives it
from the safe browser context already attached to the submission, so engineers
do not have to ask “what browser were you using?” after every report.
Cloud analysis also includes analysis.triage with impact, reproducibility,
and an optional suggested owner to help route feedback to the right team faster.
Use analysis.nextActions for a short checklist of engineering or QA follow-ups
that can go straight into your tracker or support workflow. Cloud receipts also
include private attachment links for the recorded video, screenshot, and
thumbnail when present. Those links use the Cloud API and still require project
authorization.
The built-in result UI renders safe http and https attachment URLs as
compact private links and groups them with the issue-ready report. When Cloud
returns analysis, the result UI exposes copy actions for the full Markdown
report, a compact bug report, and a QA checklist, so support or QA can paste the
right level of detail into GitHub, Linear, Jira, or an internal tracker. Copied
reports carry the FeedClip submission ID and processing status, labels,
environment, transcript, and safe private evidence links when those fields are
available. The QA format turns reproduction steps, expected/actual behavior,
next actions, environment, and evidence review into explicit checklist items.
If you
build your own receipt UI, treat attachments[].url as a private API link, not
as a public CDN URL: fetch it through your authenticated backend flow or with a
short-lived scoped token. Do not paste permanent project keys into browser code
or public issue trackers.
The built-in result UI appears as soon as onSubmit returns a receipt. For
asynchronous backends it shows the submission ID and received or processing
status while analysis is not yet part of the receipt; completed analysis and
issue-export actions are rendered when your onSubmit returns them.
Keep permanent project keys, storage credentials, AI credentials, and service account tokens on the server. Browser integrations should use an authenticated proxy or short-lived scoped tokens.
Configuration
| Property | Required | Description |
|---|:---:|---|
| locale | Yes | Widget language |
| maxDurationMilliSeconds | Yes | Recording duration limit |
| maxFileSize | Yes | Maximum submitted video size in bytes |
| defaultVideoFileExtension | Yes | webm, mp4, avi, mov, or mkv |
| defaultVideoFileNameStyle | Yes | UnixTimestamp, ISO 8601, or Custom |
| onSubmit | One handler | Receives the complete feedback submission |
| onUpload | One handler | Legacy file-only upload handler |
| getContext | No | Adds application-specific metadata |
| browserContext | No | Opts into query-string or referrer capture |
| diagnostics | No | Configures the default safe capture profile and optional console, failed-network, click, and navigation events |
| privacyNotice | No | Adds a privacy-notice link to the widget |
| license | No | Enables licensed Pro features |
| onLicenseError | No | Advanced troubleshooting callback for license verification errors |
Supported locales: en-US, ru-RU, es-ES, fr-FR, de-DE, it-IT,
pt-PT, zh-CN, ja-JP, and ko-KR.
Free, Pro, and Cloud
| Plan | Best for | Included | |---|---|---| | Free | Custom and self-hosted integrations | Screen recording, optional microphone or camera mode, preview frame capture, feedback metadata, screenshot visual notes, IndexedDB, and custom HTTP submissions | | Pro | Self-hosted products that need the complete client SDK | Interactive trim preview with apply/save/cancel controls, thumbnail file export, upload progress, storage helpers, and branding removal | | Cloud | Managed feedback processing | Hosted ingestion, private storage, transcription, structured AI analysis, and Pro SDK features while subscribed |
The Free SDK is MIT-licensed, including commercial use. Pro is a separate project-bound license for client-side features. Cloud is an optional hosted service and does not require exposing permanent API or AI keys in the browser.
See current product details and pricing at feedclip.dev.
Pro license setup
FeedClip Pro is unlocked by a signed project license. After purchasing Pro on feedclip.dev, the success page shows an SDK configuration block containing:
token— the signed license token for your project;publicKey— the public verification key used by the browser SDK;issuer,audience, andprojectId— values the SDK checks before enabling Pro features.
Pass that object as config.license:
import FeedClip from "@feedclip/sdk";
import "@feedclip/sdk/style.css";
const proLicense = {
token: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkZDTCJ9...",
publicKey: {
kty: "EC",
crv: "P-256",
x: "...",
y: "...",
},
issuer: "https://feedclip.dev",
audience: "@feedclip/sdk",
projectId: "your-project-id",
};
export function Feedback() {
return (
<FeedClip
config={{
locale: "en-US",
maxDurationMilliSeconds: 60_000,
maxFileSize: 100_000_000,
defaultVideoFileExtension: "webm",
defaultVideoFileNameStyle: "ISO 8601",
license: proLicense,
onSubmit: async (submission, onProgress) => {
// Upload to your backend or storage.
},
}}
/>
);
}The Pro license is safe to verify in the browser: it contains a signed grant and a public key, not a private signing key. Still keep the purchase success page private, bind each license to the intended project, and do not confuse a Pro SDK license with server-side storage credentials.
FeedClip Cloud includes Pro SDK features while the Cloud subscription is active.
For Cloud, keep the permanent X-Project-Key on your server, exchange it for a
short-lived SDK entitlement through /api/cloud/license, and send only that
temporary entitlement to the browser.
Examples
For the most reliable screen-capture experience, open the hosted demos in a top-level browser tab:
Each hosted demo includes a visible integration sample. The StackBlitz links below are useful for exploring source code, but embedded previews may block screen sharing.
Privacy and security
Recordings remain in the browser until the user submits them. By default, FeedClip removes URL credentials, fragments, query strings, and referrers from captured browser context.
Data collection contract
Nothing leaves the browser until the user submits. A normal submission contains:
| Data | Default | Notes |
| --- | --- | --- |
| Recording file | Yes | Screen or camera stream explicitly selected by the user |
| Feedback kind, description, ID, timestamp | Yes | User-entered report and SDK-generated metadata |
| Screenshot, thumbnail, visual markers | When created | Only files/markers visible in the review UI |
| Page URL and title | Yes | Credentials, fragments, and query string are removed by default |
| User agent, language, timezone | Yes | Used to reproduce the browser environment |
| Viewport width/height and device pixel ratio | Yes | CSS viewport, not physical display inventory |
| Safe diagnostic profile | Yes | Capture outcome/surface, dimensions/FPS, MIME support, permission state, runtime/API availability, recent capture outcomes |
| Referrer and URL query string | No | Separate explicit browserContext options |
| Product/app metadata | No | Explicit allowlist supplied by your getContext callback |
| Console/network/click/navigation events | No | Explicit diagnostics.enabled: true opt-in |
Built-in collection never calls enumerateDevices and does not place device
IDs or labels, IP addresses, cookies, local/session storage, credentials,
authorization headers, form/input values, clipboard contents, request/response
bodies or headers, arbitrary environment variables, a dependency inventory, or
other-tab content in the submission payload. Network infrastructure can process
connection metadata independently of the SDK payload.
Do not place passwords, access tokens, payment data, or other secrets in
getContext. Enable query-string or referrer capture only after reviewing the
data your application places there. Link the widget to your privacy notice when
required by your use case.
FeedClip attaches a privacy-safe diagnostic profile to each submission by default. It contains an allowlisted capture outcome, capture surface and dimensions, recorder MIME support, camera/microphone permission states, and whether the app is running in a secure top-level or embedded context. It never contains device IDs or labels, IP addresses, cookies, storage, tokens, request bodies, or URL query strings. Disable it only when required:
diagnostics: { safeProfile: false }Event diagnostics remain opt-in. When diagnostics.enabled is true, the same
customContext.feedclipDiagnostics snapshot can also include console
errors, failed HTTP requests, clicks, and navigation events. It does not capture
request/response bodies, headers, input values, URL query strings, URL fragments,
or credentials.
diagnostics: {
enabled: true,
maxEvents: 40,
}The browser cannot safely infer your application stack. Add only the fields
your team needs through getContext; they are exported as Product context:
getContext: () => ({
appVersion: APP_VERSION,
buildSha: BUILD_SHA,
environment: 'production',
framework: 'react',
frameworkVersion: React.version,
releaseChannel: 'stable',
})Do not pass access tokens, user/session objects, cookies, emails, or arbitrary environment variables. Keys that look like credentials are redacted again by Cloud exports, but they should never enter the submission in the first place.
Screen sharing, camera, and microphone capture require HTTPS or localhost, user
permission, getDisplayMedia, MediaRecorder, and a media format supported by
the browser.
Browsers can block screen capture inside embedded previews even when camera and microphone access is allowed. Open StackBlitz or another embedded preview in a top-level browser tab before starting screen recording. FeedClip detects this case after a failed request and shows a specific new-tab instruction instead of the generic permissions error.
Browser capture compatibility and troubleshooting
FeedClip uses the stream returned by the browser. The browser and operating system own the tab/window/screen picker and the pixels supplied by that stream; the SDK cannot recover pixels when the browser returns an empty or black video track.
The recording lifecycle is exercised in Playwright on Chromium, Firefox, and
WebKit for both monitor and window display surfaces. Those tests cover start,
pause, resume, first-click stop, browser-controlled sharing termination, full
frame preview, and review. Automated CI uses deterministic media streams because
headless runners cannot operate the macOS system picker or inspect a physical
monitor. Before shipping a browser-specific integration, also run a manual smoke
test with the actual operating-system picker.
If screen capture fails or the preview is black:
- Open the app in a top-level HTTPS tab, not an embedded preview.
- Confirm that the browser has macOS Screen & System Audio Recording permission, then fully restart the browser after changing it.
- Update the browser. On macOS 15, Firefox requires Firefox 132 or newer for Mozilla's newer screen-sharing API.
- If Firefox returns a black whole-display stream, leave Firefox full-screen mode and retry. If it persists, select a single application window or use current Safari/Chromium for whole-display capture.
- If a selected window disappears or the browser's sharing toolbar stops the stream, FeedClip finalizes the available recording and moves to review.
References: Mozilla's macOS 15 guidance,
Mozilla's macOS full-screen capture issue,
and MediaTrackSettings.displaySurface.
Package entrypoints
import FeedClip from "@feedclip/sdk";
import FeedClipVue from "@feedclip/sdk/vue";
import { FeedClipAngularComponent } from "@feedclip/sdk/angular";
import "@feedclip/sdk/style.css";The main entrypoint also exports typed feedback contracts, browser-context helpers, HTTP and IndexedDB transports, licensed upload helpers, and license verification utilities.
License
The Free SDK is distributed under the MIT License. Paid FeedClip features and services are covered by the accompanying commercial terms.
