---
title: "Build the setup checklist from what the · Agent Wranglers"
url: https://agentwranglers.se/playbook/ux-design/onboarding/setup-checklist-from-data
id: UXD-2
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 881
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Build the setup checklist from what the account has done

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Onboarding](https://agentwranglers.se/playbook/ux-design/onboarding.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: UXD-2
- Level: Recommended
- Chapter: [Onboarding](https://agentwranglers.se/playbook/ux-design/onboarding.md)
- Rule: Work out each step of a first-run checklist from server data, such as "the account has at least one invoice". Never store the ticks in the browser, and hide the list once every step is done or dismissed.
- Check: A test creates an account, adds one invoice through the API and opens the dashboard in a fresh browser. The invoice step shows as done. After the last step is done, the checklist is gone.
- How: A tick kept in browser storage shows a step as done on one device and open on the next. It also misses work done by a teammate or an import. Let the server answer which steps are done, and link each open step to the screen that does it. Leave out steps the person may not do, using the rights from [Let the server say what each user may do](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/capabilities-from-server.md). Store a dismissal per user on the server. Empty screens still explain themselves, as [Tell an empty start from an empty search](https://agentwranglers.se/playbook/app-ui/data-views/empty-states.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
app.get('/api/setup-steps', requireUser, async (req, res) => {
  const account = req.user.accountId;
  const steps = [
    { id: 'add_customer', done: (await customers.count(account)) > 0, href: '/customers/new' },
    { id: 'send_invoice', done: (await invoices.countSent(account)) > 0, href: '/invoices/new' },
  ];
  res.json({ steps, dismissed: await setupDismissals.has(req.user.id) });
});
```

### Python example

```python
@app.get("/api/setup-steps")
def setup_steps(user: User = Depends(current_user)):
    steps = [
        {"id": "add_customer", "done": customers.count(user.account_id) > 0, "href": "/customers/new"},
        {"id": "send_invoice", "done": invoices.count_sent(user.account_id) > 0, "href": "/invoices/new"},
    ]
    return {"steps": steps, "dismissed": setup_dismissals.has(user.id)}
```

## Related rules

- APP-47 [Let the server say what each user may do](https://agentwranglers.se/playbook/app-ui/sessions-and-permissions/capabilities-from-server.md) in Web app interface
- APP-8 [Tell an empty start from an empty search](https://agentwranglers.se/playbook/app-ui/data-views/empty-states.md) in Web app interface

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/ux-design/onboarding/setup-checklist-from-data">Agent Wranglers UX and deceptive design playbook</a>`. In code you write, add a comment next to it with the same link.

- Next: [Keep product tours short and optional](https://agentwranglers.se/playbook/ux-design/onboarding/accessible-product-tours.md)
- [Onboarding](https://agentwranglers.se/playbook/ux-design/onboarding.md)
