Fields
Validation
The relay rejects a project that breaks any of these, rather than storing it and failing later:
Origins are scanned on every public request, so the cap on their number and length is a
throughput concern as much as a correctness one.
Destinations
destination is one of three shapes, and its kind decides which fields apply.
owner and repo are required for GitHub, and only projectId for GitLab. host lets a
GitLab destination point at a self-managed instance instead of gitlab.com.
A project saved before destinations existed has no destination at all. Those still work: the
relay reads the flat teamId, linearProjectId and labelIds fields as an implicit Linear
destination, so nothing had to be migrated. If you set both, destination wins, except that a
Linear destination with no labelIds of its own falls back to the flat labelIds.
Tokens
The API token is held by the relay and never reaches the browser, which is the reason the relay exists at all. You can set one token for the whole relay, and optionally override it on a single destination. A per-destination token wins where it is set, so one relay can file into two repositories owned by different people without either token being able to reach the other’s. What the token has to be able to do, which is all the relay ever asks of it:
Nothing else is called, so a token scoped tightly to one repository or project is enough. Grant no
more than that.
Where the screenshot ends up, which differs by destination
This is worth knowing before you pick one, because it decides what retention means for you. Linear and GitLab receive the image itself: the relay uploads it to the tracker, and it lives there for as long as the issue does. Relay retention does not touch it. GitHub has no attachment API the relay can use this way, so the relay stores the screenshot itself and puts a signed link to it in the issue body. The image is served from your own relay, which means retention applies to it: once the window passes, the issue keeps its text and its link stops resolving. If you self-host and file to GitHub, that is an argument for the unlimited retention a Pro licence gives you, or for keeping the screenshots yourself.Content Security Policy
If your site sends aContent-Security-Policy header, the widget needs two directives to work and
a third to take screenshots. Nothing else.
The relay’s origin is the host in your embed
src: https://feedback.example.com for a self-host,
https://relay.burnsidesteps.com for the hosted service.
img-src data: is not optional if you want screenshots. The capture renders your page into a
data URI and loads it back as an image, so a policy without it fails the capture outright rather
than degrading: the report still sends, with no screenshot attached. The browser console says so at
the moment it happens, naming this directive.
You do not need style-src 'unsafe-inline'. The widget’s own CSS is applied as a constructed
stylesheet, which is not an inline style as far as the policy is concerned, so a strict style-src
leaves the widget looking exactly as it should. On a browser old enough to lack constructed
stylesheets the widget falls back to an inline <style>, which a strict style-src will block; it
still works, it just renders unstyled.
You do not need font-src either. The capture is told not to fetch remote fonts.
A policy that covers all three looks like this:
default-src rather than naming each directive, the same values apply to it.
Plan limits
Only the hosted service enforces this. On a relay you run yourself there is no sweep at all:
the Cloudflare Worker template ships no cron, and the Node self-host keeps them until you remove
them unless you set
SHOT_RETENTION_DAYS, which defaults to keeping them indefinitely. The figure
above describes what hosted applies to a Free account, not a ceiling your own relay imposes on you.
On hosted, a nightly cron applies the window, so a screenshot outlives it by about a day. That
sweep resumes across runs rather than restarting, so as the number of accounts grows a given
account is reached every few nights rather than every night.
Retention covers screenshots the relay is storing, which in practice means GitHub destinations: see
above. The issue itself is never touched. It lives in your tracker, and nothing here can remove it.
Rate limits
These are per relay, and identical across the Cloudflare Worker and the Node self-host.
The per-project and per-IP submission limits work together. The per-project ceiling protects your
tracker from a flood, and the per-IP limit stops one visitor consuming that whole allowance and
locking everyone else out.