Sample dataset · CC0
A funnel that only points one way.
Two years of daily campaign performance across six channels. Every channel has its own click-through rate, conversion rate, cost per thousand and order value, so the ranking you get out of the data is a ranking somebody could defend in a meeting.
8 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 covers twelve campaigns across two years, which is enough for a monthly trend per channel without the chart turning into spaghetti.
| Format | Small | Standard |
|---|---|---|
| CSV | 100 rows (6.6 KB) | 1,000 rows (65.6 KB) |
| JSON | 100 rows (15.7 KB) | 1,000 rows (157.1 KB) |
| JSONL | 100 rows (15.4 KB) | 1,000 rows (154.1 KB) |
| Excel | 100 rows (20.1 KB) | 1,000 rows (125.5 KB) |
| Parquet | 100 rows (4.6 KB) | 1,000 rows (28.3 KB) |
More volume, same window
Larger sizes raise the number of rows per day rather than extending the window, so the channel mix and the funnel ratios stay put while the totals grow.
The first eight rows
The first eight rows of the 1,000-row file. Check any row: clicks are below impressions and conversions are below clicks.
| date | campaign | channel | impressions | clicks | spend | conversions | revenue |
|---|---|---|---|---|---|---|---|
| 2025-01-01 | webinar-q3 | Paid Search | 404717 | 16902 | 6063.52 | 1340 | 195355.15 |
| 2025-01-02 | partner-comarketing | Affiliate | 54239 | 1634 | 344.07 | 100 | 8152.24 |
| 2025-01-02 | back-to-work | Paid Search | 344142 | 17574 | 4332.83 | 1376 | 206780.02 |
| 2025-01-03 | black-friday | Display | 92848 | 355 | 439.15 | 4 | 350.47 |
| 2025-01-04 | free-trial-push | 107700 | 12776 | 140.91 | 648 | 99417.63 | |
| 2025-01-05 | black-friday | Display | 69751 | 294 | 259.40 | 1 | 108.04 |
| 2025-01-05 | black-friday | Paid Search | 95275 | 4227 | 1620.08 | 208 | 27579.38 |
| 2025-01-06 | webinar-q3 | Paid Search | 334098 | 12922 | 5612.00 | 948 | 95771.23 |
Eight columns, and what each one holds
| Column | Type | What it holds | Example |
|---|---|---|---|
| date | date | Reporting date, ascending through the file. | 2025-01-01 |
| campaign | text | Campaign name, twelve of them running across the window. | webinar-q3 |
| channel | text | Paid Search, Paid Social, Display, Email, Affiliate or Video. | Paid Search |
| impressions | integer | Times the ad was served. | 404717 |
| clicks | integer | Clicks. Always at or below impressions; the click-through rate is set by channel. | 16902 |
| spend | decimal | Cost in USD, derived from impressions and the channel's CPM. | 6063.52 |
| conversions | integer | Conversions. Always at or below clicks. | 1340 |
| revenue | decimal | Attributed revenue in USD, conversions times an order value that varies by channel. | 195355.15 |
What it models
Daily performance rows out of an ad platform export: one row per campaign per day, with the four counts and two money columns every marketing dashboard is built from. It is deliberately the flat, already-joined shape those exports arrive in, rather than a normalized set of tables, because that is the file people are handed.
Twelve campaigns run across the two-year window, and each row picks its channel independently of its campaign name. That is a simplification, and it means you should treat campaign as a label rather than as a stable entity with its own channel. If you need a strict hierarchy, group by channel.
The rates are per channel, and they are plausible
Paid Search runs a 4.1 percent click-through rate at a 14 dollar CPM and converts at 5.2 percent. Display runs 0.35 percent at a 4 dollar CPM and converts at 0.8 percent. Email is the outlier on every axis: a 9.2 percent click rate, a CPM near zero because you already own the list, and the highest order value in the file.
Those numbers are set as channel constants and then jittered per row, so the ranking is stable but no two days are the same. The consequence is that a return-on-ad-spend chart built from this file puts Email first and Display last, which is the answer a real analyst would expect, and which means the file can be used to check whether a dashboard is computing ROAS correctly rather than just computing something.
The funnel constraint
clicks is capped at impressions and conversions is capped at clicks, on every row, at every size. It sounds like a triviality and it is the single most common defect in generated marketing data: draw three counts independently and you get rows with more conversions than clicks, which makes every rate above 100 percent and every chart nonsense.
A test in the repository walks 600 rows and asserts both inequalities. That gives you a file where a computed click-through rate is always between 0 and 1, so if your tool produces a rate above 100 percent the tool is wrong, not the data. Having a known-good input is most of what makes debugging a dashboard tractable.
What people use it for
- ROAS and CPA dashboards where the channel ranking is knowable in advance.
- Funnel charts, on data where the funnel cannot invert.
- Testing derived-metric arithmetic: CTR, CVR, CPC and CPM all have a right answer here.
- Time series with six series on one axis, which is a real legibility test for a chart tool.
- Teaching weighted averages, because a mean of per-row click rates is not the overall click rate.
Open it somewhere useful
This is the dataset to point at a chart builder, because almost every column is a measure and there are only two dimensions to argue about.
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.
There are no people in this file at all. Campaign names are invented internal slugs, and the numbers are generated from channel-level rates rather than derived from anybody's real ad account.
Questions people ask about this file
Can conversions ever exceed clicks?
Never. clicks is clamped to impressions and conversions is clamped to clicks before the row is written, and a test asserts both across hundreds of rows. This is the defect that makes most generated marketing data unusable, because a single inverted row turns a conversion rate into a number above 100 percent and quietly breaks every average built on top of it.
Which channel wins on return on ad spend?
Email, by a distance, because it has the highest click rate, the highest conversion rate, the highest order value and almost no media cost. Display comes last. That ordering is baked into the channel constants deliberately, so the file has a right answer you can check a dashboard against rather than a random ranking that tells you nothing.
Is spend consistent with impressions?
Yes. Spend is impressions divided by a thousand, times the channel's CPM, times a jitter between 0.8 and 1.3. So the effective CPM you compute back out of the file sits in a believable band around the channel's rate rather than being an unrelated number, and cost per click behaves sensibly as a consequence.
Why does averaging the per-row click rate give the wrong overall rate?
Because the rows have wildly different impression counts, and an unweighted mean of ratios ignores that. The overall click-through rate is total clicks divided by total impressions, not the average of each row's rate. This file has a wide enough spread of impression volumes that the two numbers differ visibly, which makes it a good, concrete way to teach the difference.
More sample data
All twenty datasets · Messy files and every other format · Build your own schema