Most data products die in a Notion doc. You have a good CSV, a clear buyer, and a way to charge for it, but no way for a stranger to find the thing, understand it, and pay for it without you sitting in the loop. The gap is not the data. The gap is the shopfront: a page per dataset that a search engine can index, a checkout that grants access, and an API that enforces what was bought. This is the part that usually gets bolted together from three SaaS tools and a spreadsheet.

VBWD handles that shopfront as a plugin on a self-hosted, source-available platform (Python/Flask, Postgres, Vue 3, Docker). The interesting piece for anyone selling data is how three concerns line up: a dataset is a thing you can price, buying it grants an entitlement, and the entitlement is what your API checks. Around that runs a per-dataset landing page that can actually rank. Here is how it fits together and where it will bite you.

What the dataset plugin does

The dataset plugin treats a dataset as a first-class sellable object rather than a file behind a login. Concretely it does three jobs. It registers each dataset as a Priceable so the catalogue and checkout treat it like any other product. It issues an entitlement when someone completes a purchase. And it exposes the data over an API that only serves callers whose entitlement is valid.

The word doing the work here is seam. The plugin does not reach into checkout internals to know when a sale happened. Instead there is an invoice-line link registry: a small contract that says "when an invoice line of this type is paid, run this handler." The dataset plugin registers a handler that turns a paid line into an entitlement. That indirection is why the platform core stays agnostic about datasets, and why the same mechanism can grant a subscription, a booking, or a data license without the core knowing what any of those are.

The Priceable to entitlement to API flow

Walk the path a single purchase takes:

Priceable. A dataset carries a price through the platform's unified price model, so tax, currency, and discounts are computed the same way they are for every other product. You are not writing bespoke pricing math for data. The catalogue lists datasets through the shared filter and pagination contract, so a "datasets" listing behaves like any other product grid, with the same facets and paging behaviour. Pricing options and rules live on the features side of the platform, not in the plugin.

Checkout. Payment runs through swappable payment plugins. The dataset plugin does not care whether the buyer paid by card, by invoice, or by crypto; it only cares that a line was paid. That is what the link registry is for. Swapping the payment provider does not touch the dataset code. If you want to see how the money side is wired, the billing model is documented separately from the products that sit on top of it.

Entitlement. When the paid line fires the registered handler, the plugin creates an entitlement that records who bought what, and under what terms. This is the durable record. It survives page reloads, token refreshes, and support tickets, because it is a row in Postgres, not a flag in someone's browser.

API access. The entitlement is the gate on the data endpoints. A request for the dataset checks for a live entitlement before it returns a row. You design that API surface: what the endpoints look like, what fields you expose, how you paginate, and what rate limits apply. The plugin gives you the gate; it does not decide your rate limits or your response shape for you. That is deliberate, and it is also where most of your real design work lives.

Why each dataset gets its own crawlable page

Here is the part that turns a data catalogue into a business rather than an internal tool. A plugin can attach SEO metadata to an individual entity. In practice that means each dataset gets its own page_seo record: a title, a description, and a social share image, served at that dataset's own URL.

Why does this matter enough to call it out? Because the buyers for a niche dataset are searching for the niche, not for your marketplace. Someone looking for "German postal code population density 2025" will type that into a search engine, not browse your homepage. If every dataset lives behind a single JavaScript route that renders "Marketplace" in the page title, none of those searches ever land on you. Give each dataset a distinct, descriptive, indexable page and each one becomes a separate front door.

There is a technical catch with single-page apps: the Vue frontend renders in the browser, so a naive crawler sees an empty shell. VBWD runs an SEO renderer sidecar that produces a real rendered version of the page for bots, so the per-dataset title, description, and content are present in the HTML a crawler receives. The metadata you attached to the entity is what that renderer emits. The result is that each dataset can be indexed and can rank on its own merits, instead of being invisible behind client-side routing. The renderer behaviour is covered in the docs.

