Documentation JavaScript SDK

JavaScript SDK v1.0.1

TypeScript-first SDK for integrating FeedbackKit into web applications. Zero dependencies, tree-shakeable, works in Node.js and browsers.

Node.js 18+ Browsers npm GitHub
$ npm install feedbackkit-js

Installation

Install the FeedbackKit JavaScript SDK using your preferred package manager.

terminal
# Using npm
npm install feedbackkit-js

# Using yarn
yarn add feedbackkit-js

The SDK is written in TypeScript and ships with full type definitions. No additional @types packages are needed.

Quick Start

Initialize the client with your project API key and start collecting feedback in minutes.

app.ts
import { FeedbackKit, FeedbackCategory } from 'feedbackkit-js';

// Initialize the client
const client = new FeedbackKit({
    apiKey: 'your-api-key',
    userId: 'user_12345'
});

// List feedback
const feedbacks = await client.feedback.list();

// Submit feedback
const newFeedback = await client.feedback.create({
    title: 'Add dark mode',
    description: 'Would love a dark mode option',
    category: FeedbackCategory.FeatureRequest,
    userId: 'user_12345'
});

Configuration

The FeedbackKitConfig interface accepts the following options when creating a new client instance.

Option Type Required Default Description
apiKey string Yes Your project API key
userId string No Default user identifier
timeout number No 30000 Request timeout in ms

Client Methods

config.ts
const client = new FeedbackKit({
    apiKey: 'sf_your_api_key',
    userId: 'user_12345',
    timeout: 10000
});

// Update user ID after login
client.setUserId('user_12345');

// Get current user ID
const userId = client.getUserId();

// Clear user ID on logout
client.setUserId(undefined);

API Reference

Feedback API

client.feedback

Method Description
list(options?: ListFeedbackOptions): Promise<Feedback[]> List all feedback with optional filters
get(feedbackId: string): Promise<Feedback> Get single feedback by ID
create(request: CreateFeedbackRequest): Promise<Feedback> Submit new feedback
feedback-api.ts
// Get all feedback
const all = await client.feedback.list();

// Filter by status
const pending = await client.feedback.list({
    status: FeedbackStatus.Pending
});

// Filter by category
const bugs = await client.feedback.list({
    category: FeedbackCategory.BugReport
});

// Include merged items
const withMerged = await client.feedback.list({
    includeMerged: true
});

// Get single feedback
const feedback = await client.feedback.get('feedback-uuid');
console.log(feedback.title, feedback.voteCount);

// Submit new feedback
const created = await client.feedback.create({
    title: 'Add dark mode',
    description: 'Please add a dark mode option for night time use.',
    category: FeedbackCategory.FeatureRequest,
    userId: 'user_12345',
    userEmail: 'user@example.com'  // optional
});

Votes API

client.votes

Method Description
vote(feedbackId: string, request: VoteRequest): Promise<VoteResponse> Vote for feedback
unvote(feedbackId: string, request: UnvoteRequest): Promise<VoteResponse> Remove vote
votes-api.ts
// Simple vote
const result = await client.votes.vote('feedback-id', {
    userId: 'user_12345'
});

// Vote with email notification opt-in
const result = await client.votes.vote('feedback-id', {
    userId: 'user_12345',
    email: 'user@example.com',
    notifyStatusChange: true
});

// Remove a vote
const removed = await client.votes.unvote('feedback-id', {
    userId: 'user_12345'
});
console.log(removed.hasVoted); // false

Comments API

client.comments

Method Description
list(feedbackId: string): Promise<Comment[]> List comments for feedback
create(feedbackId: string, request: CreateCommentRequest): Promise<Comment> Add comment
comments-api.ts
// List all comments
const comments = await client.comments.list('feedback-id');
for (const comment of comments) {
    console.log(`${comment.userId}: ${comment.content}`);
    if (comment.isAdmin) console.log('(Admin response)');
}

// Add a user comment
const comment = await client.comments.create('feedback-id', {
    content: 'This would be really helpful!',
    userId: 'user_12345'
});

// Add an admin response
const adminComment = await client.comments.create('feedback-id', {
    content: 'Thanks for the feedback! We are working on this.',
    userId: 'admin_user',
    isAdmin: true
});

Users API

client.users

Method Description
register(request: RegisterUserRequest): Promise<SDKUser> Register SDK user
users-api.ts
// Register a free user
const user = await client.users.register({
    userId: 'user_12345'
});

// Register a paying user with MRR
const payingUser = await client.users.register({
    userId: 'user_67890',
    mrr: 9.99
});

// Update MRR when subscription changes
const upgraded = await client.users.register({
    userId: 'user_67890',
    mrr: 19.99
});

Events API

client.events

Method Description
track(request: TrackEventRequest): Promise<TrackedEvent> Track analytics event
events-api.ts
import { SDKEvents } from 'feedbackkit-js';

// Track a simple event
await client.events.track({
    eventName: 'feedback_list',
    userId: 'user_12345'
});

