Guide
Report page & widget
The people who use your app can tell you about it from a browser — the same three things the in-app form asks, pictures, a way to reply — on a page Pharen hosts under your app's name. Link to it, or add one tag to your own site and open it in a frame from your own Support button. A report lands beside your crash issues, with a number.
What you get
- A hosted page. Your app's name at the top; Report a problem, Suggest an improvement or Ask a question; a message; up to five pictures; an optional email for a reply. No script, no account, nothing to install.
- A widget. One
<script>tag that opens the same page in a modal frame on your site when your own control asks it to. There is no second form: the frame is the page, so everything below about the page is true inside the frame too. - A report, numbered. Each report becomes an issue — #143 — in the same list as your crashes, assignable and resolvable, with the pictures and the reply address on it. The reporter is told the number.
1. Mint the key and the page
The page belongs to a publishable key — a fourth kind of credential, made to be public. Its value starts with phk_…; it can submit reports for one app in one environment, and nothing else: it reads nothing and mints nothing. Mint it with a page:
pharen ingest-keys create --publishable --label "support page" --environment production --pageThe answer carries the page's URL. The page is reached by an opaque handle, not by the key — the URL reveals nothing about the credential — and the URL stays the same through a key rotation and stops answering when the key is revoked. A key minted without --page gets one later with pharen ingest-keys edit <key-id> --publishable --page, and asking twice answers the same URL: a link you have handed out never changes.
2. Link to the page
That is the whole integration for a link: put the URL in your app's Help screen, an email footer, a support article. A person opens it, sends, and sees Thanks — your report reached us at [your app]. Your report is #143.
3. Or open it on your own site
First, name your site. The page is embedded only from the origins its key names, and a key that names none embeds nowhere:
pharen ingest-keys edit <key-id> --publishable --origins https://www.example.comThen add the tag the mint printed (the console's keys page shows it too, beside the page URL, with a copy button), and have your own Support or Contact control call PharenReport.open():
<!-- Opens your report page in a frame. Your own control calls PharenReport.open();
a filed report fires a "pharen:report-sent" event on document with the report number. -->
<script src="https://api.pharen.ai/report/YOUR-PAGE-HANDLE/widget.js" async></script>
<button type="button" onclick="PharenReport.open()">Report a problem</button>
<script>
document.addEventListener('pharen:report-sent', (event) => {
console.log('report filed, number', event.detail.number);
});
</script>What the widget does, and does not do:
PharenReport.open()mounts a modal frame of the page over your site;PharenReport.close()closes it. Your control is the entry point — the widget draws no button of its own unless you ask for one.- The dialog is labelled, Escape closes it, focus stays inside it and returns to your control on close, it fills the screen on a phone, and it honours a reduced-motion preference. An Open in a new tab control beside Close is always there.
- When a report is filed, the frame shows the confirmation and your page receives a
pharen:report-sentevent ondocumentwith the number inevent.detail.number. Nothing else the frame sends is yours to handle. - Want a floating button instead of your own? Add
data-launcher="corner"to the tag — a real, labelled button in the corner — anddata-label="Send a report"to word it. - The script is small, has no dependencies, and is served with an hour of cache; it puts one name on
windowand nothing else, and it loads nothing into your page from anywhere — no font, no stylesheet; its own few rules go in through the stylesheet API, so a strict Content-Security-Policy on your site has nothing to allow.
4. Brand the page
The page renders in a neutral look by default — system fonts, the reader's own light or dark. To make it read as part of your app, give the key a brand:
pharen ingest-keys edit <key-id> --publishable \
--accent '#7a2e0e,#f0a070' \
--surface '#fbf7f0,#1b1512' --text '#2a1a12,#f4ebe2' \
--radius small --font SpectralFive levers, and nothing else: the accent (the button and the focus ring), the background and its text (a pair — one without the other is refused), the corner radius (none, small, medium, large), and the font — system, or a Google Fonts family name as the catalogue spells it, loaded from Google Fonts and from nowhere else. Every colour takes a value per scheme, light,dark, or one value for both. The console's keys page has the same controls as a form.
A brand can change how the page looks and never whether it can be read: text must clear 4.5:1 on its background and the accent 3:1, in both schemes, or the record is refused whole and the answer names the field — brand.text.light: reads 2.85:1 on the light surface; 4.50:1 is the floor for text. The record is saved whole, so a flag left out is a field cleared; --no-brand returns the page to neutral. Inside the widget, the frame's own chrome — the card and its two controls — takes the page's colours and font too, so the whole thing reads as one surface. Your site's stylesheet may restyle the chrome as well: the classes are .pharen-report-dialog, .pharen-report-bar, .pharen-report-frame and .pharen-report-launcher, and the widget's own rules yield to yours at equal specificity.
What the reporter sees, and what you get
- Beside the Send button, one plain sentence in your app's own voice says where the report goes and who reads it — Your report comes to us. We read it with the tools we use for support. — and, when an email is asked for, that it is used only to reach the person about this report. Pressing Send is the consent for that report.
- Every picture is decoded and re-encoded on the server before it is stored, so no location, camera or time details survive. Up to five pictures of 800 KB each; a message of up to 4,000 characters.
- The reply address never touches the event stream. It sits on the issue, visible to developers and owners in the console, and is withheld from every agent surface. Whether the field is optional, required or absent is a remote-configuration switch per app.
- The page carries a small Powered by Pharen mark in its footer, linked to this site. It is the one place the platform appears; the page speaks for your team.
Limits, and pulling the key
Each publishable key has its own rate limit — a share of your tenant's, raised per key with --rate-limit-per-second — and every address is limited on top of that, so a copied key or a busy afternoon spends at most its own budget. The origin list is abuse prevention, not a wall: a request that is not from a browser can claim any origin, so the limit and the revoke are what bound a copy.
Every report remembers how it came in: which key admitted it, the platform the submitter named, and the browser origin it came from. On the console a report that rode in on a publishable key wears a Web key chip naming the key's label, on the row and beside its issue; click it and the list is everything that came in on that key. Both lists filter by the kind of key — what the platform saw, which a script holding a copied key cannot talk its way out of — and by the one key, each report page says its source, and the keys page counts the reports of the last seven days beside every web key, on the instant each arrived. A number that jumps is the first sign of a copied key, one row above rotate and revoke.
pharen ingest-keys list --publishable # ids, labels, origins, reports this week, page URLs
pharen ingest-keys rotate <key-id> --publishable # same page, new key; the old one stops at once
pharen ingest-keys revoke <key-id> --publishable # immediate, no undo — the page answers not foundRotation moves the page and its brand to the replacement key, so the URL you handed out keeps working; revocation ends the page with the key. Which keys have a page, and which accept any origin, is on the console's keys page and in Keys & credentials.