Custom Integrations
Integrate the widget with custom triggers, frameworks, and analytics.
Custom trigger buttons
By default, the SDK renders a floating button in the corner of your page. If you want full control over the trigger, set trigger: 'custom' during initialization. The built-in button will not be rendered.
Then attach your own trigger to any element:
You can open directly to any section depending on where in your app the user triggers the widget:
// From a "See what's new" link
changelogLink.addEventListener('click', () => window.uj.showWidget({ section: 'updates' }));
`
React hook
Encapsulate the SDK in a custom hook to make it easy to use throughout your React application.
| declare global { | |
|---|---|
| uj: { | |
| init: (id: string, opts?: Record<string, unknown>) => void; | |
| identify: (user: { id: string; email?: string } | null) => void; |
| showWidget: (opts?: { section?: string }) => void; | |
| hideWidget: () => void; | |
| }; | |
| } | |
| } |
export function useJotReview(projectId: string) { useEffect(() => { window.uj.init(projectId, { widget: true, trigger: 'custom' }); }, [projectId]);
| const identify = useCallback((user: { id: string; email?: string } | null) => { |
|---|---|
| }, []); |
return { identify, openFeedback, openRoadmap };
}
`
Usage in a component:
return (
<header>
<button onClick={openFeedback}>Give Feedback</button>
</header>
);
}
`
Vue component
Use a composable and a setup script for clean Vue 3 integration.
export function useJotReview(projectId: string) { onMounted(() => { window.uj.init(projectId, { widget: true, trigger: 'custom' }); });
| function identify(user: { id: string; email?: string } | null) { |
|---|---|
| } |
| function showWidget(section?: 'feedback' | 'roadmap' | 'updates') { |
|---|---|---|
| } |
return { identify, showWidget };
}
`
const auth = useAuthStore(); const { identify, showWidget } = useJotReview('proj_a1b2c3d4');
identify({ id: auth.user.id, email: auth.user.email }); </script>
<template>
<button @click="showWidget('feedback')" class="feedback-btn">
Share Feedback
</button>
</template>
`
Angular component
Create an Angular service to wrap the SDK and inject it where needed.
declare global { interface Window { uj: Record<string, (...args: unknown[]) => void>; } }
@Injectable({ providedIn: 'root' }) export class JotReviewService { init(projectId: string) { window.uj.init(projectId, { widget: true, trigger: 'custom' }); }
| identify(user: { id: string; email?: string } | null) { |
|---|---|
| } |
| showWidget(section?: 'feedback' | 'roadmap' | 'updates') { |
|---|---|---|
| } | ||
| } | ||
` |
@Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { constructor( private jr: JotReviewService, private auth: AuthService ) {}
openFeedback() {
this.jr.showWidget('feedback');
}
}
`
Analytics integration
Track widget interactions alongside your existing analytics by combining JotReview with tools like Segment, Mixpanel, or PostHog.
The recommended pattern is to fire your analytics event first, then open the widget:
// Open the widget
window.uj.showWidget({ section: 'feedback' });
});
`
For Segment users, you can combine identification:
// Mirror the identity to JotReview
window.uj.identify({
id: user.id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
});
`
Keyboard shortcut
Add a keyboard shortcut (e.g., Cmd+Shift+F) to open the widget without interrupting the user's flow.
You can also expose a Cmd+K command palette entry:
Conditional display by user segment
Show or hide the widget based on user properties, such as their plan, role, or account age.
function initForUser(user) { window.uj.identify({ id: user.id, email: user.email, });
| // Only show the widget to paying customers | |
|---|---|
| const isEligible = user.plan !== 'free' | new Date(user.createdAt) < thirtyDaysAgo; |
| window.uj.setWidgetEnabled(isEligible); | |
| } | |
` |
You can also show different sections based on the user's role: