Sample dataset · CC0

A customer table you can safely publish.

Nine columns of SaaS customer record: keys, names, contact details, geography, signup date, plan and monthly revenue. Every address is on a domain that cannot receive mail, so this is a file you can paste into a public bug report without a second thought.

9 columns · 100 or 1,000 rows as a file · up to 1,000,000 rows generated here · CSV, JSON, JSONL, Excel, Parquet

Take a file

The 1,000-row file is the one that matters, because it is exactly the key space the orders and support-tickets datasets reference. Take it, take orders, and you have a join.

Bigger sizes, built here

Larger sizes keep going up from customer_id 1001 with no gaps, so a million-row file is a million distinct customers rather than the same thousand repeated.

The first eight rows

The first eight rows of the 1,000-row file. Note that plan and mrr never disagree.

customer_idfirst_namelast_nameemailcountrycitysignup_dateplanmrr
1001DanielEvansdaniel.evans1001@example.comCanadaToronto2024-07-01Business299.00
1002AishaYoungaisha.young1002@example.comMexicoMexico City2024-07-02Pro99.00
1003OlgaReedolga.reed1003@example.comFranceParis2024-07-02Business299.00
1004MichaelWalkermichael.walker1004@example.comBrazilSao Paulo2024-07-03Free0.00
1005SharonLopezsharon.lopez1005@example.comUnited StatesSeattle2024-07-04Starter29.00
1006AishaMorganaisha.morgan1006@example.comUnited Arab EmiratesDubai2024-07-05Pro99.00
1007SharonMorrissharon.morris1007@example.comUnited StatesSeattle2024-07-05Pro99.00
1008SusanPatelsusan.patel1008@example.comUnited Arab EmiratesDubai2024-07-06Pro99.00

Nine columns, and what each one holds

Column Type What it holds Example
customer_id integer Primary key, 1001 upward, no gaps. 1001
first_name text Given name drawn from a fixed pool. Daniel
last_name text Family name drawn from a fixed pool. Evans
email text Unique address on example.com, the domain RFC 2606 reserves so test mail can never be delivered. daniel.evans1001@example.com
country text Country of the billing city. Canada
city text City, always one that really sits in that country. Toronto
signup_date date Date the account was created, ascending through the file. 2024-07-01
plan text Free, Starter, Pro, Business or Enterprise. Business
mrr decimal Monthly recurring revenue in USD. Always the price of the plan on the same row. 299.00

What it models

A subscription business's customer table, at the level of detail that ends up in a CSV export rather than in the production database. Identity, geography, when they arrived, what they pay for and what that is worth per month. It is deliberately the parent side of a relationship: no orders, no tickets, no usage, just the entity everything else points at.

Plans follow a bell rather than a flat draw, so Pro is the fat middle and Enterprise is the thin tail, which is roughly how a real book of business looks. Monthly revenue is not drawn independently of the plan: Free is 0, Starter is 29, Pro is 99, Business is 299, and Enterprise varies between 1,200 and 9,600 because enterprise pricing always does. Group by plan and average mrr and you get the price list back.

Cities and countries agree with each other. Bengaluru is in India and Munich is in Germany, which sounds like a low bar until you generate customer data with a library that draws city and country independently and ends up with Springfield, Japan.

The email addresses, specifically

Every address has the form first.last1234@example.com. The local part carries the customer id, so addresses are unique across a million rows and you can eyeball which row an address belongs to. The domain is example.com, which RFC 2606 reserves permanently for documentation and testing; mail sent there goes nowhere by design.

That matters more than it sounds. Test datasets built with real-looking domains have a long history of ending up in production mail queues during a load test, and the owner of the domain gets the bounces. Using the reserved domain removes the possibility rather than reducing the risk.

Using it as the parent in a join

customer_id starts at 1001 and increments with no gaps, so the 1,000-row file holds ids 1001 through 2000. Both the orders dataset and the support-tickets dataset draw their customer_id from exactly that range, which means every foreign key resolves against the 1,000-row customers file with nothing left over on either side.

The obvious exercise: join orders to customers on customer_id, group by plan, sum total. You get revenue by plan tier, and because mrr is on the customer row you can put subscription revenue and transactional revenue side by side, which is the shape of a question real analysts get asked and most sample data cannot answer.

What people use it for

  • Join practice, as the parent table for orders and support tickets.
  • CRM and onboarding demos that need contact records you can show on a screen share.
  • Testing email validation and parsing, on addresses that are well formed and undeliverable.
  • Cohort analysis by signup_date, which ascends evenly across two years.
  • Checking that a tool keeps customer_id an integer and mrr a decimal after a round trip.

It is the parent table

customer_id runs 1001 upward, so the first 1,000 rows are the customers the orders and support-tickets datasets reference.

Two datasets point at this one. Take the 1,000-row customers file together with orders and you can compute revenue by plan tier; take it with support tickets and you can ask whether your most expensive customers are also your loudest. Neither question is answerable from a single file, which is exactly why most sample data cannot support a realistic demo.

License, and the people in it

This dataset is dedicated to the public domain under CC0 1.0. Put it in a course, a paid product, a test suite, a bug report, a screenshot, a conference talk or a book. There is nothing to ask for, nothing to sign and no attribution required. A link back is welcome and is not a condition.

Nothing in this file describes a real person. The names are drawn from a fixed pool, the addresses are cities rather than street addresses, and every email address ends in example.com, the domain RFC 2606 reserves so that test mail can never be delivered to anybody. There is no personal information here to anonymize and none to leak.

Questions people ask about this file

Are these real people?

No. Names are assembled from a fixed pool of given names and family names, cities are real cities but there are no street addresses, and every email address is on example.com, the domain RFC 2606 reserves so that test mail cannot be delivered. There is no personal data here to protect, which is why the file can be attached to a public issue or printed in a book.

Does mrr match the plan?

Always. Free is 0, Starter is 29, Pro is 99, Business is 299, and Enterprise is a multiple of 300 between 1,200 and 9,600. Group by plan and take the average of mrr and you will read back the price list, which makes this file usable for teaching a GROUP BY where the answer is knowable in advance.

Do the customer ids line up with the orders dataset?

Yes. customer_id runs from 1001 with no gaps, and the orders and support-tickets datasets both draw their customer_id from 1001 to 2000. So the 1,000-row customers file covers every foreign key in those files exactly, with no orphans in either direction. That is the whole reason the key space was fixed rather than randomized.

Is it safe to use in a demo I record and publish?

Yes, and that is what it is for. Everything on screen is synthetic, the license is CC0, and the email domain cannot receive mail. Screen recordings of real customer tables are one of the more common ways a company leaks a customer list, so having a plausible-looking substitute on hand is worth more than it looks.