Goal: stand up a data marketplace where you sell datasets as a catalogue, and every dataset has its own indexable landing page that a search engine can find. This is the step-by-step version — commands, config, and what success looks like — of turning files into a self-serve product.

Who this is for (and when not to bother)

This is for anyone with data worth paying for — market data, curated research sets, cleaned public records, domain-specific corpora — who wants buyers to discover and purchase access without a sales call. If you have one dataset and three known customers, skip all of this and email them a link. The setup below earns its keep when you have a catalogue and you want strangers to find individual datasets through search.

Prerequisites

Step 1 — Create a dataset as a Priceable entity

In the admin backoffice, go to the dataset plugin's admin view and create a dataset record. A dataset is a Priceable — the same pricing abstraction the shop and subscriptions use — so it gets a price, currency and tax class for free, and the unified pricing engine quotes it exactly the way checkout will charge it.

Fill in the fields that matter for both selling and ranking: a clear name, a genuinely descriptive summary (this becomes your SEO body — write it for a human searching, not for a crawler), the schema or column list, update cadence, licence terms, and the price. Save it as a draft first; you don't want a half-described dataset indexed.

Success looks like: the dataset appears in GET /api/v1/datasets (or the plugin's catalogue endpoint) with a resolved price from the pricing engine, not a raw number you typed in two places.

Step 2 — Wire the entitlement

Selling access is not selling a file — it's selling an entitlement. When a buyer checks out, the platform's entitlement machinery grants their account access to that dataset's API automatically, and revokes it if the purchase is a subscription that lapses. You don't write this loop; you configure it. Link the dataset's Priceable to the entitlement it should grant, so "paid" becomes "can call the delivery API" with no human in between.

Gotcha: test the negative path. Create a second test user who has not bought the dataset and confirm the delivery endpoint returns 403 for them. An entitlement you've only tested from the buyer's side is an entitlement you haven't tested.

Step 3 — Author a per-dataset SEO page

This is the step that turns a catalogue into a discoverable one. Each dataset entity gets its own Entity Page with its own page_seo — a distinct title, meta description, and crawlable body at its own URL. This is not one "datasets" page listing everything; it is one indexable page per dataset, which is what lets a specific dataset rank for a specific search.

Write the page SEO from the dataset's real attributes: what the data is, what columns it has, how fresh it is, what it's good for, and the price. The description you wrote in Step 1 does double duty here. Set the meta title to the thing people would actually search ("EU air-quality hourly readings 2019–2026, by station"), not a slogan.

Success looks like: visiting /datasets/<slug> in a browser shows the page; each dataset has a unique URL, title and description.

Step 4 — Make bots see the rendered page

Here's the technical crux. Your storefront is a Vue SPA, and a naive crawler fetching the URL gets an empty shell — the content is rendered by JavaScript the crawler may not run. The vbwd-seo-renderer sidecar solves this: it detects bot user-agents and serves them fully rendered HTML (headless Chromium), while humans get the normal SPA.

Point the renderer at your storefront and confirm the routing: a request from a real browser UA gets the SPA; a request from a bot UA gets pre-rendered HTML containing your dataset's title and description in the markup. Verify with curl:

curl -A "Mozilla/5.0 (compatible; Googlebot/2.1)" https://yoursite/datasets/<slug> | grep -i "<title>"

Success looks like: that curl returns your dataset's real title inside the HTML, not a generic app-shell title. If it returns the shell, the renderer isn't intercepting the bot UA — fix that before you do anything else, because it's the difference between "indexable" and "invisible."

Step 5 — Checkout and delivery

Connect the two ends. The buyer lands on the dataset's SEO page, clicks buy, and goes through the standard checkout — the same cart-backed flow the shop uses, quoting the same price the pricing engine resolved in Step 1. On successful payment, the entitlement from Step 2 fires, and the buyer can now call the delivery API for that dataset.

Design the delivery API yourself — the platform gates access, but the response shape, pagination, rate limits and format (CSV, JSON, streaming) are your product decisions. A reasonable v1: an authenticated endpoint that checks the entitlement and returns the data or a signed download URL.

Success looks like: a test purchase with a real (or sandbox) payment method flips the buyer's access on, and their authenticated call to the delivery endpoint returns the data while an unentitled user still gets 403.

Verification checklist

Limits & next steps

Be honest about what this does and doesn't give you.

A page is not a ranking. Per-dataset SEO makes each dataset crawlable and distinct; it does not make it rank. Ranking still depends on the description being useful, the dataset being something people search for, and the ordinary signals search weighs. A thin auto-generated blurb on a dataset nobody wants will sit unindexed in practice. The renderer removes the technical blocker; the content is still your job.

The gate answers "allowed in," not "should this request be served." Rate limiting, abuse handling, and the buyer who scrapes their whole allocation in an hour are your engineering, not the platform's.

Licensing is your exposure. The plugin gates access; it does not vet your right to sell the data. "Public source" is not "free to resell," and a dataset you sell is not public-domain by default. That's your legal responsibility.

Next: automate freshness. If your data updates on a schedule, wire the ingestion so the dataset (and its "last updated" SEO field) stays current without manual re-uploads — a stale "updated 2024" line on a live-data product costs you sales.

Takeaway

The reason data products stall is rarely the data — it's the plumbing between "I have a file" and "a stranger paid for access without my involvement." The chain here closes that gap end to end: a dataset is a Priceable, payment grants an entitlement, the entitlement gates a delivery API you design, and every dataset gets its own crawlable page that the SEO renderer makes visible to search. Because it's 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 catalogue and the customer relationship instead of renting a marketplace that owns both.

Building a data product? Start with the dataset plugin, see how entitlements and billing connect in the developer docs, and read the architecture for how the SEO renderer fits.