DEV Community

Jules Sarah
Jules Sarah

Posted on

How we cut support tickets 70% with docs

We sell React Native + Expo app templates. Six months ago, ~25% of buyers opened a support ticket within their first week. Today it's ~7%. Same product, same buyers. Only the docs changed.

This is the tactical writeup: what we audited, what we changed, and the seven doc pages that eat most of our former support volume.

  • Audit 90 days of tickets. Tag each with root cause + which doc would have prevented it.
  • Two-thirds of our tickets were setup friction, not bugs.
  • Consolidate environment variable docs into ONE page with a complete table.
  • Ship a "first 15 minutes" quick start that skips every optional feature.
  • Put error strings verbatim in your docs so Google indexes them.
  • Make your support surface more prominent, but route through a dialog that suggests docs first.
  • Result: ~70% fewer tickets, better bug reports, more time for real work.

The audit

We store support requests in a Supabase table (support_requests) surfaced through a small admin dashboard. Pulled 90 days, ~312 tickets, tagged each:

category: env-misconfig | supabase-setup | eas-build | stripe | bug | customization
template: weather-app | fitness-app | ai-voice-notes | chat-with-pdf | ...
doc_that_would_have_helped: <path or "none">
Enter fullscreen mode Exit fullscreen mode

Breakdown:

Category % of tickets
.env misconfig 34%
Supabase project setup 22%
Expo / EAS build errors 15%
Genuine bugs 11%
Stripe / license activation 9%
"How do I customize X" 9%

66% of tickets were pre-first-run setup friction. Not novel bugs. Not missing features. The twenty-minute cliff between git clone and a working simulator build.

Change #1: Index error strings, not concepts

The single highest-ROI change. For every ticket that mentioned an error message, the literal string now appears verbatim in a doc page with the fix beneath it.

Bad:

### AsyncStorage resolution issues

If your bundler can't resolve async storage, ensure the dependency is installed.
Enter fullscreen mode Exit fullscreen mode

Good:

### Error: `Unable to resolve module "@react-native-async-storage/async-storage"`

```bash
npx expo install @react-native-async-storage/async-storage
npx expo start --clear
```

This happens when the module was added transitively (usually via
`@supabase/supabase-js` session persistence) but not explicitly installed.
Enter fullscreen mode Exit fullscreen mode

Devs paste error strings into Google. Google indexes the string. Google sends them to the fix. You never see the ticket.

Change #2: One environment.mdx, not seven scattered mentions

Old state: .env variables were mentioned in the Supabase page, the Stripe page, the push-notifications page, the OneSignal page, the EAS page. Each mention was correct in isolation. Collectively, nobody could find anything.

New state: one environment.mdx page. One table. Columns: variable name, source, client-or-server, what fails if missing.

| Variable                          | Source                | Scope   | If missing                                |
|-----------------------------------|-----------------------|---------|-------------------------------------------|
| EXPO_PUBLIC_SUPABASE_URL          | Supabase dashboard    | Client  | App loads, all queries return 401         |
| EXPO_PUBLIC_SUPABASE_ANON_KEY     | Supabase dashboard    | Client  | Auth silently fails                       |
| SUPABASE_SERVICE_ROLE_KEY         | Supabase dashboard    | Server  | Server routes return 500                  |
| STRIPE_SECRET_KEY                 | Stripe dashboard      | Server  | Purchase webhooks 500, no license grants  |
| ...                                                                                                     |
Enter fullscreen mode Exit fullscreen mode

Boring. Effective. This one page killed a plurality of setup tickets alone.

Change #3: Six-command quick start

Old quick-start.mdx was maximalist: clone, install, env, Supabase, Stripe, EAS, push notifications, deep linking. New one:

git clone <your-license-url>
cd applighter-template
npm install
cp .env.example .env
# fill in EXPO_PUBLIC_SUPABASE_URL + ANON_KEY
npx expo start
Enter fullscreen mode Exit fullscreen mode

Six commands. A running app on your simulator. Everything else is optional and lives on its own page.

Nobody wants to configure OneSignal in their first hour. Stop making them.

Change #4: Prominent support surface, routed through docs

Counter-intuitive result: making our support link more visible reduced tickets, not increased them.

The floating support button (a contact-author-fab component) opens a dialog. The dialog:

  1. Asks for a one-line problem summary
  2. Searches our docs for keyword matches
  3. Surfaces top 3 doc results before offering the submit button
  4. Only then lets you file a ticket

Roughly 40% of dialog opens never become tickets. People click a doc result, read it, close the dialog, and move on. Zero human interaction.

What didn't work

Videos. Three 8-minute setup walkthroughs. Two weeks of production. ~40 views/month combined. No measurable ticket delta. Devs skim; video prevents skimming.

Chatbot on our docs. Hallucinated flags, invented API surface, confidently misrepresented patterns we don't use. Customers pasted its answers back to us as bug reports. Killed after one week. The space is improving fast, but static docs that say the true thing still beat generative docs that say a plausible false thing.

The seven-page scaffold

If you're starting fresh (this is the structure every Applighter template's docs now follow):

  1. quick-start.mdx: six commands, no optional features
  2. installation.mdx: prerequisites, tool versions, common install errors verbatim
  3. environment.mdx: one table, every variable, every failure mode
  4. folder-structure.mdx: where things live, in one screen
  5. supabase.mdx: project provisioning, RLS, storage buckets
  6. expo-integration.mdx: EAS Build, provisioning, error strings verbatim
  7. ui-components.mdx: customization points, how to not break updates

Everything beyond these seven pages is a nice-to-have.

Metrics worth tracking

  • Tickets per 100 active customers/week (target: <8)
  • % of tickets citing a doc page (target: >60%, which means people are reading first)
  • % of support-dialog opens that don't become tickets (target: >30%)
  • Median first-response resolution rate (target: >50%)

Metric to stop tracking: total weekly support hours. Goes to zero if you ignore your inbox. Useless.

References

Fewer tickets, better product, same 4,000 words of docs, just pointed at the right problems.

If you sell templates or dev tools: what's your top ticket category? Curious whether the two-thirds-setup-friction split holds outside our niche. Drop it in the comments.

Top comments (0)