// Track with properties
await client.events.track({
    eventName: 'feedback_list',
    userId: 'user_12345',
    properties: {
        filter: 'feature_request',
        sort: 'votes'
    }
});

// Using predefined SDK events
await client.events.track({
    eventName: SDKEvents.FeedbackList,
    userId: 'user_12345'
});

// Track a custom event
await client.events.track({
    eventName: 'onboarding_completed',
    userId: 'user_12345',
    properties: {
        step_count: 5,
        duration_seconds: 120
    }
});

Predefined SDK Events: SDKEvents.FeedbackList, SDKEvents.FeedbackDetail, SDKEvents.SubmitFeedback

Models & Types

Feedback

Field Type Description
id string Unique identifier
title string Feedback title
description string Detailed description
status FeedbackStatus Current status
category FeedbackCategory Feedback category
userId string ID of the user who submitted
userEmail string? Email of the submitter (if provided)
voteCount number Total number of votes
hasVoted boolean Whether the current user has voted
commentCount number Total number of comments
totalMrr number? Combined MRR of all voters
createdAt string When the feedback was created
updatedAt string When the feedback was last updated
rejectionReason string? Explanation for rejection
mergedIntoId string? ID of feedback this was merged into
mergedAt string? When this feedback was merged
mergedFeedbackIds string[]? IDs of feedback items merged into this one

Enums

FeedbackStatus

Value Raw
Pending "pending"
Approved "approved"
InProgress "in_progress"
TestFlight "testflight"
Completed "completed"
Rejected "rejected"

FeedbackCategory

Value Raw
FeatureRequest "feature_request"
BugReport "bug_report"
Improvement "improvement"
Other "other"

Comment

Field Type Description
id string Unique identifier
content string Comment text
userId string ID of the commenting user
isAdmin boolean Whether this is an admin comment
createdAt string When the comment was created

VoteResponse

Field Type Description
feedbackId string ID of the feedback item
voteCount number Updated vote count
hasVoted boolean Whether the user has voted after this action

Request Types

CreateFeedbackRequest

Field Type Required Description
title string Yes Brief title (1-200 chars)
description string Yes Detailed description (1-5000 chars)
category FeedbackCategory Yes Feedback category
userId string Yes Unique identifier of the submitting user
userEmail string No Optional email for status update notifications

VoteRequest

Field Type Required Description
userId string Yes Unique identifier of the voting user
email string No Email for status change notifications
notifyStatusChange boolean No Opt-in to receive email notifications

UnvoteRequest

Field Type Required Description
userId string Yes Unique identifier of the user removing their vote

CreateCommentRequest

Field Type Required Description
content string Yes Comment text (1-2000 chars)
userId string Yes Unique identifier of the commenting user
isAdmin boolean No Whether this comment is from an admin/developer

ListFeedbackOptions

Field Type Required Description
status FeedbackStatus No Filter by status
category FeedbackCategory No Filter by category
includeMerged boolean No Include merged feedback items

RegisterUserRequest

Field Type Required Description
userId string Yes Unique identifier of the SDK user
mrr number No Monthly Recurring Revenue

TrackEventRequest

Field Type Required Description
eventName string Yes Name of the event to track
userId string Yes Unique identifier of the user
properties Record<string, unknown> No Optional key-value properties for the event

Error Handling

The SDK provides a typed error hierarchy so you can handle specific error cases. All errors extend the base FeedbackKitError class.

Error Class Status Code Code Description
FeedbackKitError Base error class (statusCode, code, message)
AuthenticationError 401 UNAUTHORIZED Invalid or missing API key
PaymentRequiredError 402 PAYMENT_REQUIRED Subscription limit exceeded
ForbiddenError 403 FORBIDDEN Action not allowed (archived project, voting blocked)
NotFoundError 404 NOT_FOUND Resource not found
ConflictError 409 CONFLICT Duplicate action (e.g., already voted)
ValidationError 400 BAD_REQUEST Request validation failed
NetworkError 0 NETWORK_ERROR Network connectivity issue
error-handling.ts
import {
    FeedbackKit,
    FeedbackKitError,
    AuthenticationError,
    PaymentRequiredError,
    NotFoundError,
    ConflictError,
    NetworkError
} from 'feedbackkit-js';

try {
    const feedback = await client.feedback.create({
        title: 'My feedback',
        description: 'Details here',
        category: FeedbackCategory.FeatureRequest,
        userId: 'user_12345'
    });
} catch (error) {
    if (error instanceof AuthenticationError) {
        console.error('Invalid API key');
    } else if (error instanceof PaymentRequiredError) {
        console.error('Upgrade your plan to continue');
    } else if (error instanceof NotFoundError) {
        console.error('Resource not found');
    } else if (error instanceof ConflictError) {
        console.error('Action already performed');
    } else if (error instanceof NetworkError) {
        console.error('Check your internet connection');
    } else if (error instanceof FeedbackKitError) {
        // Catch-all for other API errors
        console.error(`Error ${error.statusCode}: ${error.message}`);
    }
}