Business translation: your marketing surface grows with your catalogue. Ten datasets is ten landing pages. Two hundred datasets is two hundred. You are not writing a landing page by hand for each one; the page is generated from the entity plus its SEO metadata.

Generating the data with datavibes

A marketplace is only as good as the data flowing into it, and hand-exporting CSVs does not scale past your first few products. Datavibes is a companion, config-driven toolkit that produces versioned CSV snapshots of a dataset on a schedule. You describe the source and the shape once in config; datavibes runs on cron or a GitHub Action and emits a new versioned snapshot each cycle.

The division of labour is clean. Datavibes produces the snapshots. The dataset plugin sells them and gates access to them. Because snapshots are versioned, a dataset is not a single frozen file; it is a series, and buyers can be given access to the current version, a specific version, or an ongoing feed, depending on how you design the API and the entitlement terms. The scheduling means "monthly refreshed" data is a config line and a cron entry, not a recurring manual chore.

A worked example

Say you compile a dataset of electric-vehicle charging stations across a region: location, connector types, operator, and last-verified date. You want to sell it as a monthly-refreshed product at a fixed price.

You configure datavibes to pull from your sources, normalise the columns, and emit a versioned CSV on the first of each month via a GitHub Action. You register the dataset as a Priceable in the plugin, set its price through the unified price model, and write its SEO metadata: title "EV Charging Stations, [Region], Monthly", a description naming the columns and the refresh cadence, and a social image. That page goes live at its own URL and the SEO renderer makes it crawlable.

A buyer finds the page from a search for regional charging data, reads the description, and checks out through whichever payment plugin you have enabled. The paid invoice line fires the handler; the handler writes an entitlement. The buyer then calls your dataset API with their credentials, the endpoint confirms the live entitlement, and returns the current snapshot, respecting the rate limit you set. Next month datavibes emits a new version, and your entitlement design decides whether existing buyers get it automatically or need to renew.

Nothing in that loop required you to touch the platform core. You wrote config, a price, some SEO text, and your own API shape.

Honest limits

Some things this design does not do for you, and pretending otherwise will cost you later.

You host the data, so you own its licensing and quality. The plugin gates access; it does not vet your right to sell what you are selling. "Public source" is not the same as "free to resell." Scraping a public website or aggregating an open portal does not automatically grant you redistribution rights, and terms vary by source. This is your legal exposure, not the platform's. And to be explicit: a dataset you sell is not CC0 by default, and you should not label it so unless you genuinely mean to place it in the public domain.

The entitlement gates access, but you design the API. Rate limits, abuse prevention, response shape, and how you handle a buyer who scrapes their entire allocation in an hour are all your work. The gate answers "is this person allowed in"; it does not answer "should this specific request be served right now." Budget engineering time for the API surface itself.

A page is not a ranking. Per-entity SEO gives every dataset a crawlable, distinct page. It does not make that page rank. Ranking depends on the description being genuinely useful, the dataset being something people search for, and the usual signals search engines weigh. A thin, auto-generated description on a dataset nobody wants will sit unindexed in practice. The infrastructure removes the technical blocker; the content is still on you.

Takeaway

The reason data products stall is rarely the data. It is the plumbing between "I have a file" and "a stranger paid me for access without my involvement." VBWD's dataset plugin closes that gap with a clean chain: Priceable to entitlement to gated API, joined by an invoice-line link registry so the core never learns what a dataset is. Per-entity SEO gives each dataset its own front door, and datavibes keeps the data fresh on a schedule. Because it is self-hosted and source-available under BSL 1.1 (free for commercial use while annual VBWD-attributable sales stay under the value of 6.7 BTC per year), you own the stack and the data instead of renting a marketplace that owns your customers.

What you still own is the hard part: the rights to the data, the quality of it, the API design, and content good enough to rank. The platform removes the undifferentiated plumbing so your effort goes to the parts that actually make the product worth buying.

Building a data product? Start with the dataset plugin and read how entitlements and billing connect in the docs.