Quick Start
Add the Loupe feedback widget to any web app in under a minute. Pick your framework
below — every snippet is copy-paste ready against
@loupeink/web-sdk.
Plain HTML
No build step. Drop the script tag before </body> and initialize with your project API key. The widget mounts itself.
<script src="https://cdn.jsdelivr.net/npm/@loupeink/web-sdk/dist/index.global.js"></script>
<script>
Loupe.init({ apiKey: "lp_your_project_api_key" });
</script> Now, get your project API key
The snippet above uses a placeholder. To go live, sign in at
app.loupe.ink,
open Organization Settings → API Keys, pick a
project and click Generate. Copy the
lp_… key — it is shown only once — and replace
lp_your_project_api_key.
React
Install the package, then call init once at your app root. Return destroy() from the effect so the widget cleans up correctly (including React StrictMode double-mounts).
npm install @loupeink/web-sdk import { useEffect } from "react";
import { init, destroy } from "@loupeink/web-sdk";
export function App() {
useEffect(() => {
init({ apiKey: import.meta.env.VITE_LOUPE_API_KEY });
return () => destroy();
}, []);
return <YourApp />;
} Next.js
The SDK runs in the browser, so it must live in a client component. App Router and Pages Router differ only in where you mount it.
npm install @loupeink/web-sdk "use client";
import { useEffect } from "react";
import { init, destroy } from "@loupeink/web-sdk";
export function Loupe() {
useEffect(() => {
init({ apiKey: process.env.NEXT_PUBLIC_LOUPE_API_KEY! });
return () => destroy();
}, []);
return null;
} import { Loupe } from "./loupe";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Loupe />
</body>
</html>
);
} import { useEffect } from "react";
import { init, destroy } from "@loupeink/web-sdk";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
init({ apiKey: process.env.NEXT_PUBLIC_LOUPE_API_KEY! });
return () => destroy();
}, []);
return <Component {...pageProps} />;
} Vue
Install the package and initialize from a root component's onMounted hook. Clean up with destroy() in onUnmounted.
npm install @loupeink/web-sdk <script setup lang="ts">
import { onMounted, onUnmounted } from "vue";
import { init, destroy } from "@loupeink/web-sdk";
onMounted(() => init({ apiKey: import.meta.env.VITE_LOUPE_API_KEY }));
onUnmounted(() => destroy());
</script> Need more options — themes, positioning, callbacks, self-hosted endpoints?
Full SDK reference on GitHub →