Olympus Docs
CookbookUI & content

In-app feedback and help button

Let users report problems quickly

When something breaks for a user, they need a way to tell you. A floating feedback button captures this.

Pattern

<FloatingButton>
  <HelpIcon /> Help
</FloatingButton>

Bottom-right corner. Always visible. Click → menu of options.

Options

<Menu>
  <MenuItem onClick={() => openDocs()}>📖 Help docs</MenuItem>
  <MenuItem onClick={() => openChat()}>💬 Live chat</MenuItem>
  <MenuItem onClick={() => openFeedback()}>📝 Send feedback</MenuItem>
  <MenuItem onClick={() => reportBug()}>🐛 Report a bug</MenuItem>
</Menu>

Choose what fits your support model.

Feedback form

<form onSubmit={submitFeedback}>
  <Select name="type">
    <option>Question</option>
    <option>Bug</option>
    <option>Feature request</option>
    <option>Other</option>
  </Select>
  <textarea name="message" required />
  <Checkbox name="include_session_info">
    Include diagnostic info (your account, page URL)
  </Checkbox>
  <Button type="submit">Send</Button>
</form>

Diagnostic info helps support. User consents to share.

Server-side

app.post("/api/feedback", async (req, res) => {
  const session = await getSession(req);
  const { type, message, include_session_info } = req.body;
  
  await db.insert(feedback).values({
    user_id: include_session_info ? session?.identity.id : null,
    user_email: include_session_info ? session?.identity.traits.email : null,
    type,
    message,
    page_url: req.headers.referer,
    user_agent: req.headers["user-agent"],
    submitted_at: new Date(),
  });
  
  // Notify
  await slack.send({
    channel: "#feedback",
    text: `New ${type}: ${message.slice(0, 200)}...`,
    user: session?.identity.traits.email,
  });
  
  res.json({ ok: true });
});

Notifies team. Allows quick triage.

Confirmation

<Toast>
  Thanks! We'll get back to you within 24 hours.
</Toast>

User feels heard.

Triage workflow

Feedback queue:

// Admin tool
<FeedbackInbox>
  {feedback.map(f => (
    <FeedbackItem>
      <Header>
        {f.user_email} - {f.type} - {timeAgo(f.submitted_at)}
      </Header>
      <Body>{f.message}</Body>
      <Footer>
        <Button onClick={() => respond(f.id)}>Respond</Button>
        <Button onClick={() => convertToTicket(f.id)}>Open ticket</Button>
        <Button onClick={() => archive(f.id)}>Archive</Button>
      </Footer>
    </FeedbackItem>
  ))}
</FeedbackInbox>

Daily review. Respond within agreed SLA.

Categorization

Auto-categorize by keywords:

function categorize(message: string) {
  if (/(bug|broken|error|crash)/i.test(message)) return "bug";
  if (/(feature|request|wish|wish list)/i.test(message)) return "feature_request";
  if (/(slow|performance)/i.test(message)) return "performance";
  return "other";
}

Helps prioritize.

Sentiment

Optional: sentiment analysis.

const sentiment = await openai.completions.create({
  prompt: `Analyze sentiment of this feedback: "${message}". Return: positive, neutral, or negative.`,
});

Helps identify upset users for proactive outreach.

Screenshots

For UI bugs, screenshot upload:

<input type="file" accept="image/*" name="screenshot" />

Or, advanced:

<Button onClick={captureScreen}>📷 Attach screenshot</Button>

html2canvas or dom-to-image captures current page.

Session replay

Tools like LogRocket, Hotjar record sessions. When user submits feedback:

  • Link to their replay.
  • Support sees what user saw + did.

Massively helpful for debugging weird UI bugs.

Privacy

Feedback might contain PII (user pastes screenshot of their data).

  • Don't auto-share to third-party logs.
  • Redact in logs.
  • Treat as sensitive data.

Don't intercept

Some apps interrupt user with "Are you sure you want to leave?" Don't. Feedback button: passive.

Most apps need a help center. Link prominently:

<MenuItem href="https://your-domain.com/docs">📖 Help center</MenuItem>

Or contextual:

<HelpIcon onClick={() => router.push("/docs/feature-x")} />

Per-page docs.

<input 
  type="search"
  placeholder="Search help..."
  onSubmit={(e) => router.push(`/docs/search?q=${e.target.value}`)}
/>

Direct to docs from in-app.

Chat

If you have support chat (Intercom, Crisp, Drift):

<MenuItem onClick={() => window.Intercom?.("show")}>💬 Live chat</MenuItem>

Pre-load user context:

window.Intercom("update", {
  user_id: session.identity.id,
  email: session.identity.traits.email,
  plan: session.identity.metadata_public.plan,
});

Support agent sees who they're talking to.

Don't overdo

Some apps spam: "rate us!" pop-ups, "take a survey," etc. Restraint:

  • Feedback button visible always.
  • Active prompts: rarely (after milestones).
  • Surveys: weeks apart, with cap.

Annoyance defeats the purpose.

On this page