Choose where to save feedback
Save feedback in your browser, share it through your own API, or follow the upcoming Artemis72 service.
Help me follow the Choose where to save feedback guide. Save feedback in your browser, share it through your own API, or follow the upcoming Artemis72 service. Review the current project and turn this guidance into concrete next steps.
Pick a setup
| Option | Choose this when | What you need |
|---|---|---|
| localStorage | You work alone or want to try it | No backend |
| API | Your team needs shared feedback | Your own backend |
| Artemis72 | You want a managed service | Coming soon |
Not sure which one to choose? Start with localStorage. Move to API later when the team needs to see the same feedback across browsers.
Use localStorage without a backend
Add this once near the root of your app. Feedback will be saved in the current browser.
<FivePixels project={{ id: "my-app" }} visibility={{ devOnly: true }}/>No API or Adapter is needed. You should see the Fivepixels button after the page loads.
localStorage only saves data in the current browser. Use API mode when teammates need to see the same feedback.
visibility.devOnly hides Fivepixels in production builds. Turn it off if your staging site is built in production mode.
Connect your API
API mode saves feedback through your backend so the team can share it. A FivePixelsAdapter is the small connection between Fivepixels and your API. Add the three basic handlers below and use sync="api".
Start with these three required functions to load, create, and update shared feedback.
import { useMemo } from "react";import { FivePixels, type FivePixelsAdapter } from "@fivepixels-js/react";
function createAdapter(): FivePixelsAdapter { const base = "/api/v1/fivepixels/projects/my-app"; const write = (method: "POST" | "PATCH", body: unknown) => ({ method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), });
return { markers: { list: ({ pathname }) => fetch(`${base}/feedbacks/markers?pathname=${encodeURIComponent(pathname)}`) .then((response) => response.json()), }, feedback: { create: (payload) => fetch(`${base}/feedbacks`, write("POST", payload)) .then((response) => response.json()), update: (id, payload) => fetch(`${base}/feedbacks/${id}`, write("PATCH", payload)) .then((response) => response.json()), }, };}
export function App() { const adapter = useMemo(() => createAdapter(), []);
return ( <FivePixels project={{ id: "my-app", env: "stage" }} sync="api" adapter={adapter} /> );}Create the Adapter once with useMemo or outside the component. Creating it again on every render can repeat requests.
More API examples
Choose how reviewers sign in
API sharing asks reviewers to sign in by default. Add auth.login to the Adapter above.
const adapterWithLogin: FivePixelsAdapter = { ...createAdapter(), auth: { login: async (credentials) => { const response = await fetch("/api/v1/fivepixels/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(credentials), }); if (!response.ok) throw new Error("Login failed"); return response.json(); }, },};
<FivePixels sync="api" adapter={adapterWithLogin} />Connect your team tools
Run your code when feedback changes, and send selected work to a GitHub Issue.
<FivePixels sync="api" adapter={adapter} onEvent={(event) => console.info("fivepixels", event)} github={{ enabled: true, modes: ["from-list"], onCreate: async (feedback) => { const response = await fetch("/api/github/issues", { method: "POST", body: JSON.stringify(feedback), }); const issue = await response.json(); return { issueNumber: issue.number, issueUrl: issue.html_url }; }, }}/>Share existing feedback with your team
Keep the same project id when you move from localStorage to API. Choose the environment and version together so everyone sees the expected feedback.
// Before: feedback stays in this browser.<FivePixels project={{ id: "my-app" }} sync="local" />
// After: new feedback uses your shared API.<FivePixels project={{ id: "my-app", env: "stage", version: "1.3.0" }} sync="api" adapter={adapter}/>Switching to API does not copy old browser feedback automatically. Move it with JSON Export/Import, or create it again in the shared API.
Artemis72 and what you build
Artemis72 is a planned hosted service for Fivepixels. It is still in preparation, so setup code is not available yet.
Required API functions
- markers.list({ pathname }) returns ReportFeedback[].
- feedback.create(payload) returns ReportFeedback with a server id.
- Implement feedback.update or cases.update.
| Function | What it does |
|---|---|
| markers.list | Required for markers on the current pathname |
| feedback.create | Required to persist new feedback |
| feedback.update or cases.update | At least one update path is required |
| auth · replies · members · session | Optional extensions based on your workflow |
For a shared API without login, set require={{ authLogin: false, reviewerKey: false }}. Authentication handlers are not used in this mode.
You build and run the API routes, database, sign-in, and permissions. Fivepixels connects to them through the frontend Adapter.