@landedso/sdk
v0.3.2
Published
Headless client and React hooks for the Landed feedback API
Readme
@landedso/sdk
Headless TypeScript client and React hooks for integrating Landed feedback collection into your own UI.
Install
npm install @landedso/sdkHeadless client
import { LandedClient } from "@landedso/sdk";
const landed = LandedClient.create({
publishableKey: "wk_pub_...",
});
await landed.identify({
id: "user_123",
email: "[email protected]",
organization: {
externalId: "org_123",
name: "Acme",
domain: "acme.example",
payment: { businessName: "Acme", billingEmail: "[email protected]" },
},
});
const config = await landed.getConfig();
const inbox = await landed.listConversations();
if (inbox.openBehavior === "thread" && inbox.selectedConversationId) {
const thread = await landed.getConversation(inbox.selectedConversationId);
console.log(thread.conversation.messages.length);
}
const upload = await landed.upload(file);
await landed.submit({
text: "Love the new dashboard",
storageRefIds: [upload.storageRefId],
context: {
pageUrl: window.location.href,
},
});
// Verify Local / Production Setup from the current browser origin.
// Do not set or spoof Origin — browsers send it automatically.
await landed.ping();
const releases = await landed.listChangelogReleases({
limit: 5,
sort: "publishedAt",
order: "desc",
});
const release = await landed.getChangelogRelease(releases.data[0].id);React hooks
import {
LandedProvider,
useLandedConfig,
useIdentify,
useSubmitFeedback,
} from "@landedso/sdk/react";
export function FeedbackForm() {
const { config, isLoading } = useLandedConfig();
const identify = useIdentify();
const { submit, isSubmitting } = useSubmitFeedback();
if (isLoading || !config) return null;
return (
<form
onSubmit={async (event) => {
event.preventDefault();
await submit({ text: "Great product!" });
}}
>
<button type="submit" disabled={isSubmitting}>
{config.widget.copy.submitLabel}
</button>
</form>
);
}
export function App() {
return (
<LandedProvider publishableKey="wk_pub_...">
<FeedbackForm />
</LandedProvider>
);
}Submission shape
submit() accepts the fields required to create a Conversation Message:
text— feedback bodystorageRefIds— attachment IDs returned fromupload()context— optional page URL, user agent, or custom metadatanewUser— guest email/name whenidentify()was not calledconversationId— continue a specific Conversation when the End User has severalcreateConversation— start a new Conversation even when one already exists; omitconversationIdwhen using thisidempotencyKey— replay the same submission without creating a second Message
listConversations() returns the End User's non-deleted Widget Conversations and an openBehavior of create (none), thread (one), or list (several). Anonymous Visitors see only Conversations for the current visitor token. getConversation(id) returns customer-visible Messages for a Conversation the current identity owns.
Call identify() with a host product id and email to attach a signed-in user. Anonymous submissions require the workspace widget config to allow anonymous feedback. Call logout() to rotate the visitor token and leave prior Conversations attached.
