Docs
Next.js
The widget in one line, your own changelog with hooks, and customers who are known when they vote.
Create a project
Sign in, create a project, and note its slug. Your public pages are live at
https://shipnoted.com/p/your-slugalready.Add the widget
The quickest way is the CLI, which edits
app/layout.tsxfor you and shows what it changed:npx shipnoted initOr add it yourself, once, to the root layout:
app/layout.tsx
import Script from "next/script" export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> {children} <Script src="https://shipnoted.com/widget.js" data-project="your-slug" strategy="afterInteractive" /> </body> </html> ) }A bell button appears in the corner. Press it: you have a changelog, an idea box and voting.
Your own changelog with hooks#
If you would rather draw the changelog yourself, use the headless hooks. Fetch the first page on the server so there is no loading state, and let the hook take over from there.
npm i @shipnoted/reactimport { createPublicClient } from "@shipnoted/react/core"
import { Changelog } from "./changelog"
export default async function Page() {
const client = createPublicClient({ project: "your-slug", baseUrl: "https://shipnoted.com" })
const { releases } = await client.releases({ limit: 10 })
return <Changelog initialData={releases} />
}See React hooks for useFeedback (list, vote, post an idea) and the rest.
Verified customers#
Tell Shipnoted who is signed in and their votes become one verified person on every device, carry their plan and revenue, and the person is emailed when their request ships. You sign a short token on your server with the identify secret (Install & connect).
app/api/shipnoted-token/route.ts
import { SignJWT } from "jose"
import { auth } from "@/auth" // your own auth
export async function GET() {
const user = await auth()
if (!user) return Response.json({ token: null })
const token = await new SignJWT({
email: user.email, name: user.name,
plan: user.plan, mrr: user.mrr, company: user.company,
attrs: { beta: user.beta },
})
.setProtectedHeader({ alg: "HS256" })
.setSubject(user.id)
.setExpirationTime("1h")
.sign(new TextEncoder().encode(process.env.SHIPNOTED_IDENTIFY_SECRET!))
return Response.json({ token })
}in a client component
const { token } = await (await fetch("/api/shipnoted-token")).json()
if (token) window.Shipnoted?.identify(token) // the widget
// or <ShipnotedProvider project="your-slug" userToken={token}> // the hooksShip the first release#
Write one in the dashboard, or from the terminal:
export SHIPNOTED_API_KEY=snk_… # Install & connect → API keys
npx shipnoted release create --title "Hello" --body "- Our first release" --publishThen have it happen on every tag with the GitHub Action.