Desde

Viewer guide

Reviewing a prototype

Open a deployed prototype, pin comments to elements, reply, mention teammates, and resolve threads. Also covers what anchors a comment and where notifications stop.

The review page is where the Viewer earns its keep. It puts a deployed prototype in an iframe, lets anyone reading it click an element and leave a comment pinned to that element, and keeps every thread in a rail beside it.

Open it at /review/{slug}. From the dashboard, use the Review button on a project.

Note /review/{slug} returns not-found until the project has an active deployment. A project you just created is not reviewable yet. See builds.

The screen#

Three parts:

  • The header: back to Projects, the project name, then Members, Repo, your account chip, Show resolved, and Comment.
  • The prototype: a full-height iframe of /p/{slug}/. You navigate it exactly as you would the real app: click links, fill forms, move between routes.
  • The comment rail: a narrow column on the right listing every visible comment by number and first line.

There is no element inspector here. Reading a component's props, styles and source location is the Editor's job, not the Viewer's.

Leaving a comment#

  1. Click Comment in the header. The cursor inside the prototype becomes a crosshair.
  2. Click the element you want to talk about. A pin drops there and a compose card opens next to it.
  3. Type, and press the send arrow, or Cmd/Ctrl + Enter.

What gets saved is the element's selector and the page you were on (its path plus hash), not a pixel coordinate on a screenshot. That is the whole point of the design: if the layout shifts, the button moves, or the build changes its spacing, the comment travels with the element rather than pointing at empty space.

When an element genuinely disappears (you deleted it, or renamed the thing the selector matched), the comment does not vanish. It gets a moved badge in the rail, so the thread is still readable and still resolvable, it just no longer has a pin to sit on.

Pins render inside the prototype, so they scroll with the content. The thread card renders in the shell around it and is positioned by translating the pin's in-iframe rectangle into page coordinates.

Who you are#

If you are signed in with GitHub, comments are attributed to your account and you are never asked anything.

If you are not (the common case for a public-link project shared by URL), the first comment or reply opens a small "Who's commenting?" form asking for a name and, optionally, an email. That identity is stored in your browser's local storage and reused. It is self-declared and unverified by design.

A reply you typed before giving a name is not lost. It is held while the identity form is shown and sent automatically once you save.

Authorship is decided by the server, not by the browser. A signed-in caller's comment is attributed to their real account regardless of what the request says, and an anonymous caller cannot claim a verified account identity.

Replies and resolving#

Click a pin, or a row in the rail, to open the thread. From there you can reply, resolve, or delete the comment.

Resolving does not delete anything. Resolved comments drop out of the rail and their pins disappear from the prototype until you turn on Show resolved in the header, which brings both back: resolved rows dimmed and check-marked. Resolving is a toggle, so anything resolved can be reopened.

Limits: a comment or reply body is capped at 10,000 characters, a thread at 500 replies, and a single comment at 20 mentions.

Everyone looking at the same project sees changes live. The page holds a server-sent-events stream open and refetches whenever anything on the project changes.

Mentions#

Type @ in a new comment to open a picker over the project's participants: everyone who has commented on this project, plus anyone invited by email from this same picker. Filtering matches on name or email.

If the person you want is not there yet, use the Invite by email… field in the picker's footer. They are added to the directory and inserted as a mention in one motion.

Note The reply box has no picker. Replies use a plain textarea, so typing @Jane there is just text. It resolves to nobody and emails nobody. To reach someone from an existing thread, mention them in a new comment.

A mention is stored as @[Name](participantId): an opaque id, never an email. The server re-checks every id against the project's real participant list and silently drops anything that does not resolve, so a hand-typed @[Bob](bob@example.com) cannot smuggle an address into the mention list. Your comment still posts.

Note Participants are not members. A participant is an entry in this project's mention directory; a member is someone on the access list of an invited project. Adding a participant grants no access. See members and tokens.

Notification emails#

If the server has SMTP configured (VIEWER_SMTP_HOST and friends), each mentioned participant with a deliverable email gets a message: who mentioned them, the comment text, and a View comment link straight to /review/{slug}. Mentioning yourself sends nothing.

Set VIEWER_UNSUBSCRIBE_SECRET as well and every email carries a signed one-click unsubscribe link, both in the footer and as a List-Unsubscribe header. Unsubscribing is per project. With that variable unset, mention emails still send. They just have no unsubscribe link.

Without SMTP configured, mentions still work: they highlight in the comment and the recipient sees them when they open the page. Nothing is emailed.

Warning Editing a comment to add a mention sends no notification. The notification is only enqueued when a comment or reply is first posted. PATCH /api/v1/projects/{id}/comments/{commentId} (there is no edit control in the review UI, so this is the API lane) will store the new mention and render it everywhere else, but nobody is emailed. Post a new comment when you actually need to reach someone.

Who can comment#

Commenting is not an authenticated action. Anyone who can read the project can also comment on it, reply, edit and delete, including an anonymous visitor on a public-link project. That is the anonymous-review product, not an oversight. An Admin can still turn anonymous commenting off for the whole instance with the allowAnonymousComments setting (on by default, next to allowPublicLinks in Settings); anonymous visitors then get "Sign in to comment on this project" instead.

One practical limit: the live-update stream allows at most 20 open connections per client. Past that, a new stream is refused with a 429 until one closes. Normal multi-tab reviewing stays well under it.

The one restriction is on scoped credentials: a request carrying a read-scoped dsv_ token is refused with 403 on any write. A caller that genuinely wants anonymous-level access can simply not send the header.

One timing detail worth knowing: the live-update stream checks visibility when it connects, not continuously. Removing someone's membership takes effect the next time their page reconnects, not instantly.

Next#