VibeWeek
Home/Grow/Microcopy & Product Copy Systems: Chat Prompts

Microcopy & Product Copy Systems: Chat Prompts

⬅️ Back to 6. Grow

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:

  1. A strings/ directory organized by surface area or feature
  2. Typed constants so misspelled keys fail at compile time
  3. Easy to grep / find usage of any string
  4. 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:

  1. 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")
  2. 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
  3. 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")
  4. 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:

  1. [error scenario 1, e.g. "Stripe payment declined"]
  2. [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:

  1. A headline (4-8 words; explains state and primary action)
  2. A subheadline (1-2 sentences; orients the user to what they should do)
  3. A primary CTA button label
  4. Optional secondary CTA / link

Surfaces:

  1. Inbox empty (no messages yet)
  2. Dashboard empty (no data ever recorded)
  3. Search empty (search returned no results)
  4. List empty (no items in this list because user filtered them out)
  5. Trash empty
  6. Notifications empty
  7. Activity feed empty
  8. Just-signed-up state (account exists; no content yet)
  9. Trial-expired state
  10. 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:

  1. Initial app load
  2. Form submit (saving changes)
  3. File upload (with progress)
  4. Long-running search
  5. AI generation in progress
  6. Fetching external data (third-party API)
  7. Background job kicked off (showing async progress)
  8. 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:

  1. Delete a single item
  2. Delete multiple selected items
  3. Empty trash
  4. Cancel subscription
  5. Remove a teammate
  6. Transfer workspace ownership
  7. Disable two-factor auth
  8. 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:

  1. Email
  2. Password (signup vs login — different needs)
  3. Phone number (with country selector?)
  4. Date (with format hint?)
  5. URL / domain
  6. Tax ID / VAT
  7. Credit card
  8. API key
  9. Custom domain
  10. 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:

  1. Concatenation: "Hello, " + name + "! You have " + count + " messages." — breaks in other languages
  2. Pluralization: "1 item" vs "2 items" — many languages have 3-6 plural forms (Russian, Arabic)
  3. Gendered language: "his" / "her" assumes binary
  4. Implicit context: a string like "Save" might be a verb (save action) or noun (a savings) — translators need context
  5. Embedded HTML: "Hello" — translators get confused
  6. 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:

  1. Integrate with my feature-flag tool (GrowthBook / LaunchDarkly / Vercel Edge Config / your existing tool)
  2. Each test has variants; users assigned to a variant
  3. Track: click-through rate, downstream conversion (e.g. signup → activation), exposure
  4. After significance (p < 0.05; minimum 1000 exposures), pick winner
  5. 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:

  1. PR includes the new strings in the centralized strings file
  2. PR template asks: "Have you reviewed against the voice & tone guide?"
  3. 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
  4. Designer / writer review for non-trivial new copy
  5. 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)