Screens of a real app

Demo data for screenshots of your app: a privacy checklist

A privacy checklist for demo data for screenshots: what leaks into app captures, how to seed safe fake data, and what to check before an image is shared.

6 min read

Demo data for screenshots should be invented, not masked: fake people on reserved domains, fictional phone numbers, and amounts and dates that tell a plausible story, shown through a demo account on a database seeded for that purpose. A screenshot keeps everything the screen showed at that moment, and it travels further than the app does: tickets, docs, design tools, chats with an AI agent. The privacy work has to happen before the capture.

Why screenshots leak more than you expect

A screenshot has no access control of its own. Once taken, it is copied into places your app’s permissions never reach, and nobody reviews every pixel. What slips through is rarely the main table, which people check, but the edges of the screen:

  • a toast or a notification that appeared during the capture;
  • the “assigned to” column with a colleague’s full name;
  • an autocomplete list that shows recent searches;
  • a support chat widget with a customer’s last message;
  • a debug panel, an environment banner or an internal hostname;
  • the URL, when you store it with the image and its query string carries an email address or a token.

Screenshots are also read by machines now. An image pasted into a chat with an AI assistant or a coding agent goes to a model provider, and a capture sent to a design or review tool is stored on its servers. Each copy follows the retention rules of the place it lands, not yours.

Principles for safe demo data

  1. Invent, do not mask. Covering real data with boxes or blur is fragile: miss one field and the image leaks. Data that was never real cannot leak.
  2. Use a separate environment. A demo database seeded from a script, never a restored copy of production, even “only for staging”.
  3. Realistic, yet obviously fake. Plausible names, lengths and amounts reveal layout problems that “Lorem ipsum” hides, while reserved domains make it clear nothing is real.
  4. Deterministic. The same seed gives the same records, so screenshots taken a month apart can be compared.
  5. Dedicated accounts. One demo account per role, with credentials that open nothing else. It is the same idea as giving an AI agent a scoped key: access limited to what the task needs.

The checklist

Data Safe choice
Person names Invented, varied in length and origin, including one very long name
Email addresses A reserved domain: example.com, example.org or a .test domain (RFC 2606)
Phone numbers Fictional ranges, such as 555-0100 to 555-0199 in North America
Postal addresses Invented streets and towns
Avatars and photos Initials, generated shapes, or images you have the right to use
Company names Invented, and checked against a quick search
Amounts and balances A range: small, large, zero, negative
Card and bank numbers Your payment provider’s published test numbers only
IP addresses Documentation ranges such as 192.0.2.0/24 (RFC 5737)
Dates and times A fixed clock, so “today” and “3 minutes ago” do not drift
Free text Written for the demo: notes, comments, messages, search history
Staff and internal data Demo teammates, no real colleague names, no internal hostnames
Secrets No key, token or session identifier in a debug panel or a URL

Seed the demo data from a script

A seed script in the repository makes demo data reviewable and repeatable. Keep it short and written by hand for the screens you capture, rather than generating thousands of random rows:

// seed/demo.js: runs only against the demo database
if (process.env.APP_ENV !== "demo") throw new Error("Demo seed refused outside the demo environment");

const customers = [
  { name: "Harbor Street Bakery", contact: "Lena Ortiz", email: "lena@harbor-bakery.example.com" },
  { name: "Quill and Compass Studio", contact: "Tomasz Wierzbicki-Hallström", email: "tomasz@quill.test" },
  { name: "Blue Fern Clinic", contact: "Ada Mensah", email: "billing@bluefern.example.org" },
];
const invoices = [
  { customer: 0, amount: 1250.0, status: "paid", due: "2026-02-10" },
  { customer: 1, amount: 98430.55, status: "overdue", due: "2026-01-15" },
  { customer: 2, amount: 0, status: "draft", due: null },
];

Note the deliberate edge cases: a long name, a large amount, a zero, an empty due date. Good demo data doubles as test data for the layout.

Control the rest at capture time

Some data comes from places a seed cannot reach: third-party APIs, notifications, the clock. Playwright gives you three tools:

  • Mock the API of a screen. page.route() with route.fulfill({ json }) answers a request with your fixture, and the real API is never called (Playwright docs on mocking APIs).
  • Freeze the clock. page.clock.setFixedTime() before navigating fixes what Date.now() and new Date() return.
  • Mask as a last resort. page.screenshot({ mask: [locator] }) covers an element with a solid box, pink by default. Use it for a third-party element you cannot control, not as a way to hide real customer data.
await page.route("**/api/notifications", (route) =>
  route.fulfill({ json: [{ title: "Invoice 1042 was paid", time: "2026-03-02T09:58:00Z" }] }));
await page.clock.setFixedTime(new Date("2026-03-02T10:00:00Z"));

Pass the demo credentials to the script as environment variables, and keep any saved session file out of the repository: Playwright’s authentication guide warns that it holds cookies that can impersonate the account. Screenshot every page with Playwright has the full capture script.

Check before an image leaves your machine

Before you share a batch of screenshots:

  • open every image at full size, not as a thumbnail: small text is where names hide;
  • look at the edges: toasts, badges, headers, footers, the user menu;
  • check what travels with the image: file names, the captured URL, any notes;
  • know where the images go, who can read them, and how to delete them;
  • capture again rather than editing an image by hand, or the next capture brings the problem back.

How agentappbuilder handles captures

agentappbuilder stores the screenshots your agent takes of your app, so these rules apply directly. The platform does not read, blur or filter the images: what the app showed is what is stored. Its guide tells your agent to capture with demo data only, and to stop and ask you if the app seems to show real customer data or points at a production deployment.

Unless your message already named the Playwright install and app.agentappbuilder.com, your agent first asks you in one message which screens it will capture, that the screenshots go there, that the app must show demo data only, and which demo account it will sign in with. The credentials stay in environment variables on your machine; the platform receives the images with the address captured and the window size, so keep tokens and emails out of the URLs you capture. Captures sit in a private storage bucket in Ireland, and project members read them through signed links valid one hour.

If something slipped through, ask your agent to capture the state again. An image you already imported into the prototype stays there until you ask your agent to delete that prototype frame. Security and data and the FAQ on demo data give the details.

Demo data is a small investment: one seed script, one account per role, a frozen clock. It lets you share screenshots freely, with people and with agents, without a privacy review for every image.

Frequently asked questions

Can I blur real customer data instead of using demo data?

Blurring is fragile: it is easy to miss a field, a toast or a line of small text, and a light blur can leave text readable. Invented data in a separate demo environment removes the risk at the source.

Which email domains and phone numbers are safe for fake data?

Use the domains reserved for examples, such as example.com or the .test top-level domain, set aside by RFC 2606. In North America, numbers from 555-0100 to 555-0199 are reserved for fictional use.

Is a staging database safe for screenshots?

Only if it was seeded with invented data. A staging database restored from a production copy holds real customers, even when it runs on a test server.

Try it on your own app

Tell Claude Code one sentence. It creates the project and gives you a link to see your screens.

Tell Claude Code:

Connect this project to agentappbuilder.com and show me its screens.