Context and diagnostics
What the browser sends with a message, and what you can add to a bug report.
| What | Default | Sent with | Switch |
|---|---|---|---|
| Telemetry | On | Every message, feedback note, contact form send and crash report | telemetry={false} |
| Screenshots | Depends on the component | See the table below | screenshot={false} |
| Diagnostics | Off | The first send after mounting, then any send after something new went wrong | diagnostics |
| App state | None | Inside the diagnostics snapshot | appState |
| Attached data | Nothing queued | The next widget message, feedback note, contact form send or crash report | medianSupport.attach() |
Crash reports from an error screen are on Crash reports.
Telemetry
The widget reads these when the visitor sends something. Nothing is watched or read before that.
| Field | Source | Shown to your team as |
|---|---|---|
| Time zone | The browser’s time zone | Local time, with the zone under it |
| Language | navigator.language |
Language, as a name such as English (United Kingdom) |
| Browser | The user agent, reduced to a name and major version | Browser |
| OS, device, screen | The user agent, touch support, and the screen size | Under Browser, such as macOS · Desktop · 1512 × 982 |
| Page | The URL without its query string or fragment, the page title, and the referrer | Started on, with the referrer’s host under it |
- Device is Desktop, Tablet or Phone.
- The raw user agent is never sent.
- The page is kept from a conversation’s first message. Later messages do not change it.
- Each message refreshes the customer’s time zone, language and browser.
- Last seen is the time of the last message, feedback note or crash report. It is kept with or without telemetry.
telemetry={false}sends none of these.MedianSupport,MedianSupportModal,MedianFeedback,MedianContactForm,useMedianContact,sendMedianContactandreportErrorall take it.
Screenshots
| Component | When a picture is taken | If it fails |
|---|---|---|
MedianSupport, MedianSupportModal |
When the agent asks to see the screen and the visitor presses Share my screen | The agent is told no picture is coming and asks in words |
MedianFeedback |
With every note, unless the visitor attached 6 pictures | A failed capture sends the note without it. A failed upload stops the send and shows the error |
reportError |
With every crash report | The report goes without it |
MedianContactForm |
Never |
screenshot={false}turns it off. OnreportError, passscreenshot: false. On the widget, the agent is then told no picture is coming.- When the agent asks, the panel shows Share my screen and Not now over the composer. Not now, or declining the browser’s prompt, tells the agent the visitor chose not to share. With no answer after 2 minutes, the agent is told no picture is coming.
- The widget’s picture lands in the thread as the visitor’s message, with no text, so the visitor sees what was sent.
- A note’s or crash report’s picture lands on the report in Signal, beside any the visitor attached. Pictures the visitor sent in a thread are copied onto a bug filed from it, up to 6.
| How it is taken | The agent’s request | Feedback notes and crash reports |
|---|---|---|
| Source | The browser’s screen sharing. The visitor allows it, one frame is taken, and sharing stops | Drawn from the page’s DOM. Nothing is recorded, and no permission prompt appears |
| Area | What the visitor shares. Chrome and Edge offer the current tab. Firefox and Safari ask for a window or screen | The visible part of the page |
| Size | Scaled down to 1440px wide at most | Scaled down to 1440px wide at most |
| Format | JPEG, named screenshot.jpg |
JPEG, named screenshot.jpg |
| Left out | Median panels fade out while the frame is taken | Every Median panel, launcher, contact form and highlight ring |
| Time limit | None for the frame. The request waits 2 minutes for an answer | 6 seconds, then the picture is skipped |
- Where the browser cannot share a screen, such as on phones, or a
Permissions-Policyblocksdisplay-capture, the agent’s request draws the page from the DOM instead. - In a drawn picture, cross-origin images,
<canvas>and<video>can come out blank. A font that fails to load is drawn in the browser’s fallback. - In a drawn picture, a
position: fixedelement is drawn where it sits on screen. Aposition: stickyelement is drawn where it sits in the page, so a sticky header can be missing from a picture taken further down. - The background of a drawn picture is the body’s color, then the html element’s, then white.
- Everything on the page is in the picture. Pass
screenshot={false}on pages that show somebody else’s data.
Diagnostics
Off by default. When on, the component records what goes wrong on the page and sends it with the next message or note.
<MedianSupport
apiKey="median_pk_..."
diagnostics={{ network: true, console: true }}
appState={{ version: BUILD_SHA, plan: user.plan }}
/>
| Switch | Records | How |
|---|---|---|
errors |
Uncaught errors and unhandled promise rejections | Listens on window. Failed image and script loads are skipped |
network |
fetch calls that threw or returned a status outside 200 to 299, with the method and URL |
Wraps window.fetch. XMLHttpRequest is not watched |
console |
console.error calls |
Wraps console.error |
| You pass | errors |
network |
console |
|---|---|---|---|
diagnostics or diagnostics={true} |
On | Off | Off |
diagnostics={{ network: true }} |
On | On | Off |
diagnostics={{ errors: false, console: true }} |
Off | Off | On |
Nothing, or false |
Off | Off | Off |
- The wrappers call through to what they replaced. They are removed when the component unmounts.
MedianSupport,MedianSupportModal,MedianFeedback,MedianContactFormanduseMedianContacttake the same prop.- Every component on the page shares one list of events, and each kind of event is recorded once however many components ask for it. Each component sends the list only when its own
diagnosticsprop is on. - The first send after a component mounts carries a snapshot with the page URL, the viewport size,
appStateand the recorded events. Later sends carry one only when something new was recorded. - A snapshot carries the latest 12 events, not only the new ones.
- On a conversation, the newest snapshot replaces the last one. It is copied onto a bug the agent files from that conversation.
- reportError always sends a snapshot, whatever the props say.
| Limit | Value |
|---|---|
| Events kept | 12. Older events drop off |
| Event message | 300 characters |
| Source, as file and line or method and URL | 200 characters |
| Stack | 800 characters |
URLs lose their query string and fragment. On a report in Signal, the snapshot shows as Page, Viewport, one row per appState entry, and Browser logs. An appState entry whose value the page URL already ends with is left out.
Your server can add its own half. A diagnostics function in median.config.ts runs when a bug is filed, and its answer shows on the report as Server check.
App state
appState puts facts about your app on a bug report, such as a build, a flag or a plan.
- It is read at send time, so it can change as the visitor moves around.
- It travels inside the diagnostics snapshot. Without
diagnostics,MedianSupport,MedianFeedbackand the contact form do not send it. reportErrorsends theappStateof the last Median component given one, with or withoutdiagnostics.
| Limit | Value |
|---|---|
| Entries | 20. The rest are dropped |
| Key | 60 characters |
| Value | 200 characters. Numbers and booleans become text. null and undefined are skipped |
Attach your own data
attach queues data for the next bug report, such as a trace, a request id or the state of a store.
import { medianSupport } from "@mediansh/widget";
window.addEventListener("error", (event) => {
medianSupport.attach("Crash trace", event.error?.stack);
});
useMedianSupport().attach is the same function.
- The queue lives in memory for the page load. A full reload empties it.
- The next widget message, feedback note, contact form send or crash report takes the whole queue. A failed send puts it back.
- It works with
diagnosticsoff. - A second entry with the same label replaces the first.
- Objects are written out as indented JSON. Numbers and booleans become text.
- On a conversation, entries wait for the agent to file a bug from it. If no bug is filed, nobody sees them.
| Limit | Value |
|---|---|
| Entries | 8, newest kept |
| Label | Trimmed, cut at 60 characters |
| Value | Cut at 4,000 characters |
How an entry shows on a report:
| Value | Shows as |
|---|---|
An http or https URL ending in .png, .jpg, .jpeg, .gif, .webp, .avif or .bmp |
The picture, named with the label |
| Any other lone URL | A link row |
| Anything else | A block titled with the label |
medianSupport.attach(
"Last render",
"https://files.acme.com/shots/checkout-8812.png",
);
- An empty label or value queues nothing. In development, the console says
Median: attach() needs a label and a value, and nothing was queued. - In development, attaching with no
MedianSupport,MedianFeedbackor contact form mounted printsMedian: data was attached, but no <MedianSupport>, <MedianFeedback> or contact form is on the page to send it.after one second. The next send from any of them still takes the queue.
The agent attaches data the same way when it files a bug. A trace, an error id or a failing request the customer pastes is kept on the report word for word.