Microcopy & Product Copy Systems: Chat Prompts
Microcopy is the small, in-product text that nobody calls "copy" — button labels, error messages, empty states, confirmation dialogs, success toasts, validation errors, helper text on form fields, placeholder text, loading states, tooltips. It's 80% of the words in your app and the surface where most users decide whether your product feels professional or sloppy. Most teams ship microcopy ad-hoc — engineers type the first thing that comes to mind ("Error", "Submit", "Are you sure?"), designers maybe wordsmith later, copywriters get involved only for marketing pages. The result: inconsistent voice, terms used differently in different surfaces ("workspace" / "team" / "org"), translation rot when you go international, and 200 hardcoded English strings nobody can find.
A product copy system fixes this — centralized strings, voice + tone guidelines, terminology dictionary, copy-review process, i18n-ready from day 1, and ideally A/B testable for the 5-10 strings that actually move metrics (paywall CTA, signup button, error recovery).
When You Need a Real Copy System
Buy in early when:
- Product has 50+ user-facing surfaces (most SaaS past pre-revenue)
- You'll go international within 18 months (rip out hardcoded strings now)
- You have 3+ engineers touching UI strings (consistency suffers fast)
- You'll A/B test critical CTA copy (need centralized control)
Don't over-engineer when:
- Pre-product-market fit (strings change weekly)
- Solo dev / 2-person team where ad-hoc works
Centralized String Management
Strings should live in one place — not scattered across components.
I want to centralize all my product strings in a single source of truth.
Current state: strings are hardcoded inline like:
```tsx
<Button>Save changes</Button>
<p className="text-sm text-muted-foreground">No data found</p>
I want:
- A
strings/directory organized by surface area or feature - Typed constants so misspelled keys fail at compile time
- Easy to grep / find usage of any string
- Eventually: i18n-ready (the structure should support per-locale variants without a full rewrite)
Recommend an approach. Options I'm considering:
- Plain TS objects:
export const strings = { auth: { signIn: "Sign in" } } - next-intl / react-intl with JSON files
- tolgee or Lingui for managed translation
- Skip i18n for now; just colocate strings as constants
For my stage (Series A, English-only, 6 months from EU launch), what's the right depth?
Stack: Next.js 16 App Router + TypeScript.
Recommended at Series A: **next-intl with English-only JSON, structured for future locales**. You get the centralization benefits now and can add locales later without refactoring.
## Voice and Tone Guide
Microcopy decisions need a voice + tone framework, not 1-by-1 negotiation.
Help me draft a voice and tone guide for my B2B SaaS [type, e.g. "developer tools" / "marketing platform"].
Structure:
-
Brand voice (consistent across surfaces)
- 3-5 voice attributes (e.g. "concise, confident, never condescending")
- 3-5 voice anti-patterns (e.g. "no exclamation marks; no marketing speak; no apologies")
-
Tone (varies by context)
- First-time user welcome: friendly, helpful, brief
- Error message: clear, actionable, not blameful ("We couldn't save that" not "You did wrong")
- Confirmation dialog: serious, specific, no humor
- Empty state: encouraging, suggestive of action
- Success toast: brief acknowledgment, no celebration
- Power-user shortcut: terse, technical
-
Term-by-term style decisions
- Sentence case vs Title Case for buttons (sentence case)
- "We" / "you" / "your" usage
- Period at end of UI text (no for buttons; yes for sentences)
- Numbers (numerals for counts: "3 items" not "three items")
- Dates ("Mar 15" or "March 15, 2026" or "15 March 2026")
-
Concrete examples
- "Save" vs "Save changes" — when each is right
- "Delete" vs "Remove" vs "Archive" — when each is right
- "Loading…" vs "Saving…" vs blank
- "Are you sure?" alternatives
Output a usable voice & tone document plus 30 example microcopy do/don't pairs.
Stack: B2B SaaS, [your product type and audience].
This is one of the highest-leverage docs you can write — it ends 100 future debates about whether to use "Edit" or "Modify."
## Terminology Dictionary
Pick a term for each domain concept; use it consistently. "Workspace" / "team" / "org" / "account" are not interchangeable.
Help me build a terminology dictionary for my product. Here are the domain concepts I have:
- The container that holds users + their data: workspace? team? org? account?
- The individual user: user? person? member? teammate?
- The thing users create with the product: project? document? item? entity?
- The shareable link to a thing: share link? public link? guest link? embed?
- The role that can administer: admin? owner? manager?
- The role that can only view: viewer? reader? guest? member?
- The thing on a billing plan: subscription? plan? tier?
- The list of features in a tier: features? capabilities? entitlements?
- The notification of an event: alert? notification? message? event?
Pick one term for each. Define each:
- The single canonical term (the one to use)
- The forbidden synonyms (so engineers stop saying "team" when we mean "workspace")
- A 1-sentence definition
- An example usage in UI
Then write a lint rule (or at least a list) that I can use in PR review to catch synonym drift.
Output the dictionary as a Markdown table; output a terminology.json artifact suitable for tooling.
Run this against your existing product strings. You'll find 5-10 places where two terms are used for the same thing.
## Error Messages That Don't Suck
Error microcopy is where most products fail hardest.
I want to rewrite my error messages. Current state: most are generic ("An error occurred") or technical ("HTTP 422 Unprocessable Entity").
Help me adopt a structured error-message format:
Pattern: "[What happened]. [Why]. [What to do.]"
Examples:
-
BAD: "Network error"
-
GOOD: "We couldn't save your changes. Your connection seems unstable. [Retry] or [Save as draft]."
-
BAD: "Invalid email"
-
GOOD: "Email address is missing the @ symbol. Add an @ between the username and domain."
-
BAD: "Permission denied"
-
GOOD: "You don't have permission to delete this. Ask an admin to delete it, or [Move to trash] instead."
For each of my common errors, draft the new copy:
- [error scenario 1, e.g. "Stripe payment declined"]
- [error scenario 2] ...
Constraints:
- Never blame the user
- Never apologize hollow ("Sorry for the inconvenience" — meaningless)
- Always offer next action when possible
- Plain language, no jargon
- Short — error is read in a stressed moment
Stack: Next.js + your existing error-display surfaces.
The "what happened / why / what to do" formula alone fixes 80% of bad error UX.
## Empty States
The blank slate of a feature is a copy + design problem.
I have several empty states in my app that currently say "No items" with a generic icon. Help me rewrite them.
For each empty state below, write:
- A headline (4-8 words; explains state and primary action)
- A subheadline (1-2 sentences; orients the user to what they should do)
- A primary CTA button label
- Optional secondary CTA / link
Surfaces:
- Inbox empty (no messages yet)
- Dashboard empty (no data ever recorded)
- Search empty (search returned no results)
- List empty (no items in this list because user filtered them out)
- Trash empty
- Notifications empty
- Activity feed empty
- Just-signed-up state (account exists; no content yet)
- Trial-expired state
- No-permission state
Tone: encouraging, brief, suggestive of action. Never sad ("nothing here :(").
Output as a copy spec with each surface's spec.
## Loading States Beyond "Loading…"
"Loading…" is the default. Sometimes that's fine; sometimes specific is better.
For each operation, propose loading-state copy:
- Initial app load
- Form submit (saving changes)
- File upload (with progress)
- Long-running search
- AI generation in progress
- Fetching external data (third-party API)
- Background job kicked off (showing async progress)
- Skeleton state (shimmer; what text, if any?)
Constraints:
- Specific over generic when speed allows
- Skeleton states usually need no copy
- Progress percentage when known
- Time estimates for known-slow operations ("This usually takes 30 seconds")
- "AI is thinking…" is OK; "Loading AI…" is not
Output: per-surface copy + when to show skeleton vs spinner vs progress.
## Confirmation Dialogs
Most confirmation dialogs are bad ("Are you sure?"). Rewrite mine.
Pattern: state the consequence; specify the action; offer cancel.
Examples:
- Generic: "Are you sure?"
- Better: "Delete 5 items? They'll be permanently removed and can't be recovered. [Cancel] [Delete]"
For each destructive action, write the dialog:
- Delete a single item
- Delete multiple selected items
- Empty trash
- Cancel subscription
- Remove a teammate
- Transfer workspace ownership
- Disable two-factor auth
- Delete account
Constraints:
- The destructive button is the right side, danger color
- The action name is on the button ("Delete", not "Confirm")
- Cancel is left side, neutral
- No "OK" — name the action
Output the spec for each.
## Helper Text on Form Fields
For my form fields, decide which need helper text and what it says.
Pattern:
- Label: short, identifies the field
- Helper text: when more context is needed; minimal noise
- Error: only when invalid; specific
Field types:
- Password (signup vs login — different needs)
- Phone number (with country selector?)
- Date (with format hint?)
- URL / domain
- Tax ID / VAT
- Credit card
- API key
- Custom domain
- Slug (auto-generated; user can edit)
For each:
- Should helper text always show or only on focus?
- What's the error message when invalid?
- Any privacy / security notice ("We never share your email")?
Output a per-field spec.
## Localization-Ready Strings
When you add a second language, hardcoded strings break — concatenation fails, plural rules differ, context disappears.
Make my strings i18n-ready before I add a second language.
Audit my strings for these issues:
- Concatenation:
"Hello, " + name + "! You have " + count + " messages."— breaks in other languages - Pluralization: "1 item" vs "2 items" — many languages have 3-6 plural forms (Russian, Arabic)
- Gendered language: "his" / "her" assumes binary
- Implicit context: a string like "Save" might be a verb (save action) or noun (a savings) — translators need context
- Embedded HTML: "Hello" — translators get confused
- Sentence reordering: SVO vs SOV languages need different word orders
Refactor to:
- Use ICU MessageFormat for plurals:
{count, plural, one {# item} other {# items}} - Use template variables:
{name} sent you a message - Provide context comments alongside each string:
// Verb: save form data - Avoid concatenation; use a single template with placeholders
Show me how to refactor 5 example strings from my codebase.
Stack: next-intl or react-intl.
## A/B Testing Critical Copy
Some strings move metrics. Others don't. For the metric-movers, A/B test.
I want to A/B test microcopy on a few critical surfaces:
- Signup button: "Sign up free" vs "Get started" vs "Try it free"
- Pricing page CTA: "Start free trial" vs "Try Pro free for 14 days"
- Empty state CTA: "Create your first project" vs "Add a project"
- Paywall: "Upgrade to Pro" vs "Unlock Pro features"
Build:
- Integrate with my feature-flag tool (GrowthBook / LaunchDarkly / Vercel Edge Config / your existing tool)
- Each test has variants; users assigned to a variant
- Track: click-through rate, downstream conversion (e.g. signup → activation), exposure
- After significance (p < 0.05; minimum 1000 exposures), pick winner
- Avoid: testing 10 strings at once (no power); testing strings nobody hits
Implement the pattern + show me a <TestableLabel testKey="signup_cta" variants={...} /> component.
Stack: Next.js + GrowthBook + PostHog (or your stack).
## Copy Review Process
Past 10+ engineers, copy needs gating to stay consistent.
Help me design a copy review process:
For new strings:
- PR includes the new strings in the centralized strings file
- PR template asks: "Have you reviewed against the voice & tone guide?"
- CI lint catches:
- Banned terms (the synonyms list from the dictionary)
- "Sorry" or "please" overused
- Title Case where sentence case is preferred
- Hardcoded strings outside the strings file
- Designer / writer review for non-trivial new copy
- Required for: new error messages, new empty states, paywall, signup, billing
For existing strings:
- Quarterly audit: pull all strings; review with designer / writer
- Update inconsistencies; document changes
- Re-localize if multi-language
Build:
- The PR template
- The CI lint rule (regex-based for the banned terms)
- The audit query (SELECT all strings; group by surface)
Stack: GitHub Actions + your existing PR flow.
## Common Pitfalls
**Hardcoded strings.** Strings buried in components; nobody can find them; localization is impossible. Centralize.
**Inconsistent terminology.** "Workspace" in one place, "team" in another, "organization" in a third. All meaning the same thing. Pick one.
**Title Case button labels.** "Save Changes" reads heavier than "Save changes". Use sentence case unless your design system explicitly mandates otherwise.
**Apologetic language.** "Sorry for the inconvenience" / "Sorry, we couldn't…" — every instance is meaningless overhead. Drop it; state the problem and fix.
**Blame the user.** "You entered an invalid email." Better: "This email address looks invalid — check the @ symbol."
**No "what to do next" in errors.** "Network error" tells me nothing. Tell me to retry, save offline, contact support.
**Generic loading states.** "Loading…" everywhere is fine if you use it sparingly. Specific is better when speed matters.
**Concatenation for i18n.** "Hello, " + name + "!" — breaks in many languages. Use templates.
**Plurals as `${count} item${count !== 1 ? 's' : ''}`.** Doesn't work for languages with multiple plural forms. Use ICU MessageFormat.
**Voice drift.** Engineering team writes "Submit"; design rewrites "Save changes"; QA sees "Confirm" — three different terms for the same action. Voice guide + lint catches drift.
**No copy on first-launch experience.** First 60 seconds in the product is where retention decisions happen. Empty states + onboarding hints carry disproportionate weight.
**A/B testing low-impact strings.** Testing whether "Hi" or "Hello" performs better is noise. Test paywall CTAs, signup buttons, error recovery — strings that move conversion meaningfully.
**Hardcoded strings in error boundaries.** Production errors fall back to "Something went wrong." Same generic everywhere; can't be customized per route. Centralize even error-boundary copy.
**Forgetting placeholder text.** Form placeholders like "Enter your email" are copy too. They're often left as default browser text or default React Hook Form values — review them like other strings.
**Shouting.** "WARNING!", "ERROR!", "PLEASE NOTE:" — caps + exclamation = panic. Calm copy reads more confident.
**Cuteness.** "Oopsie!" / "Looks like things got a bit silly!" — chips away at brand seriousness for B2B. Save personality for delight moments, not error states.
**Inconsistent date / number formats.** "Mar 15" in one place; "March 15, 2026" in another; "15 March 2026" in a third. Pick a format per context (timeline = relative; document metadata = absolute).
**Marketing voice in product.** "🎉 Congratulations! You just took an amazing step!" copy lifted from a landing page into the product reads as vibe mismatch. Product voice ≠ marketing voice.
**Translating before sourcing.** Sending raw strings to translators without context (verb? noun? button? heading?) produces broken translations. Provide context comments.
## See Also
- [Form Validation UX](./form-validation-ux-chat.md) — error message patterns
- [Empty States, Loading & Error States](./empty-states-loading-error-states-chat.md)
- [Toast Notifications UI](./toast-notifications-ui-chat.md)
- [Tooltip & Hint Systems](./tooltip-hint-systems-chat.md)
- [Onboarding Tour Implementation](./onboarding-tour-implementation-chat.md)
- [In-Product Help Center / Knowledge Base](./in-product-help-center-knowledge-base-chat.md)
- [In-Product Release Notes / What's New](./in-product-release-notes-whats-new-chat.md)
- [In-App Status Banners & System Notifications](./in-app-status-banners-system-notifications-chat.md)
- [In-App Notifications](./in-app-notifications-chat.md)
- [Email Template Implementation](./email-template-implementation-chat.md)
- [Internationalization](./internationalization-chat.md)
- [AB Testing](./ab-testing-chat.md)
- [Feature Flags](./feature-flags-chat.md)
- [Settings & Account Pages](./settings-account-pages-chat.md)
- [Account Suspension & Fraud Holds](./account-suspension-fraud-holds-chat.md)
- [Trial to Paid](./trial-to-paid-chat.md)
- [Pricing Page](./pricing-page.md)
- [Reduce Churn](./reduce-churn-chat.md)
- [Activation Funnel](./activation-funnel-chat.md)
- [Brand Voice (LaunchWeek)](https://launchweek.dev/content/1-position/brand-voice.md)
- [Localization & Translation Tools (VibeReference)](https://viberef.dev/marketing-and-seo/localization-translation-tools.md)