snagset

Click-to-comment review for a live website. One script tag, or one import. React, Vue, Next.js, Vite, Astro.
4,053
Install
npm install snagset
Latest Version:0.1.36
Vue:3
License:MIT
Last Updated:Oct 21, 2026
Links: GitHub  ·  npm
Maintainer: eeeurico

snagset

Click-to-comment review for a live website. Your client clicks the thing that's wrong and types; you get the pin, the screenshot, the console and the route.

One import, or one script tag. Both do exactly the same thing.

npm install snagset

# later — a caret on a 0.x version stays inside that minor, so this is how you move up
npm install snagset@latest

Vanilla

import snagset from "snagset";

snagset.init({ host: "https://review.example.com", site: "prj_…" });

That is the whole API. snagset.destroy() takes it back off; snagset.tag({…}) gives you the tag as data if you would rather render it yourself.

React

import Snagset from "snagset/react";

<Snagset host="https://review.example.com" site="prj_…" />

Vue

<script setup>
import Snagset from "snagset/vue";
</script>

<template>
  <Snagset host="https://review.example.com" site="prj_…" />
</template>

Next.js

// app/layout.tsx
import { Snagset } from "snagset/next";

<body>
  {children}
  <Snagset host="https://review.example.com" site="prj_…" />
</body>

No "use client" — it renders the script tag on the server, so it costs zero client JavaScript. Leave the props off and it reads NEXT_PUBLIC_SNAGSET_HOST and NEXT_PUBLIC_SNAGSET_SITE, so each environment configures itself from .env. Works in the Pages Router too.

Vite — and Nuxt, SvelteKit, SolidStart, anything on Vite

// vite.config.ts
import { snagset } from "snagset/vite";

export default defineConfig({
  plugins: [snagset({ host: "https://review.example.com", site: "prj_…" })],
});

One line in a file the project already has; the tag is injected before </body>. In Nuxt, put it under vite: { plugins: […] } in nuxt.config. Want it only in dev? Use Vite's own idiom: mode === "development" ? snagset({…}) : undefined. Shipping the tag to production is safe either way — who sees the toolbar is a dashboard setting, checked by the tag on load, not something baked into your build.

Astro, Rails — anything that renders a layout

---
import { snagsetTag } from "snagset/astro";
const tag = snagsetTag({ host: "https://review.example.com", site: "prj_…" });
---
<script src={tag.src} {...tag.attrs} defer is:inline></script>

is:inline matters — without it Astro bundles the script and rewrites the src, and the widget finds its chunks relative to its own src.

Or no npm at all

<script src="https://review.example.com/snag.js" data-snag-site="prj_…" defer></script>

That is what this package writes for you. There is no feature behind the npm install — if a script tag suits your stack better, use it. It works on WordPress, Webflow, Shopify and Rails, where a React-only tool cannot go.

Options

Every data-snag-* attribute, as a camelCase key. host and site are the only required ones.

Option What it does
host Your Snagset instance
site The project uid, from the dashboard
env Which environment this build is — staging, production
theme light, dark, or leave it to follow the page
lang UI language
position Where the toolbar sits
hotkey Default is alt+c
branch, build Stamped onto every comment, for "which deploy was this?"

What this package is

A loader. It writes the script tag and nothing else — the widget itself is served by your Snagset instance, at your instance's version.

That is deliberate. The widget is a lazy chunk graph: about 10 kB loads on every page and the remaining ~245 kB arrives only if somebody opens the toolbar. Bundling it here would put all of it into your bundle, and pin a widget version in your package.json that can drift from the server it talks to.

It also means the bytes come from your own origin, so your CSP is one script-src 'self' entry and there is no third party to justify to anyone.

Requirements

A Snagset instance. It self-hosts on Node and Postgres — snagset/snagset, or npx create-snagset to scaffold one.


Early release. This is a 0.0.x line: the tag it writes is stable and tested, but expect the odd rough edge, and pin the version if you need stability. Issues and notes are welcome at snagset/snagset.

MIT.

Related Packages

@ojolowoblue/lamba

A universal dev tool for viewing, overriding, and swapping environment variables...

1,701 1
@fasterfixes/vue

Vue plugin for the FasterFixes feedback widget. Reviewers annotate elements and...

336 41
@theonexai/chartsconnect-chat-widget

chartsconnect AI Chat Widget - Universal JavaScript library supporting React, Ne...

5,985
@blockspark/chat-widget

chartsconnect AI Chat Widget - Universal JavaScript library supporting React, Ne...

4,092
@draftbase/renderer

Framework-agnostic MDX renderer for Draftbase content (React, Next.js RSC, React...

3,429 0

Version History

Version Released License
0.1.36 MIT
0.1.35 MIT
0.1.34 MIT
0.1.33 MIT
0.1.32 MIT