Onboarding and Empty States skill for Codex
From signup to first value in fewer steps. Codex begins by naming the activation event and counting the steps a new account takes to reach it, then picks the lightest pattern that shortens the path: an auto-completing checklist, templates, sample data or a guided first task. Every empty surface gets distinct first-use, no-results and no-permission states, and funnel events show where new users stall.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- onboarding-empty-states Installs to ~/.agents/skills/onboarding-empty-states/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install onboarding-empty-states The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project onboarding-empty-states Installs to .agents/skills/onboarding-empty-states/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/onboarding-empty-states.zipunzip -o onboarding-empty-states.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) onboarding-empty-states PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $onboarding-empty-states, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Designs first-run experiences that get new users to value fast - defining the activation event, choosing between setup checklists, templates, sample data, guided first tasks and tours, writing empty states for first use, no results, cleared and no-permission cases, and instrumenting the activation funnel. Use when building signup-to-first-value flows, welcome screens, onboarding checklists or product tours, when new users churn before doing anything, or when screens show a blank table or "No data" with no next step.
Use it when
- Designing the experience between signup and first real value
- Lists, tables or dashboards show blank screens for new accounts
- Choosing between tours, checklists, templates and sample data
- Activation or day-one retention is low
Use something else when
- Loading, error and success copy across the whole app: use ui-copy-states
- Mapping the full end-to-end journey before designing screens: use user-flows
How to check the result
A fresh test account reaches the activation event in fewer steps than the baseline, and every empty surface shows the right state for first use, no results and missing permission.
The mistake it prevents
Using one generic empty state everywhere, so a search with no matches tells an experienced user to create their first item.
First-run design succeeds when a new user reaches the product’s core value (the activation event) in the fewest steps, every empty screen tells them what belongs there and offers the action that fills it, and the team can see where new users drop off. Tours that explain buttons before the user wants anything are friction, not onboarding.
Before designing
- Read
AGENTS.md, the signup flow, the first screen after signup, and every list, table or dashboard a new account sees empty. - Define activation with the user or from analytics: the action that predicts retention (“created first invoice and sent it”, “connected a repo and saw a run”). Write it as one sentence. Everything in onboarding serves this.
- Count the steps from signup to activation today, including emails, verification, required fields and integrations. That number is the baseline to cut.
Choosing patterns
| Situation | Pattern | Avoid |
|---|---|---|
| Value needs the user’s own data and a setup step (integrations, imports) | Setup checklist with 3–5 items, first item pre-completed (“Create account”) | Forcing all setup before showing the product |
| Value is visible with any data | Sample data or a demo workspace, clearly labelled and removable | Sample data that mixes into real reports |
| Users start from a blank canvas (docs, designs, automations) | Templates gallery as the empty state | An empty canvas with a blinking cursor |
| One core action defines value | Guided first task inline in the real UI | Modal tours of ten tooltips |
| Different roles want different paths | One or two questions at signup that change the first screen | Questions whose answers change nothing |
| Complex pro tool | Contextual hints at first use of each feature | Front-loaded walkthrough |
Default: put the user in the real product immediately, with the primary empty state pointing at the activation action, plus a checklist if setup is unavoidable.
Empty state anatomy
[Illustration or icon: optional, small, relevant]
Heading: what this space is for, in the user's terms "Your invoices live here"
Body: why it is empty and the value of filling it "Create one in under a minute and
get paid by card or bank transfer."
[Primary action] [Secondary: Import CSV · Use sample data · Read guide]
| Type | Cause | Content |
|---|---|---|
| First use | Nothing created yet | Purpose, value, primary create action, import or template alternative |
| No results | Search or filter matched nothing | Echo the query, offer to clear filters, suggest spelling or broader terms |
| Cleared / done | User finished everything (inbox zero) | Positive confirmation; no call to create more |
| No permission | Content exists but is hidden | Who can grant access and a request-access action |
| Error | Load failed | What failed, retry, status link; not styled as “empty” |
| Not yet available | Data is processing or arrives later | Expected time, what triggers it, notify option |
Never show a bare table header with zero rows or the word “No data”. Never reuse the first-use empty state for no-results; telling a searcher to “create your first project” when they have fifty is wrong.
import { useId } from "react";
type EmptyStateProps = {
title: string;
body: string;
action?: { label: string; onClick: () => void };
secondary?: React.ReactNode;
icon?: React.ReactNode;
};
export function EmptyState({ title, body, action, secondary, icon }: EmptyStateProps) {
const titleId = useId();
return (
<section className="empty-state" aria-labelledby={titleId}>
{icon && <div className="empty-icon" aria-hidden="true">{icon}</div>}
<h2 id={titleId}>{title}</h2>
<p>{body}</p>
{action && <button type="button" onClick={action.onClick}>{action.label}</button>}
{secondary && <div className="empty-secondary">{secondary}</div>}
</section>
);
}
Layout: center within the content area (not the viewport), max width ~40ch for text,
keep the surrounding page chrome (nav, filters) so users stay oriented. Match the
heading level to the page outline rather than always using h2.
Setup checklist rules
- 3–5 items, each tied to activation, ordered by dependency; show progress (“2 of 4”).
- Each item links to the place where it is done and ticks automatically when the event happens; manual checkboxes get ignored or lied to.
- Persist state server-side per account (and per user if roles differ).
- Dismissible, with a way back (help menu). Disappears after completion with a short success message.
- Skip items that do not apply (no “Invite team” for a solo plan).
Data model sketch:
type OnboardingStep = {
id: "connect_bank" | "create_invoice" | "send_invoice" | "invite_teammate";
completedAt: string | null; // set by the event handler, not by the UI
skippedAt: string | null;
};
Tours and hints
- Only for genuinely non-obvious features. Three steps max, launched by the user or at first use of that feature, never on first page load.
- Each hint must be keyboard reachable, dismissible with Escape, announced to screen readers, and must not trap focus or cover the element it explains.
- Store “seen” state server-side so hints do not repeat on every device.
Signup to first screen
- Ask only what is needed to create the account; defer profile fields.
- Email verification should not block exploring the product unless security requires it; gate sensitive actions instead.
- If you ask a personalization question, the next screen must visibly change because of the answer.
- Welcome screen, if any: one sentence, one action, no feature list.
Instrumentation
Fire events the product team can chart as a funnel (match the project’s analytics naming conventions first):
signup_completed -> onboarding_step_completed{step} -> activation_reached
empty_state_viewed{surface, type} -> empty_state_action_clicked{surface, action}
tour_started / tour_dismissed{step} / tour_completed
Report time-to-activation (median) and activation rate within 1 and 7 days.
Workflow
- [ ] 1. Define the activation event; count current steps to reach it
- [ ] 2. Choose the pattern from the table
- [ ] 3. Inventory every empty surface and its empty types
- [ ] 4. Write empty-state content per surface and type
- [ ] 5. Build checklist/templates/sample data with server-side state
- [ ] 6. Add events; verify the funnel fires end to end
- [ ] 7. Walk through as a brand-new account on mobile and desktop
Verification
- Create a fresh account (seeded test user, never a real one) and record steps and time to activation; compare with the baseline.
- Visit every surface empty, with a no-results filter, and without permission; each shows the correct empty type.
- Complete checklist items through the real UI; they tick without manual checking and survive reload and a second device.
- Keyboard and screen-reader pass on any tour or hint.
Gotchas
- Sample data that users cannot delete, or that pollutes billing and exports.
- Checklists that never go away, training users to ignore the area.
- Empty states designed only for desktop; on mobile, the action must be visible without scrolling past a large illustration.
- Onboarding built once and never re-tested; new required fields silently add steps.
Output contract
**Activation event:** <sentence> **Steps to activation:** <before> -> <after>
**Pattern:** <checklist | templates | sample data | guided task> because <reason>
**Empty states:** <surface>: first-use / no-results / no-permission (copy in <file>)
**Checklist:** <items>, auto-completing via <events>, stored in <table/API>
**Events:** <list> **Not done:** <...> What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Onboarding and Empty States"
short_description: "From signup to first value in fewer steps"
default_prompt: "$onboarding-empty-states New users sign up and never create a project, redesign our first-run experience" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.